الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

خوارزميات البحث و الترتيب (الجزء الثالث)

بدأه Snack3r في 16 يوليو 2012 · 4 رد · 11,653 مشاهدة · في قسم المواضيع الهامة في قسم السي /سي++
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع
post-219439-035035000 1342391261_thumb.g

في هذه السلسلة, سأضع بين أيديكم شرحا لأهم الخوارزميات الـمُستعملة في البحث و الترتيب و كلي أمل بأن يستفيد الجميع.

post-219439-020499800 1342391170_thumb.j

بداية, أعتذر عن تأخري في كتابة الجزء الثالث من هذه السلسلة لظروف خارجة عن إرادتي !

.. نبدأ على بركة الله :)

post-219439-063075700 1342392103_thumb.g

خوارزمية البحث الثنائي (Binary search algorithm)

في هذا الدرس سنتطرق إلى النقاط التالية :

  1. الخوارزمية (الهدف, الفكرة, النتيجة, الإيجابيات و السلبيات)
  2. الخوارزمية بلغة السي++
  3. أمثلة على الخوارزمية
  4. التعقيد الزمني.
  5. ملأ مصفوفة عشوائيا و اختبار سرعة الخوارزمية.
  6. اختبر قدراتك !

post-219439-063075700 1342392103_thumb.g

1. الخوارزمية (الهدف, الفكرة, النتيجة, الإيجابيات و السلبيات)

الهدف : البحث عن قيمة المفتاح key داخل المصفوفة X.

الفكرة : تعتمد هذه الخوارزمية على البحث الثنائي (Binary search) في المصفوفة X حيث يبدأ البحث من العنصر الذي يقع في وسط المصفوفة, و في كل مرة نقارنه مع المفتاح Key, إذا كانت القيمتان متساويتان, فهذا يدل على أنه تم إيجاد قيمة المفتاح في المصفوفة, أما إذا كانت القيمتان مختلفتان ستقوم الخوارزمية بإجراء فحص جديد, إذا كانت قيمة المفتاح أصغر من قيمة العنصر الأوسط سيتم البحث في الجزء الأيسر من المصفوفة و في الحالة المعاكسة سيتم البحث في الجزء الأيمن من المصفوفة, و هكذا .. حتى نحصل على مصفوفة تتكون من خانة واحدة قيمتها مساوية للمفتاح أو مختلفة عنه.

النتيجة : إذا كانت X تحتوي على Key فسنحصل على رقم الخانة التي يوجد بها الأخير و إلا فالقيمة المـُعادة ستكون -1.

الإيجابيات: الـ Binary search تُنصف (تقلص للنصف) عدد عناصر المصفوفة في كل تكرار, لذا تستغرق عملية البحث وقت قليل جدا.

تنتمي هذه الخوارزمية إلى عائلة فرق تسد.

السلبيات : خوارزمية البحث الثنائي أكثر تعقيدا من خوارزمية البحث الخطي التقليدية, كما أن الأولى تشترط الترتيب عند البحث.

post-219439-063075700 1342392103_thumb.g

2. الخوارزمية بلغة السي++

يمكننا كتابة الخوارزمية باستخدام الـ While loop أو الـ Recursive Function.

2.1 - الطريقة الأولى:

post-219439-025985500 1342392886_thumb.p

الدالة binarySearch تستقبل 3 وسائط, المصفوفة المـُراد البحث داخلها و عدد عناصرها و قيمة المفتاح.

يبدأ ترقيم عناصر المصفوفة بالقيمة low و ينتهي عند high, ويمثل المتغير mid رقم الخانة الوسطى من المصفوفة.

في كل مرة نقارن قيمة المفتاح بقيمة أوسط عناصر المصفوفة, إذا كانتا متساويتين نُعيد رقم الخانة و إذا كانتا مختلفتين نتقدم خطوة إلى الأمام أو نرجع خطوة إلى الوراء حسب وضعية المفتاح.

نكرر الخطوات السابقة ما دام low أقل أو يساوي high (بمعنى آخر, المصفوفة تحتوي على خانة أو أكثر).

إذا تم الخروج من الحلقة while دون إعادة قيمة فهذا يعني أن المفتاح غير موجود, في هذه الحالة ستعيد الدالة -1.

في الدالة الرئيسية قمنا بالإعلان عن مصفوفة تحوي ألف عنصر ثم ملأناها بالقيم الواقعة في المجال [500,500-] لاحظ أن عناصر المصفوفة يجب أن تكون مرتبة. بعد ذلك قمنا بالبحث عن القيمة -73 داخل المصفوفة و قد تم إيجادها في الخانة رقم 427 وهذا شيء طبيعي لأن الصفر يتواجد في الخانة رقم 500 و بالتالي القيمة -73 ستتواجد في الخانة رقم 73-500.

يمكننا استدعاء الدالة binarySearch على جزء من المصفوفة, في هذه الحالة نضع low و high كوسائط للدالة و ليس كمتغيرات محلية.

2.2 - الطريقة الثانية:

post-219439-059046900 1342392916_thumb.p

تستقبل الدالة binarySearch أربع وسائط, هم على التوالي : اسم المصفوفة و المفتاح و من أين يبدأ البحث ؟ و أين ينتهي ؟

المتغير mid يحتوي على رقم الخانة الوسطى من المصفوفة. إذا كانت قيمة المفتاح أكبر (أصغر) من mid سيتم تطبيق الدالة على الجانب الأيسر (الأيمن) من المصفوفة.

إذا كانت قيمة high أقل تماما من low فهذا يعني أن المصفوفة أصبحت فارغة.

post-219439-063075700 1342392103_thumb.g

3. أمثلة على الخوارزمية

نبدأ مع مثال بسيط يُوضح فكرة البحث الثنائي.

3.1 – المثال الأول

أحمد: ما رأيك بلعبة الكاهن ؟

عمرو: الكاهن ؟؟

أحمد: نعم, أختارُ عددا عشوائيا يقع في المجال [0,100] و عليك معرفة العدد !

عمرو: هذا مستحيل !!

أحمد: لا تستعجل .. في كل مرة تختار فيها عددا, سأخبرك ما إذا كان أكبر أو أصغر من العدد الذي تبحث عنه.

عمرو: لا بأس, سأحاول .. سأبدأ بالعدد الذي يقع في منتصف المجال, هل عددك أكبر من 50 ؟

أحمد: نعم !

عمرو : سأختار الآن أوسط أعداد المجال الجديد, هل العدد أكبر من 75 ؟

أحمد: لا !

عمرو: إذا العدد يقع بين 51 و 75, هل هو أكبر من 63 ؟

أحمد: نعم !

عمرو: جيد, أصبح المجال ضيقا الآن, هل العدد أصغر من 69 ؟

أحمد : نعم !

عمرو: أكبر من 66 ؟

أحمد: لا !

عمرو: أصغر من 65 ؟

أحمد: لا !

عمرو: إذا فالعدد المُختار هو 66 ؟

أحمد: نعم, أحسنت !

ملاحظة:

  • لو وضع عمرو في الحسبان أن العدد الذي يبحث عنه يمكن أن يتواجد في منتصف المجال, لاستغنى عن آخر سؤالين !
  • للفائدة, سبق و أن كتبتُ برنامجا صغيرا يُحاكي لعبة الكاهن, يمكنك تجربته من هنا.

3.2 – المثال الثاني

نريد البحث عن العدد 8 في مصفوفة مُكونة من 10 خانات, قيمها كالآتي:

post-219439-098578900 1342392949_thumb.p

الخانات الملونة باللون الأخضر تُمثل الجزء الذي سيتم البحث فيه من المصفوفة و الخانة ذات اللون الأزرق تمثل أوسط العناصر.

3.3 – المثال الثالث

ابحث عن القيمة 33 في المصفوفة التالية :

post-219439-086584000 1342614387_thumb.p

الحل:

1. نحدد منتصف المصفوفة:

post-219439-098469100 1342614480_thumb.p

2. تقسيم المصفوفة إلى قسمين وفقا لموقع mid:

post-219439-091086300 1342614406_thumb.p

3. بما أن 33 أصغر من 53, فعملية البحث ستنفذ على النصف الأول:

post-219439-062874200 1342614419_thumb.p

4. نعيد عملة التقسيم على النصف الأول و تصبح قيمة mid تساوي:

post-219439-092249400 1342614494_thumb.p

post-219439-081890400 1342614430_thumb.p

5. بما أن 33 أكبر من 25, سيتم استبعاد النصف الأول و تستمر عملية البحث في النصف الثاني:

post-219439-098299200 1342614442_thumb.p

6. من جديد, نعيد عملية التقسيم حيث تصبح قيمة mid تساوي 5:

post-219439-032829400 1342614464_thumb.p

7. و أخيرا نجد أن القيمة 33 موجودة في الموقع low و الذي يساوي 4.

post-219439-063075700 1342392103_thumb.g

4. التعقيد الزمني

خوارزمية البحث الثنائي سريعة جدا و فعالة أيضا, خصوصا عند التعامل مع المصفوفات الكبيرة, لأنها تُلغي في كل مرة نصف المصفوفة و تبحث في النصف الآخر (طبعا, دون أن ننسى أن المصفوفة يجب أن تكون مُرتبة و هذه ضريبة السرعة ^_^ )

لو أخذنا على سبيل المثال مصفوفة تتكون من 1024 خانة, في أسوأ الحالات ستقوم الخوارزمية بـــ 10 مقارنات لمعرفة ما إذا كان المفتاح موجود أم لا ! (لاحظ أن post-219439-095589700 1342394255_thumb.p). و لو زدنا عدد خانات المصفوفة ليصبح 1048576 , ستقوم الخوارزمية بـــ 20 مقارنة في أسوأ الحالات !

في أفضل الحالات, يكون التعقيد الزمني T(n) = 1 و في أسوأ الحالات يكون المفتاح في بداية أو نهاية المصفوفة أو غير موجود

في كل مرة يتم إلغاء نصف المصفوفة و العمل على النصف الآخر, لذا سيكون طول المصفوفة يساوي post-219439-095976900 1342393502_thumb.p في الخطوة رقم k.

نتوقف عندما تصبح المصفوفة عبارة عن خانة واحدة:

post-219439-091073300 1342393010_thumb.p

إذا, في هذه الحالة سيكون التعقيد يساوي post-219439-078478700 1342393059_thumb.p

الحالة المتوسطة: عندما تكون هناك احتمالية وجود المفتاح في أي جزء من المصفوفة, و عليه سيكون التعقيد:

post-219439-083596200 1342615421_thumb.p

post-219439-063075700 1342392103_thumb.g

5. ملأ مصفوفة عشوائيا و اختبار السرعة

في هذه الفقرة, سنملأ عشوائيا مصفوفة تحتوي على 1000 خانة ثم نرتب المصفوفة لنبحث في داخلها عن قيمة معينة, سنحتاج إلى الدوال التالية لتنفيذ ما سبق:

post-219439-028143000 1342393089_thumb.p

لا شيء جديد, فقط قمتُ بتجميع الدوال التي تعرفنا عليها سابقا !

محتوى الدالة الرئيسية سيكون هكذا:

post-219439-095930600 1342393117_thumb.p

قمنا بملأ المصفوفة عشوائيا ثم رتبنا القيم تصاعديا, بعد ذلك قمنا بتخزين قيمة إحدى خانات المصفوفة في المتغير Random بشكل عشوائي ثم بحثنا عن مكان تلك القيمة داخل المصفوفة X.

لاحظ سرعة الخوارزمية مُقارنة مع خوارزمية البحث الخطي التي تعرفنا عليها في الدرس الأول.

post-219439-063075700 1342392103_thumb.g

6. اختبر قدراتك !

سأخصص لهذه الفقرة موضوع مستقل يحتوي على تمرين يكون بمثابة مراجعة للحلقات الثلاثة السابقة.

:: تعديل ::

رابط الجزء الرابع.

إلى هنا أصل بكم إلى نهاية الدرس, أرجو أن تكونوا قد استفدتم. لا تنسوني من صالح الدعاء.

تحياتي.

post-219439-060296700 1342392322_thumb.g
المرفقات
Couverture.jpgالبسملة.gif-.1.gif-.4.gifbinarySearchWhile.pngbinarySearchFoncRecrs.pngbinarySearchExample.pngExpLog.pngO(n).pngbinarySearchFoncsComplete.pngbinarySearchMain.pngn_2_k.png1024.pngEtape1.pngEtape2.pngEtape3.pngEtape4.pngEtape5.pngEtape6.pngCalcMid.pngMid.pngcasMoyn.png

تم تعديل هذه المشاركة بواسطة أحمد الشنقيطي في 18 يوليو 2012 في 15:48 — السبب: إضافة رابط الجزء الرابع.

4
#2

رائعة من روائعك اخى احمد ;) :cool: انتظر مفاجأتى قريبا :)

.Everyone has a dream

.I never thought that I would be the one I am on now

...No Pain No Gain

مشرف قسم السى/سى++ و الاسيمبلى سنة 2015 بأذن الله ...

تعديل: مشرف قسم السى/سى++ من 2012.

#3

ردس ممتاز بكل المقاييس جزاك الله خيراً أخي أحمد ...

لدي ملاحظة بسيطة :

إن عملية البحث السريعة تعتمد على الترتيب ..كما ذكرت ..

ولكننا إذا أردنا ترتيب العناصر فهذا سيدفعنا بالضرورة إلى المرور على جميع العناصر ...

وبالتالي يمكننا اختبار العناصر أثناء ترتيبها ..وعندها لن يكون للبحث بعد ذلك أي داع ... وكذلك سيكون الترتيب دون فائدة ...

أي أن : عملية الترتيب + البحث الثنائي أقل جدوى من عملية البحث التسلسلي (لوحدها)

وبذلك تكون عملية البحث الثنائي مجدية فقط عندما يكون الهدف عناصر مرتبة من المصدر .. لدي إجابة لهذا الكلام ولكن أنتظر إجابتك..:wink:

إجابة السؤال هي أننا نحتاج غالبا للبحث آلاف المرات ربما.... بينما نقوم بالترتيب مرة واحدة فقط ... تحياتي ..: )

تقبل تحياتي

بارك الله بك ... :happy:

ننتظر مفاجأة الأخ Xmaster :)

والسلام عليكم ورحمة الله وبركاته ..

تم تعديل هذه المشاركة بواسطة مصطفى 36a2 في 16 يوليو 2012 في 08:52

#4

+1

مقالة أكثر من رائعة و أسلوب متميز في الشرح.

أعتقد أن هذه السلسلة ستكون مرجعا مهما لكل من يريد دراسة خوارزميات البحث و الترتيب :)

تحياتي.

#5

شكرا لــ ماستر, مصطفى و خالد :)

ردا على سؤال الأخ مصطفى :

اقتباس
يمكننا اختبار العناصر أثناء ترتيبها ..وعندها لن يكون للبحث بعد ذلك أي داع

في الشركات الكبرى و المصانع الضخمة, تكون البيانات مُرتبة (تصاعديا أو تنازليا) لتسهيل عمليات كثيرة من بينها عملية البحث. لذا لن تستغرق خوارزمية البحث الثنائي وقتا يُذكر ! :)

تحياتي.

تم تعديل هذه المشاركة بواسطة أحمد الشنقيطي في 16 يوليو 2012 في 14:27 — السبب: تصحيح خطأ إملائي !

مواضيع مشابهة