You are on page 1of 509

‫ت‬‫س‬

‫هياكل البيانات نا خدام ‪C++‬‬

‫ناليف‬
‫ل‬ ‫ا‬ ‫خ‬ ‫ن‬ ‫ــــ‬
‫الأسياذ الد ور ال ر اذي‬
‫ي‬ ‫ع‬ ‫ي‬‫ض‬ ‫ض‬ ‫ي‬ ‫ك‬

‫‪1‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫هياكل البيانات باستخدام ‪C++‬‬

‫‪3‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫العبادي‪ ،‬نضال‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫رقم اإليداع في دار الكتب والوثائق ‪ -‬بغداد‪)2018/609( :‬‬
‫رقم التصنيف‪0053.13 :‬‬
‫الواصفات‪ / : :‬لغات البرمجة ‪ / /‬الحاسبات الكترونية ‪ / /‬لغة‪C++‬‬
‫تم إعداد بيانات الفهرسة والتصنيف األولية من قبل دار الذاكرة للنشر والتوزيع‬

‫الطبعة األولى‬
‫‪2018‬‬
‫حقوق الطبع محفوظة للناشر‬

‫حقوق النشر اإللكتروني محفوظة للناشر‬


‫يمنع طباعة أو تصوير هذا المنشور بأية طريقة كانت إلكترونيةة أو‬
‫ميكانيكية أو مغناطيسية أو بالتصةوير أو بالة ذ كلةو ول الر ةو‬
‫الفاعةةة‬ ‫إلةةةل الناشةةةر وبةةةسكل وبةةةي مسةةةبر وبالةةة ذ كلةةةو يت ةةةر‬
‫للم حقة القانونية‬

‫بغداد ‪ -‬الصرافية – مجاور الجسر الحديدي‬


‫نقال‪07700488780 / 07800740728 :‬‬

‫بريد إلكتروني‪info@althakera.com / www.althakera.com :‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫الل روح والدي ‪...‬‬


‫الل روح والدتي ‪...‬‬
‫ما انا عليه هو بفضلكم‬
‫ب د هللا‬
‫أسأل هللا ال يغفر لكما‬

‫‪5‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫دول المحتويات‬

‫المقدمة ‪13 ........................................................................................‬‬

‫الفص االول ‪ ..‬هياك البيانات والالوارزميات ‪Data Structures and‬‬


‫‪19 ............................................................................... Algorithms‬‬

‫المقدمة‪19 ......................................................................................‬‬
‫المعلومات والبيانات ‪20 .....................................................................‬‬
‫هياكل البيانات‪20 .............................................................................‬‬
‫انواع هياكل البيانات ‪21 .....................................................................‬‬
‫صفات هياكل البيانات ‪23 ...................................................................‬‬
‫لماذا هياكل البيانات ‪24 ......................................................................‬‬
‫ماهي الخوارزمية ‪26 ........................................................................‬‬

‫الفص الثاني ‪ ..‬المصفوفات ‪33 ................................................... Arrays‬‬

‫المقدمة‪33 ......................................................................................‬‬
‫المصفوفات ‪33 ................................................................................‬‬
‫المصفوفات االحادية ‪34 .....................................................................‬‬
‫انشاء المصفوفة‪36 ...........................................................................‬‬
‫الوصول الى عناصر المصفوفة ‪40 .......................................................‬‬

‫‪7‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫المصفوفات متعددة االبعاد ‪42 ..............................................................‬‬


‫الفص الثالث ‪ ..‬الترتيب ‪53 .......................................................Sorting‬‬

‫المقدمة‪53 ......................................................................................‬‬
‫الترتيب المستقر وغير المستقر ‪54 ........................................................‬‬
‫خوارزميات الترتيب المالئمة وغير المالئمة‪55 ........................................‬‬
‫مصطلحات مهمة ‪55 .........................................................................‬‬
‫ترتيب الفقاعة ‪55 .............................................................................‬‬
‫ترتيب الحشر‪59 ..............................................................................‬‬
‫ترتيب االختيار‪63 ............................................................................‬‬
‫الترتيب بالدمج ‪67 ............................................................................‬‬
‫الترتيب بطريقة شل‪73 ......................................................................‬‬
‫الترتيب السريع ‪76 ...........................................................................‬‬
‫البحث‪89 .......................................................................................‬‬
‫جداول التجزئة ‪102 ..........................................................................‬‬

‫الفص الرابع ‪ ..‬المكدس ‪113 ...................................................... Stack‬‬

‫المقدمة‪113 ....................................................................................‬‬
‫تعريف المكدس ‪113 .........................................................................‬‬
‫العمليات التي تجرى على المكدس ‪115 ..................................................‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫تطبيقات المكدس‪117 ........................................................................‬‬


‫التعابير الجبرية ‪119 .........................................................................‬‬
‫تحويل تعبير العالمة القياسية الى تعبير العالمة الالحقة ‪120 .........................‬‬
‫حساب تعبير العالمة الالحقة ‪130 .........................................................‬‬
‫خوارزمية تحويل تعبير العالمة القياسية الى تعبير العالمة السابقة‪140 ............‬‬
‫بعض البرامج الالزمة لتطبيقات المكدس باستخدام لغة ‪149................... C++‬‬
‫اجوبة التمارين ‪163........................................................................‬‬

‫الفص الالامس ‪ ..‬البابور ‪167 .................................................. Queue‬‬

‫المقدمة‪167 ....................................................................................‬‬
‫ما هو الطابور‪168 ...........................................................................‬‬
‫بعض تطبيقات الطابور‪169 ................................................................‬‬
‫الطوابير الخطية ‪170 ........................................................................‬‬
‫تنفيذ قوائم االنتظار‪170 .....................................................................‬‬
‫خزن البيانات في هياكل بيانات مستقرة ‪172 ............................................‬‬
‫خزن الطابور في هياكل بيانات ديناميكية ‪173 ..........................................‬‬
‫خوارزمية اضافة عنصر الى طابور ‪174 ...............................................‬‬
‫حذف عنصر من الطابور ‪175 .............................................................‬‬
‫الطابور الدائري ‪177 ........................................................................‬‬

‫الفص السا س ‪ ..‬القوائم الموصولة ‪187 ........................... Linked Lists‬‬


‫‪9‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫المقدمة ‪187.................................................................................‬‬
‫ابتداء القوائم الموصولة ‪188..............................................................‬‬
‫ماهي القوائم الموصولة‪189 ................................................................‬‬
‫العقدة‪190 ......................................................................................‬‬
‫لماذا القوائم الموصولة‪192 .................................................................‬‬
‫المؤشرات‪192 ................................................................................‬‬
‫هيكلية القوائم الموصولة‪198 ...............................................................‬‬
‫المرور على عناصر القائمة الموصولة ‪200 ............................................‬‬
‫القوائم الموصولة االحادية ‪202 ............................................................‬‬
‫القوائم الموصولة الثنائية ‪238 ..............................................................‬‬
‫القوائم الموصولة الدائرية ‪268 .............................................................‬‬
‫القوائم الموصولة الدائرية الثنائية ‪294 ....................................................‬‬

‫الفص السابع ‪ ..‬االستدعاء الذاتي ‪325 ................................. Recursion‬‬

‫المقدمة ‪325.................................................................................‬‬
‫االعادة‪326 ....................................................................................‬‬
‫كيف يستخدم االستدعاء الذاتي ‪328 .......................................................‬‬
‫االستدعاء الذاتي باستخدام مثال‪329 ......................................................‬‬
‫كتابة دوال االستدعاء الذاتي ‪338 ..........................................................‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص الثامن ‪ ..‬االشجار الثنائية ‪343 ................................ Binary Trees‬‬

‫المقدمة‪343 ....................................................................................‬‬
‫تعريف االشجار الثنائية ‪344 ...............................................................‬‬
‫العقدة‪345 ......................................................................................‬‬
‫مصطلحات االشجار ‪346 ...................................................................‬‬
‫فوائد االشجار ‪346 ...........................................................................‬‬
‫الشجرة الثنائية ‪352 ..........................................................................‬‬
‫اشجار البحث الثنائي‪359 ...................................................................‬‬
‫العمليات التي تجرى على شجرة البحث الثنائي ‪362 ...................................‬‬
‫اشجار التعابير الرياضية‪386 ..............................................................‬‬
‫تمثيل االشجار‪397 ...........................................................................‬‬

‫الفص التاسع‪ ..‬تكديس هياك البيانات ‪407 ........... Heap Data Structure‬‬

‫المقدمة‪407 ....................................................................................‬‬
‫تعريف التكديس‪407 .........................................................................‬‬
‫خوارزمية انشاء التكديس ‪409 .............................................................‬‬
‫الحذف من شجرة التكديس ‪415 ............................................................‬‬
‫تمثيل التكديس ‪417 ...........................................................................‬‬

‫الفص ال اشر ‪ ..‬المالببات ‪423 ............................................... Graphs‬‬

‫‪11‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫المقدمة‪423 ....................................................................................‬‬
‫ما هو المخطط ‪424 ..........................................................................‬‬
‫تطبيقات نظرية المخططات‪424 ...........................................................‬‬
‫مصطلحات المخططات ‪425 ...............................................................‬‬
‫اولر وجسور كونزبيرج‪441 ...............................................................‬‬
‫انواع المخططات ‪443 .......................................................................‬‬
‫طرق المرور على المخطط ‪447 ..........................................................‬‬
‫العمليات االولية االساسية التي تجرى على المخططات ‪470 .........................‬‬
‫تمثيل المخطط‪472 ...........................................................................‬‬
‫خوارزمية ديكسترا‪481 .....................................................................‬‬

‫المصا ر ‪504 ....................................................................................‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫المقدمة‬
‫الحمد هلل حمدًا يلير بج ل و هه وعظيم سلبانه‪ ،‬وأشهد أل ال إله إال هللا وحةد ال‬
‫شريو له‪ ،‬وأشهد أل محمدًا عبد هللا ورسوله‪ ،‬صلوات هللا وس مه عليه وعلل آله‬
‫وأصحابه البيبين الباهرين‪ ،‬و َمن سار علل نهجه إلل يةو الةدين‪ .‬الحمةد هلل الةذي‬
‫لنا من ال لم نورا نهدي به‪.‬‬
‫عند الحديث عن اي فرع من فرروع الحاسربات الرقميرة فرال برد ان نسرتذكر ان الغايرة‬
‫من اختراع الحاسبات الرقمية الحديثة هو لغرض تسهيل وتسريع العمليات الحسابية‬
‫المعقدة والتي تستهلك وقت‪ .‬في غالبيرة التطبيقرات فران قردرة الحاسربات علرى الخرزن‬
‫والوصول الى كمية المعلومات الكبيرة‪ ،‬فضال عن سرعة اجراء العمليرات الحسرابية‬
‫تلعب دور رئيس وتعتبر الميزة االولى لها‪.‬‬
‫دائما ً ما نجد أن األشياء تمتاز بمجموعرة صرفات‪ ،‬وهرذل الصرفات تعتبرر الخصرائص‬
‫المميزة والمحددة لألشياء‪ ،‬وتنتظم هذل الصفات طبيعيا ً بشكل بنائي منظم‪.‬‬
‫نحن نرغب لتجميع العناصر ذات العالقرة معرا‪ ،‬ونرغرب ايضرا لتنظريم هرذل البيانرات‬
‫على شكل تكتالت بطريقة مناسبة للبرمجة وكفوءة في التنفيذ‪.‬‬
‫تاريخيررا فرران هياكررل البيانررات تعتبررر الدعامررة الرئيسررية ألقسررام علرروم الحاسرربات‪ .‬اننررا‬
‫ندرس هياكل البيانات لنتعلم كيفية كتابة برامج حاسوب أكثرر كفراءة‪ .‬علرى مردى ‪20‬‬
‫سنة االخيرة ازداد التركيز على هذا الموضوع وأصبح واسعا بشكل ملحوظ‪.‬‬
‫واذ نحن نضع بين ايديكم هذا الكتاب الذي نرجرو ان يكرون فري المسرتوى المطلروب‪،‬‬
‫ونأمل اننا على االقل لم نقصر ولم نهمل تبيان جواهر عناصر الكتاب‪.‬‬
‫لقد كانت رحلرة جاهردل لالرتقراء بردرجات العقرل ومعرراج االفكرار‪ ،‬فمرا هرذا اال جهرد‬
‫مقل وال ندعي فيه الكمال ولكن عذرنا انا بذلنا فيه قصارى جهدنا‪ ،‬فان أصربنا فرذا‬
‫مرادنا وان أخطأنا فلنا شرف المحاولة والتعلم‪.‬‬
‫اننررا نعتقررد ان هياكررل البيانررات مررن المواضرريع المعقرردة نسرربيا لررذلك تحترراج الررى جهررد‬
‫اضافي لتبسيطها وجعلها أسهل للفهم‪.‬‬

‫‪13‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الكتاب تم كتابته بطريقة مبسطة لمساعدة طلبة علوم الحاسبات في الدراسة االوليرة‪،‬‬
‫وكذلك من الممكن ان يكون مساعد لمحترفي البرمجيات ممن يرغب ان يفهم هياكل‬
‫البيانات بخطوات مبسطة‪ .‬تم مراعاة عدم االسرهاب غيرر المبررر ممرا يجعرل الكتراب‬
‫يمررنح القررار فهمررا واسررعا حررول مفرراهيم هياكررل البيانررات‪ .‬أتمنررى أن أكررون موفقررا فرري‬
‫سررردي لعناصررر الكترراب سررردا ال ملررل فيرره وال تقصررير موضررحا ابيررار ا يجابيررة‬
‫والسلبية لهذا الموضوع الشائك الممتع‪.‬‬
‫ان الراغبين برتعلم هياكرل البيانرات يجرب ان تكرون لهرم المعرفرة بلغرة البرمجرة ‪ C‬او‬
‫‪ C++‬والتي تستخدم كأساس برمجي لكل فقرات وفصول الكتاب‪.‬‬
‫ان المبرررر وراء كتابررة هررذا الكترراب هررو افتقررار المكتبررة العربيررة الررى كتررب عربيررة‬
‫احترافية في مجال علوم الحاسبات‪ .‬لذلك فران الهردف االولري لكتابرة هرذا الكتراب هرو‬
‫تغطية التفاصيل والمواضيع الخاصة بموضوع هياكل البيانات بطريقة تسراعد علرى‬
‫فهررم واسررتنباط المفرراهيم االساسررية لهياكررل البيانررات فضررال عررن انهررا تراعرري جميررع‬
‫المسررتويات‪ .‬كررذلك فرران الكترراب يرروفر امثلررة واشرركال توضرريحية تسرراعد علررى متابعررة‬
‫الموضوع خطوة خطوة‪ ..‬ناهيك عن تعزيزها بمجموعة من البرامج التي كتبت بلغة‬
‫البرمجة ‪.C++‬‬
‫يختلررف هررذا الكترراب عررن كتررب علرروم الحاسرربات بشرركل عررام والترري تكررون مملرروءة‬
‫بالنظريررات والعالقررات الرياضررية‪ ،‬وامثلررة ربمررا تكررون مررن الصررعب حلهررا‪ ،‬حيررث تررم‬
‫التركيز في هذا الكتاب على الشرح السلس للتقنيرات التري تطبرل علرى مشراكل العرالم‬
‫الحقيقي‪ .‬تجنبنا البراهين المعقدة والرياضيات الثقيلة‪ .‬واضريفت الكثيرر مرن االشركال‬
‫لتوضيح المواضيع المعقدة‪.‬‬
‫يتكون الكتاب من عدد من الفصول اشير لها هنا باختصار‪.‬‬
‫الفص ة االول‪ :‬تررم التركيررز فيرره علررى بعررض المصررطلحات العامررة وتعريررف هياكررل‬
‫البيانررات وعالقتهررا مررع الخوارزميررات‪ .‬وتررم توضرريح الخوارزميررات بشرركل مختصررر‬
‫لبيان اهميتها في البرمجة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفصة الثةةاني‪ :‬ركررز علررى المصررفوفات االحاديررة والثنائيررة علررى اعتبررار انهررا البدايررة‬
‫لمواضيع هياكل البيانات‪ ،‬الفصل يحتوي على عدد من االمثلة للتوضيح‪.‬‬
‫الفصة الثالةةث‪ :‬تررم التطرررق الررى خوارزميررات الترتيررب وقررد حاولنررا فرري هررذا الفصررل‬
‫تحليررل ودراسررة عرردد مررن خوارزميررات الترتيررب بشرركل مبسررط مررع امثلررة توضرريحية‬
‫ورسوم توضيحية لغرض المتابعة‪.‬‬
‫الفصة الرابةةع‪ :‬يتنراول المكرردس بالتفصريل والررذي هرو مررن مواضريع هياكررل البيانررات‬
‫كثيرة االستخدام‪ .‬تم توضريح اسرتخدام المكردس مرع التعرابير الجبريرة وعرزز الفصرل‬
‫بكثير من األمثلة التوضيحية‪.‬‬
‫الفص الالامس‪ :‬نستمر في الفصل الخامس مع الطابور (الخطي والدائري) وكل ما‬
‫يتعلل بهذا الموضروع مرن عمليرات اضرافة وحرذف‪ .‬ترم توضريح تطبيقرات ومميرزات‬
‫الطابور وعزز الفصل بعدد من االمثلة والبرامج‪.‬‬
‫الفصة السةةا س‪ :‬تناولنررا فيرره القرروائم الموصررولة وانواعهررا االربررع‪ ،‬ونظرررا الن هرذا‬
‫الموضوع فيه شيء من التعقيد لذلك حاولنرا االسرهاب بره قلريال‪ .‬خوارزميرات البحرث‬
‫والحشر والحذف كلها تم مناقشتها مع امثلة ورسوم توضيحية‪.‬‬
‫الفص السابع‪ :‬ناقش موضوع االستدعاء الذاتي نظررا السرتخداماته الواسرعة‪ ،‬حيرث‬
‫ركزنررا علررى اعطرراء القررار فرصررة لفهررم المفرراهيم االساسررية لالسررتدعاء الررذاتي وتررم‬
‫توضيح كيف من الممكن استخدامه فري حرل المشراكل البرمجيرة‪ .‬الخطروط العريضرة‬
‫لكتابة دوال استدعاء ذاتي تم توضيحها باستخدام االمثلة‪.‬‬
‫الفص الثامن‪ :‬تطرقنا فيه الى االشجار بشكل عرام واشرجار البحرث الثنرائي كطريقرة‬
‫لتنظيم البيانات‪ ،‬مع بيان عدد من العمليات االساسية التي تجرى على اشجار البحرث‬
‫الثنائي‪ .‬الفصل ايضا تضمن بعض طرق البحث عطاء القار الفرصة للمقارنة‪.‬‬
‫الفص التاسع‪ :‬تم التطرق الى موضوع التكديس والعمليات التي تجرى عليره نظررا‬
‫ألهمية الموضوع‪ ،‬تم توضيح العمليات باستخدام امثلة توضيحية معززة بالرسوم‪.‬‬

‫‪15‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص ال اشةر‪ :‬الفصرل العشرر هرو خترام الكتراب مرع موضروع المخططرات وكرل مرا‬
‫يتعلل بها‪ ،‬تم توضيح المفاهيم والمصطلحات االساسرية المسرتخدمة مرع المخططرات‬
‫وكذلك كيفية تنفيذها وعمليات البحث والحشر والحذف‪..‬‬
‫في ختام هذل المقدمة فاني ال ازيد على ما قاله عماد االصفهاني "رأيت انره ال يكترب‬
‫انسان كتابا فري يومره ال قرال فري غردل لرو غيرر هرذا لكران أحسرن ولرو زيرد كرذا لكران‬
‫يستحسن ولو قدم هذا لكان أفضل ولرو ترر هرذا لكران أجمرل وهرذا مرن أعظرم العبرر‬
‫وهو دليل على استيالء النقص على جملة البشر"‪.‬‬

‫وأخيرا َ بعرد أن تقردمنا باليسرير فري هرذا المجرال الواسرع نملرين أن ينرال القبرول ويلقرى‬
‫االستحسان‪ ..‬وصل اللهم وسلم على سيدنا وحبيبنا محمد وعلى نل بيته اجمعين‪..‬‬

‫نضال ال با ي‬
‫النجف األشرذ‪ /‬ال راق ‪2018‬‬
‫‪comp_dep_educ@yahoo.com‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫المؤلف باوتصار‪:‬‬

‫االستاذ الدكتور نضال خضير العبادي‪ ..‬حاصل على‬


‫شهادة البكالوريوس في الهندسة‪ ،‬بكالوريوس في‬
‫علوم الحاسبات‪ ،‬ماجستير ودكتورال في علوم‬
‫الحاسبات‪ .‬عمل في مجال الصناعة وعمل في مجال‬
‫التدريس في عدد من المؤسسات التعليمية‪ .‬مقوم‬
‫علمي لعدد من المجالت والمؤتمرات العلمية العربية‬
‫والعالمية‪ .‬أشرف على عدد من طلبة الدكتورال‬
‫والماجستير‪.‬‬
‫مؤلف لعدد من الكتب العلمية‪ ،‬وله العديد من البحوث العلمية في مجال اختصاصه‪.‬‬
‫مجال االختصاص الدقيل هو معالجة الصور والبيانات‪ .‬حاليا استاذ في جامعة‬
‫الكوفة – العراق‪.‬‬

‫‪17‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص االول‬
‫هياك البيانات والالوارزميات‬
‫‪DATA STRUCTURES AND‬‬
‫‪ALGORITHMS‬‬

‫‪ 1.1‬المقدمة‬

‫تستخدم كلمة هيكل وهيكلية فري مجراالت عديردة لتوصريف أغرراض كبيررة ترم بنائهرا‬
‫مررن وحرردات بنائيررة صررغيرة بأسررلوب تكررراري‪ ،‬وهياكررل البيانررات هرري كتلررة منطقيررة‬
‫نجمت عن تكراريرة عناصرر البيانرات وفرل ترتيرب محردد وعالقرات‪ ،‬وتعتبرر هياكرل‬
‫البيانات مرحلة وسيطة بين الملفات على وسائط التخزين وبين برامج التطبيقات‪.‬‬
‫فمثالً أن أسماء أفراد العائلة تنتظم تحت بناء يشبه الشجرة "‪ ,"tree‬حيث يعبر الجرد‬
‫عن الجذر فيها واألبناء عن الفروع وكذلك األحفاد وهكذا‪.‬‬
‫وكمثال نخر ينتظم الناس في طابور لشراء حاجة ما‪ ،‬فيكون الواقف أوالً يمثل رأس‬
‫الطابور واألخير يمثل ذيل الطابور‪.‬‬
‫أن دليل التلفون يضم في كل صفحة من صفحاته عمرودين أحردهما يردل علرى أسرماء‬
‫أشررخاص معينررين‪ ،‬مؤسسررات أو هي ررات محررددة‪ ،‬والعمررود األخررر يشررتمل علررى أرقررام‬
‫الهواتف التي يملكها األفراد أو المؤسسات أو الهي ات الموجودة في العمود األول‪.‬‬
‫ويكتمل هذا التشكيل المنظم بترتيب العمود األول أبجديا ً وذلك لتسهيل عملية البحرث‬
‫عن فرد أو مؤسسة أو هي ة معينة‪.‬‬
‫كررل هررذل األمثلررة تبررين لنررا حقيقررة واحرردة‪ ،‬هرري أن المعلومررات تمترراز بالترتيررب‪ ،‬ه رذا‬
‫الترتيب يعرف بالهيكل أو هياكل البيانات "‪."data structure‬‬

‫‪19‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مصرررطلح هياكرررل البيانرررات يسرررتخدم لوصرررف طريقرررة خرررزن البيانرررات‪ ،‬ومصرررطلح‬


‫الخوارزمية يستخدم لوصف طريقة معالجة البيانات‪ .‬هياكل البيانات والخوارزميات‬
‫متعلقرررة واحررردة مرررع االخررررى‪ .‬ان اختيرررار هيكرررل بيررراني معرررين سررريؤير علرررى نررروع‬
‫الخوارزمية التي ربما تسرتخدمها‪ ،‬واختيرار الخوارزميرة ترؤير علرى هياكرل البيانرات‬
‫المستخدمة‪.‬‬
‫الخوارزمية هي عدد محدد من االيعازات‪ ،‬كل ايعاز لره معنرى واضرح ومرن الممكرن‬
‫انجرازل بكميرة جهررد لره حرردود‪ ،‬وبطرول وقررت لره حردود ايضررا‪ .‬بغرض النظررر عرن قرريم‬
‫المدخالت التي تستخدم‪ ،‬فان الخوارزمية تنتهي بعد تنفيذ عدد محدد من االيعازات‪.‬‬

‫‪ 1.2‬الم لومات والبيانات‬


‫تعررف البيانرات علرى أنهرا مجموعرة مرن الحقرائل واألفكرار التري لرم يرتم معالجتهرا‪،‬‬
‫وتعرف بأنها المادة الخام للمعلومات‪ ،‬وحتى تصبح البيانات معلومات البد أن تعالج‬
‫هذل البيانات بطريقة معينة لتعطي بيانات ذات فائدة معينة تسمى بالمعلومات‪ ،‬تمتاز‬
‫المعلومات عن البيانات في أنها مرتبة‪ ،‬مصنفه‪ ،‬وذات فائدة معينة‪.‬‬

‫‪ 1.3‬هياك بيانات‬
‫هياكل البيانات هي تمث يرل لعالقرات منطقيرة موجرودة برين عناصرر البيانرات المفرردة‪.‬‬
‫بكالم اخر‪ ،‬فان هياكل البيانات تحدد طريقة تنظيم كامل عناصر البيانات والتي تأخذ‬
‫باالعتبررار لرريس البيانررات الترري تخررزن فقررط لكررن ايضررا عالقتهررا مررع بعررض‪ .‬مصررطلح‬
‫هياكل البيانات يستخدم لوصف طريقة خزن البيانات‪.‬‬
‫اذن هياكل البيانات هي طريقة خاصة لخزن وتنظيم البيانرات فري الحاسروب‪ ،‬بحيرث‬
‫من الممكن ان تستخدم بشكل كفوء‪.‬‬
‫لتطوير برنامج لخوارزمية معينرة يجرب علينرا اختيرار هيكرل البيانرات المناسرب لهرذل‬
‫الخوارزمية‪ .‬لذلك‪ ،‬فان البرنامج عبارة عن‪:‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫خوارزمية ‪ +‬هيكل بيانات = برنامج‬


‫هياكل البيانات يقال عنها خطية )‪ (linear‬ذا كانت عناصرها عبارة عن متوالية او‬
‫قائمة خطية‪ .‬هياكرل البيانرات الخطيرة مثرل المصرفوفات‪ ،‬المكردس‪ ،‬الطرابور‪ ،‬القروائم‬
‫الموصولة تنظم بياناتها على شكل ترتيب خطي‪ .‬ويقال عن هياكل البيانات انها غير‬
‫خطية ذا كانت عناصرها عبارة عرن تصرنيف هرمري حيرث تظهرر عناصرر بياناتهرا‬
‫بمستويات مختلفة‪.‬‬
‫االشررجار والمخططررات تسررتخدم بشرركل كبيررر هياكررل البيانررات غيررر الخطيررة‪ .‬هياكررل‬
‫االشجار والمخططات تمثل عالقة هرمية بين عناصر البيانات المفردة‪.‬‬

‫انوا هياك البيانات‬ ‫‪1.4‬‬


‫انواع البيانات هي طريقة لتصنيف مختلف انواع البيانرات مثرل االعرداد الصرحيحة‪،‬‬
‫السالسررل الحرفيررة‪...‬الا‪ .‬والترري تحرردد القرريم الترري مررن الممكررن اسررتخدامها مررع ن روع‬
‫البيانات المقابل‪ ،‬نوع العمليات التي من الممكن انجازها على البيانات المقابلة‪.‬‬
‫البيانرات علرى نروعين نروع بيانرات مبنري داخليرا ونروع بيانرات مشرتل يبنرى بواسرطة‬
‫المستخدم‪.‬‬

‫شك ‪ :1.1‬انوا هياك البيانات‬

‫‪21‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 1.4.1‬هياك البيانات المبنية اوليا ‪Built-in Data Structures‬‬


‫هي هياكل البيانات االساسرية (وتسرمى احيانرا هياكرل البيانرات البدائيرة) والتري تعمرل‬
‫بشركل مباشرر علررى ايعرازات الماكنرة‪ .‬لهررا تمثريالت مختلفرة فرري الحواسريب المختلفررة‪.‬‬
‫االرقام الصحيحة‪ ،‬ارقام النقطة العائمة‪ ،‬يوابرت الرمروز‪ ،‬يوابرت السالسرل الحرفيرة‪،‬‬
‫والمؤشرات جميعها ضمن هذا المفهوم‪.‬‬

‫‪‬‬ ‫‪Integers‬‬
‫‪‬‬ ‫)‪Boolean (true, false‬‬
‫‪‬‬ ‫)‪Floating (Decimal numbers‬‬
‫‪‬‬ ‫‪Character and Strings‬‬

‫‪ 1.4.2‬هياك البيانات المشتقة ‪Derived Data Type‬‬


‫هياكل البيانرات المشرتقة هري أكثرر هياكرل بيانرات تعقيردا وتشرتل مرن هياكرل البيانرات‬
‫البدائية‪ .‬هري تؤكرد او تركرز علرى تجميرع نفرس عناصرر البيانرات او عناصرر بيانرات‬
‫مختلفة والتي لها عالقرات فيمرا بينهرا (كرل عناصرر البيانرات)‪ .‬المصرفوفات‪ ،‬القروائم‪،‬‬
‫والملفات ترأتي ضرمن هرذا المفهروم‪ .‬هياكرل البيانرات المشرتقة هري البيانرات التري تنفرذ‬
‫بشكل مستقل حيث من الممكن تنفيرذها بطريقرة او اخررى‪ .‬انرواع البيانرات هرذل عرادة‬
‫تبنى بدمج انواع البيانات البدائية او المبنية داخليرا مرع العمليرات التري تشرتر معهرا‪.‬‬
‫مثل‬

‫‪‬‬ ‫‪List‬‬
‫‪‬‬ ‫‪Array‬‬
‫‪‬‬ ‫‪Stack‬‬
‫‪‬‬ ‫‪Queue‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 1.4.3‬هياك البيانات الثابتة والمتغيرة (الديناميكية)‬


‫مررن الممكررن ان تص ر نف هياكررل البيانررات علررى نرروعين وهمررا هياكررل البيانررات الثابت رة‬
‫وهياكل البيانات المتغيرة‪.‬‬
‫‪ ‬هياك البيانات الثابتة‬
‫مثل المتجهات والجداول والسجالت (المصفوفات)‪ ،‬حيرث عنرد االعرالن عنهرا يجرب‬
‫تحديد حجم هذل البيانات فال تقبل االضافة فوق حجمها ايناء تنفيذ البرنامج‪ ..‬وتمتاز‬
‫‪ .1‬الوصول السريع للعناصر‪.‬‬
‫‪ .2‬كلفة باهضه نسبيا بعمليات الحشر واالزالة‪.‬‬
‫‪ .3‬لها حجم يابت‪.‬‬
‫‪ ‬هياك البيانات المتغيرة‬
‫هي هياكل البيانات التي تنمو وتتقلص ايناء التنفيذ مثل (القوائم الموصولة‪ ،‬المكدس‪،‬‬
‫الطابور‪ ،‬االشجار الثنائية)‬
‫‪ .1‬سرعة في عمليات الحشر واالزالة للعناصر‪.‬‬
‫‪ .2‬بطيء في الوصول الى العناصر‪.‬‬
‫‪ .3‬مرونة في تغيير الحجم‪.‬‬
‫وهياكل البيانات المتغيرة نوعان‪:‬‬
‫‪ ‬هياكل بيانات خطية متغيرة‪ :‬مثل القوائم‪ ،‬الطوابير‪ ،‬الملفات‪ ،‬المكدس‪.‬‬
‫‪ ‬هياكل بيانات متشعبة (عشوائية)‪ :‬مثل االشجار‪ ،‬والمخططات‪.‬‬

‫‪ 1.5‬صفات هياك البيانات‬


‫الصفات العامة التي تتميز بها هياكل البيانات هي‪:‬‬
‫‪ ‬تحترروي علررى عناصررر مررن الممكررن ان تولررد عنصررر‪ ،‬مجموعررة عناصررر او‬
‫هيكل بياني اخر‪.‬‬

‫‪23‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫لها مجموعة من العمليات التي من الممكن ان تنجز علرى عناصرر البيانرات‪.‬‬ ‫‪‬‬
‫مثل البحث‪ ،‬الحشر‪...‬الا‪.‬‬
‫تصف القواعد لكيفية عالقة عناصر البيانات مع بعضها‪.‬‬ ‫‪‬‬
‫وقت التشغيل او التنفيذ لعمليرات هياكرل البيانرات يجرب ان يكرون بأقرل وقرت‬ ‫‪‬‬
‫ممكن‪.‬‬
‫الذاكرة المستخدمة لعملية هياكل البيانات يجب ان تكون بأقل ما يمكن‪.‬‬ ‫‪‬‬

‫‪ 1.6‬لماكا هياك البيانات‬


‫نظرررا الزديرراد تعقيررد التطبيقررات ووفرررة البيانررات‪ ،‬فرران هنررا يررالث مشرراكل‬
‫تطبيقية عامة تواجهنا هذل االيام‪.‬‬

‫‪ )1‬بحةةث البيانةةات‪ -‬نفرررض مطلرروب جرررد مليرون عنصررر ضررمن مخرزن‪ .‬لررذا فرران‬
‫التطبيل يبحث عن كل عنصر‪ .‬للبحث عن عنصر ضمن مليون عنصرر مرثال‪،‬‬
‫فرران كررل عنصررر يسررتغرق وقتررا يجررادل ومعالجترره‪ ،‬وبالتررالي فرران كررل عنصررر‬
‫سرريجعل عمليررة البحررث أكثررر بطررأ‪ .‬لررو فرضررنا ان هررذل البيانررات نمررت (أي كبررر‬
‫حجمها وازداد عدد عناصرها) فان البحث بالتأكيد يصبح ابطأ‪.‬‬
‫‪ )2‬سرعة الم ةال ‪ -‬سررعة المعرالج برالرغم مرن انهرا تبردو سرريعة جردا‪ ،‬لكرن هرذل‬
‫السرعة ستكون أكثر تحديدا ذا البيانات نمت الى بليون قيد مثال‪.‬‬
‫‪ )3‬البلبةةات المت ةةد ة‪ -‬ذا كرران هنررا مليررون مسررتخدم يبحررث عررن بيانررات بشرركل‬
‫متزامن على خادم الويب‪ ،‬حتى وان كان الخرادم سرريع جردا فانره ربمرا سيفشرل‬
‫عندما يبحث البيانات‪.‬‬

‫هررذل بعررض المشرراكل الترري تسررتوجب ايجرراد حررل لهررا‪ ،‬هياكررل البيانررات تررأتي ل نقرراذ‪.‬‬
‫البيانررات مررن الممكررن ان تررنظم بهيكررل بيانررات بطريقررة بحيررث انهررا تسرراعد علررى ان ال‬
‫تكون هنا حاجة لبحرث كرل البيانرات المطلوبرة‪ ،‬مرن الممكرن ان تبحرث غالبرا بشركل‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫لحظي عند استخدام هيكل البيانات المناسب (بغض النظر عن سرعة المعرالج وعردد‬
‫طلبات البحث)‪.‬‬

‫واحدة من الطرق التي ننظر بها الرى هياكرل البيانرات هرو ان نركرز علرى نقراط القروة‬
‫والضعف لكل نوع منها‪ .‬في هذا الفصل سنوفر نظرة عامرة علرى هرذل النقراط والتري‬
‫نوضحها في الجدول ‪.1.1‬‬

‫دول ‪ :1.1‬الصفات ال امة لهياك البيانات‬


‫المساوئ‬ ‫الفوائد‬ ‫هيك البيانات‬
‫سرعة حشر العناصر‪ ,‬سرعة كبيرة في بطء عمليرة البحرث‪ ,‬برطء عمليرة الحرذف‪,‬‬ ‫المصفوفات‬
‫حجمها يابت‬ ‫الوصول الى عناصر المصفوفة‬
‫اسررررررع فررررري عمليرررررات البحرررررث عرررررن برررطء عمليرررة الحشرررر والحرررذف‪ ,‬حجمهرررا‬ ‫المصررررررررررفوفات‬
‫يابت‬ ‫المصفوفات غير المرتبة‬ ‫المرتبة‬
‫ترروفر طريقررة مررن يصررل اخيرررا‪ ,‬يخرررج وصول بطيء الى العناصر االخرى‬ ‫المكدس‬
‫اوال‬
‫بطء الوصول الى العناصر االخرى‬ ‫توفر طريقة من يصل اوال يخرج اوال‬ ‫الطابور‬
‫بطء البحث‬ ‫القررررررررررررررررررررررروائم سرعة الحشر‪ ,‬سرعة الحذف‬
‫الموصولة‬
‫سرعة البحث‪ ,‬الحشر‪ ,‬الحذف (اذا بقرت خوارزمية الحذف معقدة‬ ‫االشجار الثنائية‬
‫الشجرة موزونة)‬
‫وصررول سررريع جرردا اذا عرررف المفترراح‪ ,‬بطء الحذف‪ ,‬الوصول يكون بطيء ان لم‬ ‫جدول التجزئة‬
‫يعررررف المفتررراح‪ ,‬غيرررر كفررروءة باسرررتخدام‬ ‫سرعة الحشر‪.‬‬
‫الذاكرة‪.‬‬
‫وصررررول بطرررريء الررررى برررراقي العناصررررر‪.‬‬ ‫سرعة في الحشر‪ ,‬الحذف‬ ‫التكديس‬
‫الوصول الى اكبر عنصر‬
‫بعض الخوارزميات بطي ة ومعقدة‪.‬‬ ‫ينمذج حاالت العالم الحقيقي‬ ‫المخططات‬

‫‪25‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الجدول ‪ 1.1‬يمثل خرواص هياكرل البيانرات التري سنناقشرها فري هرذا الكتراب‪ ،‬لرذلك ال‬
‫تندهش ان كانت غامضة بعض الشيء فسناتي عليها بالتفصيل في الفصول الالحقة‪.‬‬

‫‪ 1.7‬ماهي الالوارزمية‬
‫الخوارزمية هري مجموعرة منتهيرة مرن االيعرازات او المنطرل‪ ،‬تكترب لغررض انجراز‬
‫مهمه معرفة مسبقا‪ .‬الخوارزمية هي ليست شفرة كاملة او برنامج‪ ،‬هي فقط المنطرل‬
‫االسرراس (الحررل) لمشرركلة‪ ،‬والترري مررن الممكررن توضرريحها امررا علررى شرركل وصررف ذا‬
‫مستوى عال (باستخدام اللغات الحية مثال) او باستخدام المخططات )‪.(flowchart‬‬
‫الخوارزمية يقال عنها انها كفوءة وسريعة ذا كان وقت تنفيذها قليل و ذا لم تسرتهلك‬
‫مساحة كبيرة من الذاكرة‪ .‬ان كفاءة اداء أي خوارزمية تقاس بموجب ما يلي‪:‬‬
‫‪ .1‬تعقيد الوقت ‪Time Complexity‬‬
‫‪ .2‬تعقيد الفضاء ‪Space Complexity‬‬

‫‪ 1.7.1‬ت قيد الفضاء‬


‫هي تمثل كمية فضاء الذاكرة المطلروب مرن الخوارزميرة خرالل دورة حياتهرا (خرالل‬
‫تنفيذها)‪ .‬ان تعقيرد الفضراء يجرب ان يؤخرذ بنظرر االعتبرار بشركل جردي فري االنظمرة‬
‫الترري تسررمح بتعرردد المسررتخدمين وفرري حالررة ان يكررون حجررم الررذاكرة المترروفر محرردود‪.‬‬
‫الفضرراء المطلرروب مررن اي خوارزميررة يسرراوي مجمرروع فضرراء الررذاكرة الينرران مررن‬
‫المكونات‪:‬‬
‫‪ ‬جزء يابت وهو الفضاء المطلوب لخزن بيانات معينة ومتغيررات‪ ،‬والتري ال‬
‫تعتمد على حجرم المشركلة‪ .‬مثرال المتغيررات البسريطة والثوابرت المسرتخدمة‪،‬‬
‫حجم البرنامج ‪...‬الا‪.‬‬
‫‪ ‬جزء متغير وهو فضاء مطلروب مرن المتغيررات التري لهرا حجرم يعتمرد علرى‬
‫حجم المشكلة‪ .‬مثال تخصيص الذاكرة الديناميكي‪ ،‬فضاء المكدس ‪...‬الا‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫تعقيد الفضاء )‪ S(P‬ألي خوارزمية ‪ P‬يكون‬


‫)‪S(P) = C + SP(I‬‬

‫حيث ان ‪ C‬هي الجزء الثابت و )‪ SP(I‬هي الجزء المتغير للخوارزمية التري تعتمرد‬
‫على الخاصية االنية )‪ .(I‬فيما يلي مثال نحاول من خالله توضيح هذا المفهوم‬

‫)‪Algorithm: SUM (A, B‬‬

‫‪Step 1 - START‬‬

‫‪Step 2 - C ← A + B + 10‬‬

‫‪Step 3 - Stop‬‬

‫هنا لدينا يالث متغيرات )‪ (A, B, and C‬ويابرت واحرد‪ ،‬لرذلك فران ‪.S(P) = 1+3‬‬
‫االن الفضراء يعتمررد علرى نرروع البيانرات للمتغيرررات التري تعطررى ونروع الثابررت والترري‬
‫ستضرب بها وفقا لحجمها في الذاكرة‪.‬‬

‫‪ 1.7.2‬ت قيد الوقت‬


‫تعقيررد الوقررت ألي خوارزميررة هرري طريقررة لتمثيررل كميررة الوقررت المطلوبررة مررن قبررل‬
‫البرنامج كمال عمله (اكمال التنفيذ)‪ .‬متطلبات الوقت مرن الممكرن ان تعررف كدالرة‬
‫رقمية )‪ T(n‬حيث ان )‪ T(n‬من الممكن قياسها كعردد خطروات فري البرنرامج‪ ،‬تروفر‬
‫كل خطوة كمية وقت مستهلك‪.‬‬
‫على سبيل المثال اضافة اينران مرن االرقرام الصرحيحة كرل واحرد لهرا ‪ n-bit‬سرتحتاج‬
‫الى ‪ n‬من الخطوات‪ .‬بذلك فان الوقت الكلي للحسراب هرو ‪ T(n) = c*n‬حيرث ان ‪c‬‬
‫تمثل الوقت الالزم لجمع اينان من البتات‪ .‬هنا نالحر ان )‪ T(n‬تنمرو (تكبرر) بشركل‬
‫خطي ذا زاد حجم المدخل‪.‬‬
‫تعقيد الوقت للخوارزميات عادة يوضح بشكل عام باستخدام حرف ()‪ O‬الكبيرة‪.‬‬

‫‪27‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫تعقيد الوقت غالبا يقدر بحساب عدد الدوال االولية التي تنجز بالبرنامج‪ .‬ونظررا الن‬
‫كفرراءة الخوارزميررة ربمررا تتغيررر مررع اخررتالف انررواع البيانررات المدخلررة‪ ،‬عليرره فأننررا‬
‫سنستخدم لكل خوارزمية (اسوأ تعقيد وقت ‪)worst-case Time complexity‬‬
‫وذلك الن هنا اقصى وقت يحسب ألي حجم مدخالت‪.‬‬

‫عادة متطلبات الوقت لخوارزمية يقع تحت نوعين‪:‬‬


‫‪ ‬افضل وقت ‪ : Best Case‬اقل وقت مطلوب لتنفيذ البرنامج‪.‬‬
‫‪ ‬اسوأ وقت ‪ :Worst Case‬أكبر وقت مطلوب لتنفيذ البرنامج‪.‬‬

‫‪ 1.7.3‬حساب وقت الت قيد ‪Calculating Time Complexity‬‬


‫االن دعنا نتدرج الى اهم موضوع يتعلرل بتعقيرد الوقرت‪ ،‬وهرو كيرف مرن الممكرن ان‬
‫نحسب وقت التعقيد‪ .‬هو يبردو احيانرا مربرك جردا‪ ،‬ولكرن سرنحاول توضريحها بطريقرة‬
‫مبسطة‪.‬‬
‫االن المقياس االكثر عمومية لحساب وقت التعقيد هو )‪ (O‬الكبيرة‪ .‬هذل تزيرل جميرع‬
‫المعامالت الثابتة‪ ،‬لرذا فران وقرت العمرل للخوارزميرة مرن الممكرن ان يقردر نسربة الرى‬
‫)‪ ،(N‬حيث ان ‪ N‬تمثل عدد العبارات وتصل الى ما النهاية‪ .‬بشكل عام مرن الممكرن‬
‫ان نفكر بها مثل هذل‪:‬‬

‫; ‪Statement‬‬

‫اعالل لدينا عبارة واحدة‪ .‬تعقيد الوقت لها سيكون يابت‪ .‬وقت التشغيل للعبرارة سروف‬
‫ال يتغير نسبة الى ‪.N‬‬
‫)‪for (i=0 ; i < N ; i++‬‬

‫{‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪statement‬‬

‫}‬

‫تعقيد الوقت للخوارزمية اعالل سيكون خطي‪ .‬وقت التشغيل او التنفيذ لحلقة التكررار‬
‫تتناسررب بشرركل مباشررر مررع قيمررة ‪( N‬حيررث ان ‪ N‬تمثررل عرردد مرررات تنفيررذ العبررارة‬
‫‪ .)statement‬عندما نضاعف ‪ N‬فان وقت التنفيذ سيضاعف‪.‬‬
‫)‪for (i=0; i < N; i++‬‬

‫{‬

‫)‪for (j=0; j < N; j++‬‬

‫{‬

‫;‪statement‬‬

‫}‬

‫}‬

‫هنا‪ ،‬تعقيد الوقرت للخوارزميرة اعرالل سريكون تربيعري‪ .‬وقرت التنفيرذ لحلقتري التكررار‬
‫تتناسب مع مربع ‪ .N‬فعندما تضاعف ‪ ,N‬فان وقت التنفيذ يزداد بمقدار ‪.N * N‬‬
‫)‪while (low <= high‬‬

‫{‬

‫;‪mid = (low + high) / 2‬‬

‫)]‪if (target < list[mid‬‬

‫;‪high = mid - 1‬‬

‫)]‪else if (target > list[mid‬‬

‫;‪low = mid + 1‬‬

‫;‪else break‬‬

‫}‬

‫‪29‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الخوارزميرررة اعرررالل هررري لتجزئرررة مجموعرررة مرررن االرقرررام الرررى النصرررف‪ .‬االن‪ ،‬هرررذل‬
‫الخوارزمية سيكون لها لوغاريثم وقت تعقيد‪ .‬بالتاكيرد فران وقرت التنفيرذ للخوارزميرة‬
‫يتناسب مع عدد مرات ‪ N‬التي من الممكن التقسيم علرى (‪( )2‬حيرث ان ‪ N‬هنرا تمثرل‬
‫االعلى – االدنى )‪ .)(high-low‬هذا بسبب ان الخوارزمية تقسم مساحة العمل الرى‬
‫النصف في كل دورة‪.‬‬
‫)‪void quicksort (int list [ ], int left, int right‬‬

‫{‬
‫;)‪int pivot = partition (list, left, right‬‬

‫;)‪quicksort (list, left, pivot - 1‬‬

‫;)‪quicksort (list, pivot + 1, right‬‬

‫}‬

‫لنأخررذ المثررال السررابل ونناقشرره‪ ،‬الخوارزميررة اعررالل هرري جررزء منطقرري صررغير مررن‬
‫خوارزميررة ترتيررب االعررداد (سندرسررها الحقررا)‪ .‬االن فرري هررذل الخوارزميررة سننصررف‬
‫القائمة كل مرة (يعني وقت التعقيد هو لوغاريثم)‪ ،‬ولكن نعيد التكرار ‪ N‬من المرات‬
‫(حيررث ان ‪ N‬يمثررل حجررم القائمررة) (بمعنررى اعررادة التعقيررد اللوغرراريثمي بعرردد ‪ N‬مررن‬
‫المرات)‪ .‬لذا فان وقت التعقيد سيكون )‪.N*log (N‬‬
‫وقرررت التنفيرررذ لعررردد ‪ N‬مرررن التكررررارات والتررري هررري لوغاريثميرررة‪ ،‬وهرررذا يعنررري ان‬
‫الخوارزمية هي لوغاريثمية وخطية بنفس الوقت‪.‬‬
‫م حظة‪ :‬بشركل عرام‪ ،‬عمرل شريء مرع كرل عنصرر فري مصرفوفة احاديرة هرو خطري‪،‬‬
‫عمررل شرريء مررع كررل عنصررر فرري مصررفوفة ينائيررة هررو تربيررع‪ ،‬تقسرريم مسرراحة العمررل‬
‫للنصف هو لوغاريثمي‪ .‬في الجدول ‪ 1.2‬بعض الحاالت القياسية لتعقيد الوقت‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫دول ‪ :1.2‬ت قيد الوقت لب ض الالوارزميات‬

‫ت قيد الوقت‬ ‫الالوارزمية‬


‫)‪Ο(1‬‬ ‫يابت ‪constant‬‬
‫)‪Ο(log n‬‬ ‫لوغاريثمي ‪logarithmic‬‬
‫)‪Ο(n‬‬ ‫خطي ‪linear‬‬
‫)‪Ο(n log n‬‬ ‫‪N log n‬‬
‫)‪Ο(n2‬‬ ‫مربع ‪quadratic‬‬
‫)‪Ο(n3‬‬ ‫مكعب ‪cubic‬‬
‫)‪nΟ(1‬‬ ‫متعدد الحدود ‪polynomial‬‬
‫)‪2Ο(n‬‬ ‫االسي ‪exponential‬‬

‫‪31‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص الثاني‬
‫المصفوفات ‪ARRAYS‬‬
‫المقدمة‬ ‫‪2.1‬‬
‫القوائم هي واحدة من أكثر هياكل البيانات التي يتكرر استخدامها‪ .‬بالرغم مرن‬
‫ان كل البرامج تشرتر برنفس التعريرف للقروائم وهري (متواليرة مرن عناصرر البيانرات‬
‫المتجانسررة)‪ ،‬لكررن نرروع البيانررات الترري تخررزن فرري القرروائم تختلررف مررن برنررامج ألخررر‪.‬‬
‫بعضها يستخدم قوائم من االعداد الصحيحة‪ ،‬اخرى تسرتخدم قروائم الرمروز‪ ،‬االرقرام‬
‫الكسرية‪ ...‬وهكذا‪ .‬في هذا الفصل سيتم التركيز على اول انواع هياكل البيانات وهي‬
‫المصفوفات بنوعيها المصفوفات ذات البعد االحرادي والمصرفوفات المتعرددة األبعراد‬
‫مع امثلة توضيحية والعمليات التي من الممكن ان تجرى عليها‪.‬‬

‫‪ 2.2‬المصفوفات‬
‫المصفوفات هي هيكل بيانات تخزن مجموعة من المتغيرات لها نفرس النروع‪،‬‬
‫فهي تجميع لكيانات البيانات المتشابهة والتي تخزن في مواقع ذاكرة متجراورة تحرت‬
‫اسم محدد‪ .‬بكالم اخر‪ ،‬فان المصفوفة هي مجموعة من الكيانات (تسمى العناصرر)‪،‬‬
‫جميررع هررذل العناصررر مررن نرروع واحررد ويررتم خزنهررا فرري الررذاكرة فرري مواقررع متجرراورة‪،‬‬
‫وتعرف المصفوفة من خالل االسم الذي يسرند لهرا ويرتم اختيرار اسرم المصرفوفة وفقرا‬
‫لقواعد اختيار اسماء المتغيرات‪ ،‬ويستخدم هذا األسم ل شرارة الرى المصرفوفة ولريس‬
‫الررى عناصررر المصررفوفة اذ ان عناصررر المصررفوفة يررتم االشررارة الررى كررل واحررد منهررا‬
‫باستخدام أسم المصفوفة متبوعا برقم الدليل (الفهرس) الذي يشير الى موقع العنصر‬
‫في المصفوفة‪.‬‬
‫تسررتخدم المصررفوفة كبررديل عررن االعررالن عررن عرردد مررن المتغيرررات المتشررابهة‬
‫النوع‪ ،‬فمثال برنامج يحتاج الى عشرة متغيررات مرن نروع األعرداد الصرحيحة‪ ،‬فبردال‬
‫من األعالن عن عشرة متغيرات وبأسماء مختلفة يمكرن ان تعلرن عرن هرذل العناصرر‬
‫كمصفوفة من نوع األعداد الصحيحة‪ ،‬حجمها عشرة عناصرر ولهرا اسرم واحرد‪ ،‬وان‬

‫‪33‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫كررل عنصررر مررن الممكررن ان يعامررل كمتغيررر مفرررد لرريس لرره عالقررة ببرراقي عناصررر‬
‫المصفوفة األخرى ويرتم االشرارة لره مرن خرالل أسرم المصرفوفة وموقرع العنصرر فري‬
‫المصفوفة‪.‬‬

‫‪ 2.3‬المصفوفات االحا ية‬


‫المصررفوفة االحاديررة هرري هيكررل مركررب لنرروع بيانررات يتكررون مررن تجميررع لعناصررر‬
‫متجانسة‪ ،‬مرتبة‪ ،‬ذات حجم يابت‪ ،‬منتهية بحيث يكون الوصرول لهرا ممكرن‪ .‬وعنردما‬
‫نقول منتهية هذا يعني ان العنصر االخيرر محردد‪ .‬حجرم يابرت يعنري حجرم المصرفوفة‬
‫يجب ان يكون معروف مسبقا‪ ،‬وهي ال تعني بران كرل خليرة فري المصرفوفة يجرب ان‬
‫تحتوي على قيم ذات معنى‪ .‬مرتبة تعني ان هنا عنصر اول وعنصر ياني وهكرذا‪.‬‬
‫(الموقررع النسرربي للعناصررر مرتبررة‪ ،‬ولرريس بالضرررورة ان تكررون القرريم فرري المصررفوفة‬
‫مرتبة)‪ .‬والن جميع عناصر المصفوفة يجب ان تكون جميعها من نفس النوع‪ ،‬فهري‬
‫ماديا متجانسة (اي كلها لها نفس نوع البيانات)‪.‬‬
‫في ‪ C++‬يتم االعالن عن المصفوفة بتحديرد نوعهرا اوال يرم اسرم المصرفوفة واخيررا‬
‫حجمها كما في ادنال‪.‬‬
‫; ]‪int numbers [10‬‬

‫الح هنا ان حجرم المصرفوفة يوضرع برين قوسرين مرربعين‪ .‬هرذا االعرالن يعلرن عرن‬
‫ترتيرررب خطررري لمواقرررع المصرررفوفة (مواقرررع متجررراورة)‪ ,‬ومرررن الممكرررن ان نصرررور‬
‫المصررفوفة بعررد ان يررتم االعررالن عنهررا كمررا فرري الشرركل ‪( 2.1‬الحر ان االعررالن عررن‬
‫المصفوفة يعني تحديد مواقع في الذاكرة خالية من القيم)‪.‬‬
‫كل عنصر في المصفوفة من الممكن الوصول اليه مباشررة وذلرك مرن خرالل الموقرع‬
‫النسبي له في المصفوفة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :2.1‬مصفوفة احا ية افتراضية‬

‫المصفوفة االحادية هي عبارة عن سلسلة من العناصر المتشابهة النوع والتي‬


‫تخزن في الذاكرة في مواقع متجاورة والتي من الممكن االشرارة لكرل واحرد مرن هرذل‬
‫العناصر بشكل مفرد من خالل اضرافة الررقم الردليلي )‪ (index‬الرى األسرم التعريفري‬
‫الوحيد لها‪ ،‬ومثلها مثرل المتغيررات االعتياديرة فران المصرفوفة يجرب ان يرتم األعرالن‬
‫عنها قبل اول استخدام لها‪.‬‬
‫اسم المصفوفة هو اي اسم يتم اختيارل من قبل المبرمج علرى ان يتبرع القواعرد‬
‫المعروفرة بتسررمية المتغيرررات‪ ،‬امررا عرردد العناصرر الترري تحتويهررا المصررفوفة يجررب ان‬
‫يكون دائما محددا بين قوسين مربعين‪ ،‬وعنرد االعرالن عرن المصرفوفة فران المتررجم‬
‫سرريحجز عررددا مررن المواقررع المتجرراورة فرري الررذاكرة طررول كررل موقررع (عرردد البايتررات‬
‫المحددة له) يساوي الحجم المحدد لذلك النوع‪ ،‬وطبعا نفترض ان هذل المواقرع خاليرة‬
‫مررن اي قيمررة او ربمررا هرري تحترروي علررى قيمررة قديمررة لرريس لهررا عالقررة بهررذا البرنررامج‬
‫ويجب تغييرها‪.‬‬
‫م حظة‪ :‬دائما الرقم الموجود بين القوسين المربعين والذي يمثل عدد العناصر يجب‬
‫ان يكررون مررن االعررداد الصررحيحة الموجبررة او حررروف فقررط‪ .‬التعبيرررات التاليررة غيررر‬
‫مقبولة‪.‬‬
‫;]‪Static int value [0.02‬‬

‫‪35‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫;]‪Float number [-90‬‬

‫;]‪Char s [$‬‬

‫م حظةةة‪ :‬قبررل اسررتخدام أي مصررفوفة احاديررة او متعررددة االبعرراد فرري البرنررامج‪ ،‬يجررب‬
‫توفير المعلومات التالية الى المترجم او المفسر‬
‫‪ -1‬نوع المصفوفة مثال )…‪.(int, float, char‬‬
‫‪ -2‬اسرررم المصرررفوفة (ويرررتم اختيرررارل مرررن المبررررمج ويفضرررل ان يررردل علرررى عمرررل‬
‫المصفوفة)‪.‬‬
‫‪ -3‬عرردد األبعرراد (‪ )subscript‬فرري المصررفوفة (هررل المصررفوفة احاديررة او متعررددة‬
‫االبعاد)‪.‬‬
‫‪ -4‬العدد الكلي لمواقع الذاكرة المخصصة او بتحديرد أكثرر‪ ،‬عردد العناصرر لكرل بعرد‬
‫من أبعاد المصفوفة‪.‬‬

‫‪ 2.4‬انشاء المصفوفة ‪Array Initialization‬‬


‫عند االعالن عن المصفوفة فأنهرا ستنشرأ (تخلرل) كمصرفوفة خاليرة مرن القريم‪،‬‬
‫حيث ان عناصرها ال تحتوي على قيم مالم يتم خزن قريم فيهرا اي اسرناد قريم ابتدائيرة‬
‫لهررذل العناصررر وتسررمى هررذل العمليررة ابتررداء المصررفوفة‪ ،‬لررذلك يجررب عرردم أجررراء اي‬
‫عملية على عناصر المصفوفة ذا لم يتم اسناد قيم لها‪ ،‬كما هو الحرال مرع المتغيررات‬
‫االعتيادية‪.‬‬
‫المصفوفات ايضا من الممكرن ان تعررف كمرا فري المتغيررات االعتياديرة علرى‬
‫انهررا محليررة او عامررة )‪ ،(Global and Local‬وفرري كلتررا الحررالتين سررواء كانررت‬
‫مصفوفة عامة او محليرة فران اسرناد القريم لهرا مرن الممكرن ان يرتم برأكثر مرن طريقرة‪،‬‬
‫واحدة من هذل الطرق اسناد قيم ابتدائية لكل عنصر من عناصررها وذلرك مرن خرالل‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫وضع قيم بين قوسين متوسطين تفصل بين قيمة واخرى فارزة (بنفس طريقرة كتابرة‬
‫المجاميع) ومساواتها الى المصفوفة (تسند لها قيم ايناء كتابة البرنامج) كما يأتي‪:‬‬
‫; } ‪ABC [ 5 ] = { 5, -77, 34, 60, 2‬‬

‫ويجب ان تنتبه الرى ان عردد القريم برين القوسرين المتوسرطين يجرب ان ال تزيرد‬
‫على عدد عناصر المصفوفة التي تم االعالن عنها في اعالن المصرفوفة (فراذا أعلرن‬
‫عن مصفوفة من خمسة عناصر ووضع بين القوسين المتوسطين سرتة قريم‪ ،‬فري هرذل‬
‫الحالة سيصدر المترجم رسالة خطأ‪ .‬القيم ستسند الى عناصر المصفوفة بالتتالي من‬
‫اليسررار الررى اليمررين (اي ان القيمررة فرري اقصررى اليسررار (‪ )5‬ستسررند الررى العنصررر فرري‬
‫الموقع (‪ ،)0‬والقيمة التي على يمينهرا (‪ )-77‬ستسرند الرى العنصرر فري الموقرع (‪..)1‬‬
‫وهكذا)‪.‬‬
‫م حظةةة‪ :‬عنرردما يررتم ابتررداء القرريم سرروف تسررند لعناصررر المصررفوفة‪ C++ ،‬يسررمح‬
‫بإمكانيرة ترر االقرواس المربعرة فارغرة ][‪ .‬فري هرذل الحالرة‪ ،‬فران المتررجم سرريفرض‬
‫حجم للمصفوفة يطابل عدد القيم الموجودة بين االقواس المتوسطة‪ .‬مثال‬
‫; }‪ABC [ ] = {2, 5, 8‬‬

‫هنا سيحدد المترجم عدد العناصر (حجم المصفوفة) بثالث‪.‬‬


‫م حظة‪ :‬في ادنال بعض االمثلة المقبولة البتداء المصفوفة‬
‫;}‪int value [7] ={10, 11, 12, 13, 14, 15, 16‬‬
‫;}‪float coordinate [5] ={0, 0.45, -0.5, -4.0, 5.0‬‬
‫;}` ‪char sex [2] ={`M`,` F‬‬

‫;}`‪char name [5] ={`s`,`i`,`n`,`a`,`n‬‬

‫من الممكن انشاء المصفوفة وذلك بأسناد قيم لعناصرر المصرفوفة مرن لوحرة المفراتيح‬
‫عند تنفيذ البرنامج‪ ،‬وهذل هي الطريقة االفضل ألنها تعني ان البرنرامج سريكون عرام‬
‫ألي قيم يمكن ادخالها وال يحدد برالقيم التري ترم كتابتهرا اينراء كتابرة البرنرامج كمرا فري‬

‫‪37‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الطريقة السابقة‪ .‬هذه الطريقة وهي االكثر شيوعا ستعتمد على حلقة التكررار إلسرناد‬
‫قيم لعناصر المصفوفة كما في المثال ادناه‪.‬‬
‫>‪#include<iostream‬‬
‫; ‪using namespace std‬‬
‫{ )‪void main (void‬‬
‫; ]‪int A [7‬‬
‫; ‪int i‬‬
‫) ‪for ( i= 0 ; i <= 6 ; i++‬‬
‫; ]‪cin >> A [i‬‬

‫}‬

‫الح ر اننررا اسررتخدمنا حلقررة تكرررار بعرردد عناصررر المصررفوفة وذلررك لكرري يررتم‬
‫المرور على جميع مواقع المصفوفة ويسرند لهرا قريم‪ .‬امرا طباعرة عناصرر المصرفوفة‬
‫فتتم بنفس الطريقة التي استخدمنا فيها حلقرة التكررار ألسرناد قريم لعناصرر المصرفوفة‬
‫مع تغيير ايعاز االدخال بإيعاز االخراج‪ ..‬على ان تنتبه الى انه ال يمكنك طباعرة اي‬
‫عنصر من عناصر المصفوفة ذا لم تسبقه بعملية اسناد قيم لعناصر المصفوفة‪.‬‬
‫م حظة‪ :‬المصفوفة االحادية عادة ودائما تبدأ بالموقع صفر‪.‬‬
‫مثال‪ :‬برنامج يوضح طريقة اسناد وطباعة عناصر مصفوفة‪.‬‬
‫>‪# include<iostream‬‬
‫;‪using namespace std‬‬
‫{ )‪void main (void‬‬
‫;}‪int A [7] ={11, 12, 13, 14, 15, 16, 17‬‬
‫; ‪int i‬‬
‫; " ‪cout<< " contents of the array: \n‬‬
‫)‪for (i=0 ; i <= 6; i++‬‬
‫; '‪cout << a[i] << '\t‬‬ ‫}‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :2.2‬يوضح كيفية وزل عناصر المصفوفة في كاكرة الحاسوب‪.‬‬

‫ان من أكثر االخطاء التي تحدث هري عنردما تحراول خرزن عنصرر فري مواقرع‬
‫ماوراء حجم المصفوفة‪ ،‬فمثال لو عرفت مصفوفة كما يأتي‪:‬‬
‫; ]‪int A [6‬‬

‫عندما تستخدم هرذل المصرفوفة فران دليرل المصرفوفة يترراوح برين (‪ ،)5-0‬فراذا‬
‫حددت الدليل بغير ذلك فان خطأ سيحدث‪ .‬في معظم الحواسيب ال يوجرد تحرذير عنرد‬

‫‪39‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫اسررتخدام دليررل خررارج حجررم المصررفوفة‪ ،‬كمثررال افرررض أنررك حررددت قيمررة الررى الرردليل‬
‫الموضح ادنال‪:‬‬
‫; ‪A [7] = 255‬‬

‫هنررا الحاسرروب سرريعامل هررذا االمررر علررى انرره صررحيح ويضررع القيمررة ‪ 225‬فرري‬
‫العنرروان المناسررب فرري الررذاكرة‪ ،‬ولكررن عنررد حسرراب موقررع او عنرروان هررذ القيمررة فأنهرا‬
‫ستكون في العنوان الذي يحوي المتغير (‪ )more_stuff‬كما في الشكل ‪ ,2.2‬ولذلك‬
‫فان هذل القيمة الخاصة بالمتغير (‪ )more_stuff‬سوف تتغير بشكل غير مقصود‪.‬‬
‫م حظة‪ :‬ان حساب موقع اي عنصر من عناصر المصفوفة في الرذاكرة يتبرع‬
‫العالقة التالية‪:‬‬
‫عةةد بايتةةات نةو‬ ‫الموقةةع فةةي الةةذاكرة و ال نةةوال االبتةةدائي ي رقةةم الةةدلي‬
‫المصفوفة‬
‫العنرروان االبترردائي هررو عنرروان اول عنصررر بالمصررفوفة (فرري الشرركل ‪ 2.2‬هررو‬
‫‪ 1023‬للمصفوفة ‪.)A‬‬
‫رقم الدليل هو موقع العنصر في المصفوفة مثال العنصر في الموقع ‪.5‬‬
‫عدد بايتات النوع هو عدد البايتات التي تحدد لكل نوع في الذاكرة فمثال يحردد‬
‫بايتين لألعداد الصحيحة (من الممكن اربعة) وبايت للحروف وهكذا‪.‬‬
‫فمثال لو أردنا استخراج موقع الذاكرة ل يعاز ]‪ A [7‬سيكون‬
‫‪1023 + 7 * 2 = 1037‬‬ ‫العنوان =‬

‫‪ 2.5‬الوصول الل عناصر المصفوفة‬


‫عند كتابة برنامج يحتوي على مصفوفة فان بإمكانك الوصول الى اي عنصر‬
‫مررن عناصررر المصررفوفة بشرركل مفرررد وفرري اي مكرران مررن البرنررامج وتتعامررل مررع هررذا‬
‫العنصر كما تتعامل مع اي متغيرر عرادي مرن حيرث القرراءة والتحرديث‪ .‬ان الصريغة‬
‫المستخدمة ل شارة الى اي عنصر يتم من خرالل كتابرة اسرم المصرفوفة متبروع بررقم‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫موقع هذا العنصر في المصفوفة‪ ،‬ويكون الرقم محدد برين قوسرين مرربعين‪ ،‬كمرا فري‬
‫ادنال‪:‬‬
‫; ] ‪Name [ index‬‬

‫هذل الصيغة تمثل قيمرة العنصرر‪ ،‬وهري تكراف اسرم المتغيرر االعتيرادي وعلرى‬
‫هررذل الصرريغة با مكرران اجررراء كررل العمليررات الترري با مكرران اجراءهررا علررى المتغيررر‬
‫االعتيادي من ذلك النوع‪ .‬فمثال ذا كنت ترغب بأسناد القيمة ‪ 45‬الى العنصر الثاني‬
‫في المصفوفة (‪ ،)ABC‬فسيتم ذلك كما يأتي‪:‬‬
‫; ‪ABC [ 2 ] = 45‬‬

‫كما يمكنك ان تمرر هذل القيمة الى متغير اخر اعتيادي مثال (‪ ،)x‬وكما يأتي‪:‬‬
‫; ] ‪x = ABC [ 2‬‬

‫عليه فان المتغير (‪ )x‬ستكون قيمته مساوية الى ‪.45‬‬


‫م حظة‪ :‬تستخدم االقواس المربعة مع المصفوفات ألمرين‪:‬‬
‫األول‪ :‬يسررتخدم لألعررالن عررن حجررم المصررفوفة عنرردما يحترروي عررددا صررحيحا‬
‫موجبا وقت االعالن عن المصفوفة‪.‬‬
‫الثاني‪ :‬يستخدم في تحديد موقع العنصر في المصفوفة‪.‬‬
‫م حظة‪ :‬ذا لرم يرتم مسراواة عردد عناصرر المصرفوفة خارجيرا عنرد ابترداء المصرفوفة‬
‫كأن يكو ن عدد القريم المسرندة والمحرددة برين القوسرين المتوسرطين هرو اقرل مرن العردد‬
‫الررذي يحرردد حجررم المصررفوفة‪ ،‬ففرري هررذل الحالررة‪ ،‬فرران هررذل القرريم ستسررند الررى العناصررر‬
‫المقابلة لها اما باقي العناصر فستسند لها القيم االفتراضية وهي صفر‪ .‬مثال‬
‫; }‪Myarray [ 5 ] = {3, 65, 21‬‬
‫فستكون قيم العناصر كما يأتي‪:‬‬
‫; ‪Myarray [ 0 ] = 3‬‬
‫; ‪Myarray [ 1 ] = 65‬‬
‫; ‪Myarray [ 2 ] = 21‬‬

‫‪41‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫; ‪Myarray [ 3 ] = 0‬‬

‫; ‪Myarray [ 4 ] = 0‬‬

‫م حظة‪ :‬في ‪ C++‬ال يسمح بالعمليات البسيطة التي تتضمن كامل المصفوفة‪ .‬حيرث‬
‫ان اسم المصفوفة يعامل كمتغيرر منفصرل للعمليرات مثرل عمليرة المسراواة (االسرناد)‪،‬‬
‫عمليات المقارنة ‪...‬وهكذا فمثالً لو كانت )‪ (A, B‬مصفوفتان مرن نفرس النروع وذات‬
‫الحجم فأن عمليات االسناد والمقارنة يجب ان تجري فقط لعنصر مع عنصر اخر‪.‬‬
‫}‪int A[4]={2, 3, 4, 5‬‬
‫}‪int B[4]={1, 3, 5, 7‬‬
‫فالعمليات التالية مقبولة‪:‬‬
‫) ] ‪* if (A [ 2 ] > B [ 2‬‬
‫;" ‪cout<<" array are different \n‬‬

‫) ] ‪* while ( A [ 1 ] == B [ 3‬‬
‫;" ‪cout<<" AAAAAAAAAA \n‬‬
‫العمليات التالية غير مقبولة‪:‬‬
‫)‪* if (A == B‬‬
‫;" ‪cout<<" array elements are equal \n‬‬
‫)‪* while (A > B‬‬
‫;" ‪cout<<" array processing \n‬‬

‫‪ 2.6‬المصفوفات المت د ة االب ا‬


‫المصرررفوفات المتعرررددة االبعررراد مرررن الممكرررن ان تعررررف علرررى انهرررا مصرررفوفة‬
‫المصفوفات‪ ،‬فمن الممكن ان تكون لك مصفوفة تحتوي على أكثر من بعد واحد‪ ،‬كل‬
‫بعررد مررن الممكررن ان يمثررل فرري المصررفوفة كرررقم دليلرري‪ ،‬انررت تعلررم ان المصررفوفة ذات‬
‫البعررد الواحررد كرران لهررا رقررم دليلرري واح رد بعررد اسررم المصررفوفة‪ ،‬لكررن المصررفوفة ذات‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫البعدين سيكون لها رقما دليل بعد اسم المصفوفة‪ ،‬والمصرفوفة ذات الثاليرة ابعراد لهرا‬
‫يالية ارقام دليل بعد اسم المصفوفة وهكذا‪ .‬المصفوفات من الممكن ان يكون لهرا اي‬
‫عدد من االبعاد‪ ،‬ولكننا سنكتفي في هذا القسرم بشررح المصرفوفة ذات البعردين فضرال‬
‫عن المصفوفة ذات البعد الواحرد النهمرا االكثرر اسرتخداما‪ ،‬وجميرع المصرفوفات ذات‬
‫االبعاد االكثر تطابل المصفوفة ذات البعدين بالعمل‪ .‬من االمثلرة الجيردة للمصرفوفات‬
‫الثنائيرة هرري رقعررة الشررطرنج‪ ،‬حيرث تتكررون مررن يمانيررة صرفوف ويمرراني اعمرردة (كررل‬
‫صف يمثل مصفوفة احادية وكل عمرود يمثرل مصرفوفة احاديرة ايضرا)‪ ،‬المصرفوفات‬
‫الثنائيررة تتكررون مررن صررفوف واعمرردة ترررقم الصررفوف ابتررداءا مررن الرررقم (‪ )0‬وترررقم‬
‫االعمدة ايضا ابتداءا من الرقم (‪ .)0‬وكل خلية في المصفوفة الثنائية تمثرل موقرع فري‬
‫الررذاكرة وبالتررالي سررتحمل قيمررة‪ ،‬وكمررا فرري المصررفوفات االحاديررة فرران لكررل مصررفوفة‬
‫ينائية اسم وحيد تعرف به وهو اي اسم يتم اختيارل من المبرمج على ان يتبرع قواعرد‬
‫تسمية المتغيرات‪ ،‬وبالتأكيد فران لكرل مصرفوفة ينائيرة نروع وهرو يمثرل نروع البيانرات‬
‫المخزنررة فرري المصررفوفة وبا مكرران اسررتخدام اي نرروع مررن االنررواع المقبولررة فرري لغررة‬
‫‪.C++‬‬
‫المصفوفات الثنائية لها اسرتخدامات كثيررة وهري تسراعد علرى تسرهيل التعامرل‬
‫مع بعض المسرائل المعقردة‪ ..‬فمرثال لردينا عردد مرن المعامرل (ياليرة معامرل‪ ..‬معمرل‪،1‬‬
‫معمل‪ ،2‬معمل‪ )3‬التي تنتج مواد كهربائية متشابهة مثرل (تلفزيرون‪ ،‬يالجرة‪ ،‬غسرالة‪،‬‬
‫مجمدة‪ ،‬مكيف) فمن الممكن تمثيلها بمصفوفة ينائية والتعامرل معهرا علرى هرذا المبردأ‬
‫كما يلي‪:‬‬

‫مكيف‬ ‫مجمدة‬ ‫غسالة‬ ‫يالجة‬ ‫تلفزيون‬


‫معمل‪1‬‬ ‫‪20‬‬ ‫‪12‬‬ ‫‪56‬‬ ‫‪34‬‬ ‫‪23‬‬
‫معمل‪2‬‬ ‫‪21‬‬ ‫‪34‬‬ ‫‪44‬‬ ‫‪43‬‬ ‫‪22‬‬
‫معمل‪3‬‬ ‫‪12‬‬ ‫‪15‬‬ ‫‪23‬‬ ‫‪31‬‬ ‫‪42‬‬
‫شك ‪ :2.3‬مثال توضيحي لتمثي المصفوفات الثنائية‬

‫‪43‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫االن لو سألنا كم غسالة انتجت فري المعمرل ‪ ..1‬بالتأكيرد سريكون الجرواب ‪،56‬‬
‫و ذا كان السؤال كرم مكيرف أنرتج فري المعمرل ‪ 3‬فسريكون الجرواب ‪ 12‬وهكرذا (عليرك‬
‫االن ان تستنتج الطريقة التي تتعامرل بهرا مرع عناصرر المصرفوفة)‪ .‬حجرم المصرفوفة‬
‫هو (‪( )3×5‬اسماء االعمدة والصفوف في الشكل ‪ 2.3‬هي للتوضيح)‪.‬‬

‫‪ 2.6.1‬االع ل عن المصفوفة الثنائية‬


‫يتم االعالن عن المصفوفة الثنائية بنفس الطريقرة التري يرتم فيهرا االعرالن عرن‬
‫المصررفوفة االحاديررة وذلررك بكتابررة نرروع المصررفوفة متبوعررا باسررم المصررفوفة يررم عرردد‬
‫العناصر في المصفوفة وهنا يكون عدد العناصر موزعا على قوسين مربعين (ألنها‬
‫ينائيرة)‪ ،‬القروس المربرع االول يحمرل عرردد الصرفوف فري المصرفوفة الثنائيرة والقروس‬
‫المربع الثاني يمثل عدد االعمدة في المصفوفة‪ ،‬وكما يأتي‪:‬‬
‫; ]‪int TestArray [3][5‬‬

‫االعالن اعالل يمثل اعالن عن مصفوفة ينائيرة (عردد االقرواس المربعرة اينران‬
‫وهذا يعني انها ينائية) من نوع االعداد الصحيحة (اي ان جميع عناصرها مرن نروع‬
‫االعررداد الصررحيحة)‪ ،‬تحررت اسررم (‪ )TestArray‬وهرري تحترروي علررى ياليررة صررفوف‬
‫وخمسة اعمدة (اي ان عدد عناصرها الكلري يسراوي حاصرل ضررب عردد الصرفوف‬
‫في عدد االعمدة وسيكون مساوي ‪.)3x5 = 15‬‬
‫م حظة‪ :‬ال يجوز اطالقا تخصيص القوس المربع االول لألعمدة والثاني للصفوف‪،‬‬
‫الن المترررجم دائمررا ينظررر الررى القيمررة الترري فرري القرروس المربررع االول علررى انهررا عرردد‬
‫الصفوف ونفس الشيء للقوس المربع الثراني حيرث يعتبرر القيمرة التري فيره علرى انهرا‬
‫عدد االعمدة‪.‬‬

‫‪ 2.6.2‬الوصول ل ناصر المصفوفة الثنائية‬


‫الية الوصول الى اي عنصر في المصفوفة الثنائية يكون من خالل كتابرة اسرم‬
‫المصفوفة يم القوسين المرربعين‪ ،‬حيرث القروس االول سيشرير الرى رقرم الصرف الرذي‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫يتواجد به العنصر المطلوب‪ ،‬اما القوس المربع الثاني فيشرير الرى رقرم العمرود الرذي‬
‫يوجررد فيرره العنصررر المطلرروب (انظررر الشرركل ‪ ،)2.4‬اذ ان العنصررر المطلرروب هرررو‬
‫العنصر المضلل وهرو موجرود بالصرف الثالرث والعمرود الثراني‪ ،‬لرذلك فران الوصرول‬
‫ألي عنصر من عناصر المصفوفات الثنائية يكون بداللرة رقرم الصرف ورقرم العمرود‬
‫(ودائمررا القرروس المربررع االول يسررتخدم لرررقم الصررف والقرروس المربررع الثرراني لرررقم‬
‫العمود)‪.‬‬

‫شك ‪ :2.4‬تمثي للمصفوفة الثنائية‬

‫عند الوصول ألي عنصر من عناصر المصفوفة الثنائية فيمكنك التعامل معره‬
‫واجراء كافة العمليات التي تتناسب مع نوعه كأي متغير اعتيادي‪ ،‬مثال‬
‫لغرض أسناد القيمة )‪ (56‬لعنصرر مرن عناصرر مصرفوفة ينائيرة (نفررض ان‬
‫العنصر هو في الموقع ‪ )3×5‬فيتم ذلك كما يأتي‪:‬‬
‫; ‪TestArray [3][5] = 56‬‬

‫الح ر عنررد العمررل علررى عناصررر المصررفوفة ال تحترراج لتحديررد النرروع ألنرره تررم‬
‫تحديدل عند االعالن عن المصفوفة‪.‬‬
‫االن لو اردت طباعة قيمة هذا العنصر على الشاشة فسيكون كما يأتي‪:‬‬

‫‪45‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫; ]‪cout << TestArray[3][5‬‬

‫ويمكن مساواته ألي متغير اعتيادي مثل‬


‫; ]‪x = TestArray[3][5‬‬

‫طبعا ستكون قيمة المتغير )‪ (x‬تساوي (‪.)56‬‬

‫‪ 2.6.3‬ابتداء المصفوفة الثنائية‬


‫يقصد باالبتداء هو اسناد قيم ابتدائية للمصفوفة ويكون بعدة طرق‪:‬‬
‫يمكن ان تبتدأ المصفوفة الثنائية برنفس الطريقرة التري ترم فيهرا بردأ المصرفوفة‬ ‫‪‬‬
‫االحاديررة وذلررك مررن خررالل كتابررة اسررم المصررفوفة مررع االقررواس الترري تمثررل االبعرراد‬
‫ومساواتها الى مجموعة من القريم (تتكرون مرن مجموعرة مرن القريم تفصرل برين قيمرة‬
‫واخرى فارزة وتحدد القيم بين قوسين متوسطين مع مالحظة ان عدد القيم يجرب ان‬
‫ال يزيد عن عدد عناصر المصفوفة) وكما يأتي‪:‬‬
‫;} ‪int theArray[5][3] ={1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15‬‬

‫في هذل الحالة فران اول يرالث قريم يرتم اسرنادها الرى المواقرع الرثالث فري الصرف )‪(1‬‬
‫وياني يالث عناصر تسند الى المواقع الثالث في الصف الثاني وهكذا‪.‬‬
‫ويمكرررن ان تكرررون مجررراميع يالييرررة ضرررمن المجموعرررة الرئيسرررة وتسرررندها‬ ‫‪‬‬
‫للمصفوفة وكما يأتي‪:‬‬
‫‪int theArray [5][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}, {13, 14,‬‬
‫; } }‪15‬‬

‫المترجم سيهمل االقواس الداخلية‪ ،‬هي توضع للمسراعدة فري فهرم توزيرع القريم‬
‫بشكل سهل‪.‬‬
‫با مكان اسناد قيم الى عناصر المصفوفة باستخدام لوحة المفاتيح ايناء تنفيذ‬ ‫‪‬‬
‫البرنررامج وذلررك باسررتخدام حلقترري تكرررار متررداخلتين‪ ،‬الحلقررة الخارجيررة تعمررل كعررداد‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫للصفوف (تضع مؤشر على الصرفوف) بينمرا الحلقرة الداخليرة تعمرل كعرداد لألعمردة‬
‫(تضع مؤشر على االعمدة)‪( ،‬بكالم اخر فان حلقتي التكررار سرتعمالن علرى وضرع‬
‫قيم للصفوف بالتتابع اي يتم وضع قيم لعناصر الصرف (‪ )1‬ابترداءا مرن العمرود (‪)1‬‬
‫الى العمود االخير يم ينتقل الى الصف الثاني وهكذا‪.‬‬
‫مثال‪ :‬برنامج لقراءة مصفوفة ينائية بإدخال قيم عناصر من لوحة المفاتيح‪.‬‬
‫>‪#include <iostream‬‬
‫;‪using namespace std‬‬

‫)(‪int main‬‬
‫{‬
‫; ]‪int SomeArray[5][4‬‬
‫)‪for (int i = 0; i<5 ; i++‬‬
‫)‪for (int j =0; j<4 ; j++‬‬

‫; ]‪cin >> SomeArray [i][j‬‬

‫;‪return 0‬‬

‫}‬

‫‪ 2.6.4‬طباعة المصفوفة‬
‫يستخدم نفس البرنامج السابل لغرض طباعة عناصر المصرفوفة علرى ان يرتم‬
‫ابدال امر االدخال بامر االخراج وكما يأتي‪:‬‬
‫• مثال برنامج لقراءة وطباعة عناصر مصفوفة ينائية‪.‬‬
‫>‪#include <iostream‬‬
‫;‪using namespace std‬‬

‫‪47‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫)(‪int main‬‬
‫{‬
‫; ]‪int SomeArray[5][4‬‬
‫)‪for (int i = 0; i<5; i++‬‬
‫)‪for (int j = 0; j<4; j++‬‬

‫; ]‪cin >> SomeArray[i][j‬‬

‫)‪for (int i = 0; i<5; i++‬‬


‫{‬
‫)‪for (int j = 0; j<4; j++‬‬
‫; "‪cout << SomeArray[i][j]<< "\t‬‬
‫; ‪cout << endl‬‬
‫}‬
‫;‪return 0‬‬

‫}‬

‫الح في المثال السرابل اليمكرن اسرتخدام اوامرر االخرراج مرالم يرتم اسرناد قريم‬
‫لعناصر المصفوفة باحدى طرق اسناد القيم المبينة اعالل‪.‬‬
‫مثال‪ :‬برنامج لقراءة مصفوفة اعداد صحيحة احادية حجمها (‪ 100‬عنصرر)‪،‬‬
‫وايجاد العدد االكبر في المصفوفة‪.‬‬
‫>‪#include<iostream‬‬
‫;‪using namespace std‬‬

‫)‪void main (void‬‬


‫; ‪{ int B[100], i, n, Larg‬‬
C++ ‫هياكل البيانات باستخدام‬

cout<<"enter the elements "<<endl;


for(i = 0 ; i <= 99; ++i)
cin>> B[i] ;

Larg = B[0];
for (i=0 ; i <=99 ; ++i)
if (Larg < b[i])
Larg = b[i] ;
cout<<" largest value in the array = "<< Larg ;

.(D (5×5)) ‫ برنامج لطباعة عناصر القطر الرئيس في المصفوفة‬:‫مثال‬


#include < iosream>
#define row 5
#define col 5
using namespace std;

main( ){
int D[row][col] ;
for ( int i=0 ; i< 5 ; i++ )
for ( int j =0 ; j< 5 ; j++ )
cin>>D [i][j] ;
for ( i =0 ; i < 5 ; i++ )
cout << D[i][i] << endl ;
return 0;

49
C++ ‫هياكل البيانات باستخدام‬

‫ يررم برردل عناصررر الصررف‬،(AD (5×4)) ‫ برنررامج لقررراءة المصررفوفة‬:‫مثةةال‬


.‫الثاني مع عناصر الصف الثالث‬
#include <iostream>
using namespace std;

const row = 4 ، col = 5 ;


void readarray ( AD[][] )
{
for ( int i=0 ; i< row ; i++ )
for ( int j =0 ; j<col ; j++ )
cin>>D[i][j] ;
}
void writearray ( AD[][] )
{
for ( int i=0 ; i< row ; i++ ) {
for ( int j =0 ; j< col ; j++ )
cout << D[i][j] << '\t' ;
cout << endl ;
} }
main () {
int AD [row][col];
readarray ( AD );
writearray ( AD );
for ( in i =0 ; i < col ; i++ )
C++ ‫هياكل البيانات باستخدام‬

{ int temp = AD[2][i] ;


AD [2][i] = AD [3][i] ;
AD [3][i] = temp ;
}
writearray ( AD ) ;
return 0;

51
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص الثالث‬
‫الترتيب ‪SORTING‬‬

‫المقدمة‬ ‫‪3.1‬‬
‫الترتيب يشير الرى تنظريم البيانرات وفقرا لصريغة او نظرام معرين‪ .‬خوارزميرة الترتيرب‬
‫تحدد الطريقة لتنظيم البيانات بترتيب معين‪ .‬غالبيرة عمليرات الترتيرب المعروفرة هري‬
‫تعتمد على ترتيب االعداد او المعاجم (الحروف)‪.‬‬
‫ان اهمية عملية الترتيب تأتي من حقيقرة ان بحرث البيانرات يكرون بمسرتوى عرال مرن‬
‫االمثلية ذا كانت البيانات مرتبرة بطريقرة معينرة‪ .‬كرذلك فران الترتيرب يسرتخدم لتمثيرل‬
‫البيانات بصيغ أكثر قابلية للقراءة‪ .‬بعض االمثلة للترتيب في حياتنا هي‪:‬‬
‫دليل الهاتف‪ ..‬حيث ان دليل الهراتف يحفر ارقرام الهواترف لألشرخاص مرتبرة حسرب‬
‫اسمائهم‪ .‬وبهذا فمن الممكن ان نبحث عن االسماء واالرقام بسهولة‪.‬‬
‫القاموس‪ ..‬والقاموس هرو لحفر الكلمرات مرع معانيهرا‪ ،‬مرتبرة بترتيرب ابجردي ولرذلك‬
‫فان البحث عن اي كلمة يكون سهل‪.‬‬
‫خوارزميات الترتيب ربما تتطلب بعض مساحات الخزن االضافية للمقارنة والخزن‬
‫المؤقررت لرربعض العناصررر القليلررة مررن البيانررات‪ .‬هررذل الخوارزميررات الترري ال تتطل رب‬
‫مساحة خزن اضافية‪ ،‬وعملية الترتيرب تحردث فري المكران او علرى سربيل المثرال فري‬
‫المصفوفة نفسها‪ ،‬هذل تسرمى ترتيرب فري المكران )‪ .(in-place sorting‬مثرال علرى‬
‫ذلك ترتيب الفقاعات ‪.Bubble sorting‬‬
‫لكن في خوارزميات ترتيب اخرى‪ ،‬فران البرنرامج يحتراج الرى مسراحة ربمرا تزيرد او‬
‫مساوية الى العناصر التي يراد ترتيبها‪ .‬الترتيب الذي يحتاج الى مسراحة مسراوية او‬
‫أكثررر يسررمى ترتيررب لرريس فرري المكرران ‪ .not-in-place sorting‬مثررال علررى ذلررك‬
‫طريقة الترتيب بالدمج ‪Merge-sort‬‬

‫‪53‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 3.2‬الترتيب المستقر وغير المستقر ‪Stable and not Stable Sorting‬‬

‫ان خوارزمية الترتيب التي لم تغير ترتيب العناصر المتشرابهة حسرب ظهورهرا بعرد‬
‫اجراء ترتيب المحتويات‪ ،‬تسمى خوارزمية الترتيب المستقر كما في الشكل كمرا فري‬
‫الشكل ‪.3.1‬‬

‫شك ‪ :3.1‬توضيح لترتيب بيانات مستقر‪.‬‬

‫امررا ذا كانررت خوارزميررة الترتيررب‪ ،‬بعررد ترتيررب المحتويررات‪ ،‬تغيررر ترتيررب العناص رر‬
‫المتشابهة حسب ظهورها‪ ،‬فهذل تسمى ترتيب غير مستقر كما في الشكل ‪.3.2‬‬

‫شك ‪ :3.2‬توضيح ترتيب بيانات غير مستقر‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫ووارزميةات الترتيةب الم ئمةة وغيةر الم ئمةة ‪Adaptive and non-‬‬ ‫‪3.3‬‬
‫‪Adaptive Sorting Algorithms‬‬

‫خوارزميررة الترتيررب يقررال عنهررا مناسرربة او مالئمررة ذا اسررتفادت مررن ميررزة العناصررر‬
‫المرتبررة اصررال فرري القائمررة المررراد ترتيبهررا‪ .‬عليرره‪ ،‬عنررد الترتيررب ذا كانررت القائمررة‬
‫االصررلية لهررا عناصررر مرتبررة مسرربقا‪ ،‬فرران الخوارزميررة المناسرربة سرروف تأخررذ بنظررر‬
‫االعتبار هذل العناصر وال تعيد ترتيبها يانية‪.‬‬

‫بينمررا الخوارزميررة غيررر المناسرربة هرري الخوارزميررة الترري ال تأخررذ بنظررر االعتبررار‬
‫العناصر التي هي مرتبة مسبقا‪ .‬فهي تحاول اجبار كل عنصرر عرادة ترتيبره للتأكرد‬
‫من عملية الترتيب‪.‬‬
‫‪ 3.4‬مصبلحات مهمة ‪Important Terms‬‬
‫بعض المصطلحات التي صيغت بشكل عام عند مناقشة تقنيات الترتيب‪:‬‬
‫‪ ‬ترتيب تصاعدي ‪Increasing order‬‬
‫متواليررة مررن القرريم يقررال عنهررا مرتبررة تصرراعديا ذا كرران العنصررر الالحررل أكبررر مررن‬
‫العنصر السابل‪ .‬مثال ‪ 1,2,3,4,5‬هي مرتبة تصاعديا‪ ،‬حيث كرل عنصرر هرو أكبرر‬
‫من سابقه‪.‬‬
‫‪ ‬ترتيب تنازلي ‪Decreasing order‬‬
‫متوالية من القيم يقال عنها مرتبة ترتيب تنازلي ذا كان العنصر الالحل أصرغر مرن‬
‫العنصر الحالي‪ .‬كمثال ‪ 9, 8, 7, 6, 4, 1‬هذل بترتيب تنازلي‪ ،‬حيث كل عنصر فري‬
‫المتوالية أصغر من العنصر الذي يسبقه‪.‬‬

‫‪ 3.5‬ترتيب الفقاعة ‪Bubble sort‬‬


‫خوارزميررة الفقاعررة هرري خوارزميررة ترتيررب بسرريطة‪ .‬خوارزميررة الترتيررب هررذل تعتمررد‬
‫المقارنررة بررين كررل زوج مررن العناصررر المتجرراورة ويررتم التبررديل بررين القيمتررين حسررب‬

‫‪55‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫طبيعة الترتيب ان كانتا غير مرتبة (بمعنى ذا كان المطلروب ترتيرب تصراعدي فران‬
‫العنصر االصغر يجب ان يكون في البداية)‪ .‬هذل الخوارزمية غير مناسبة لمجموعة‬
‫بيانات كبيرة‪.‬‬
‫لتوضيح هذل الخوارزمية سنلجأ لمثال بحيث نقتررح مجموعرة مرن القريم غيرر مرتبرة‬
‫ويتم خزنها بمصفوفة (عادة يفضرل لترتيرب ارقرام ان تخرزن هرذل االرقرام بمصرفوفة‬
‫ألنها تسهل العمل) ونحتاج الى ترتيبها ترتيب تصاعدي‬
‫قائمة االرقام هي )‪(20, 3, 17, 19, 25, 35, 9, 42, 16, 27‬‬
‫فسيكون عمل خوارزمية الفقاعة كما يلي‪:‬‬
‫عمليررة الترتيررب سررتتم بعرردة مراحررل‪ ،‬عرردد هررذل المراحررل غيررر محرردد ويختلررف حسررب‬
‫طبيعرررة القررريم المرررراد ترتيبهرررا‪ ،‬الخوارزميرررة كمرررا سررربل وقلنرررا سرررتقارن كرررل عرررددين‬
‫متجاورين وتبدل بينهما ذا كان التبديل ضروري‪ ،‬وتستمر بهذل العملية لحين اكمرال‬
‫جميع القيم في المصفوفة عندها تكون المرحلة االولى قد انتهت وتبدأ مرحلة جديردة‪.‬‬
‫تنتهي خوارزمية الترتيب عندما نصل الى مرحلة ال يوجد فيها تبديل بين قيمتين‪.‬‬
‫االن لننرراقش المرحلررة االولررى لهررذل القرريم ونسررتعين بالشرركل ‪ ,3.3‬بدايررة سرريتم مقارنررة‬
‫العررددين )‪ (20, 3‬ولمررا كانررت ‪ 3‬أصررغر مررن ‪ 20‬لررذلك تررتم عمليررة التبررديل لتكررون ‪3‬‬
‫بالموقع االول و ‪ 20‬بالموقع الثاني‪ .‬بعدها تتم مقارنة العرددين )‪ (20, 17‬وحيرث ان‬
‫‪ 17‬أصغر من ‪ 20‬تتم عملية التبديل‪.‬‬
‫م حظة‪ :‬عملية المقارنة تبدأ بالعنصرر الرذي فري الموقرع )‪ (0‬مرن المصرفوفة ليقرارن‬
‫مررع العنصررر الررذي فرري الموقررع )‪ .(1‬يررم ينتقررل المؤشررر الررى العنصررر فرري الموقررع )‪(1‬‬
‫ليقارن مع العنصر في الموقع )‪ .. (2‬وهكذا‪.‬‬
‫االن تقررارن )‪ (20, 19‬وحيررث ان ‪ 19‬أصررغر مررن ‪ 20‬فكررل واحرردة تبرردل الررى موقررع‬
‫االخرى‪.‬‬
‫)‪ (20, 25‬هنا ‪ 20‬اصغر من ‪ 25‬لرذلك ال يوجرد تبرديل‪ .‬وكرذلك )‪ (25, 35‬ال يوجرد‬
‫تبديل‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫العددين المتجاورين )‪ (35, 9‬يتم بينهم التبديل الن ‪ 9‬أصرغر مرن ‪ (35, 42) ,35‬ال‬
‫يوجد بينهم تبديل‪.‬‬
‫)‪ (42, 16‬تجرى بينهم التبديل الن ‪ 16‬اصغر من ‪.42‬‬
‫واخر التبديالت في المرحلة االولى )‪ (42, 27‬يتم بينهم التبديل الن ‪ 27‬أصرغر مرن‬
‫‪.42‬‬
‫ونظرررا للوصررول الررى العنصررر االخيررر فرري المصررفوفة فرران هررذل المرحلررة (المرحلررة‬
‫االولى) قد انتهت وسنبدأ مرحلة يانية تتم فيهرا المقارنرة مرن اول عنصرر ونتبرع ذات‬
‫الخطرروات اعررالل‪ .‬تسررتمر هررذل العمليررات لحررين ان نصررل مرحلررة ال يوجررد فيهررا تبررديل‬
‫بذلك تكون جميع العناصر قد تم ترتيبها‪ .‬الشكل ‪ 3.3‬يوضح الخطروات الكاملرة لهرذل‬
‫الخوارزمية‪.‬‬

‫‪ ‬دالة الترتيب باستخدام خوارزمية الفقاعة‪.‬‬

‫) ] [‪void bubbleSort (int AB‬‬

‫{‬

‫)‪for (int i = 0 ; i <= (array_size) ; i++‬‬

‫{‬

‫)‪for (int j = 0 ; j < (array_size) ; j++‬‬

‫{‬

‫)]‪if (AB[ j ] > AB[ j+1‬‬

‫{‬

‫;] ‪int temp = AB[ j‬‬

‫;] ‪AB[ j ] = AB[ j+1‬‬

‫‪57‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪AB[ j+1 ] = temp‬‬

‫}}}}‬

‫شك ‪ :3.3‬الالبوات الكاملة لترتيب االعدا وفقا لالوارزمية الفقاعة‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 3.6‬ترتيب الحشر ‪Insertion Sort‬‬


‫هذل الخوارزمية هي من نوع المقارنة في المكان اي ال تحتاج مساحة خزن اضرافية‬
‫كبيرة‪ .‬هنا جزء من القائمة يتم المحافظة عليه دائما مرتب‪ .‬مثال‪ ،‬الجزء االدنرى مرن‬
‫المصرفوفة يحراف عليره مرتررب‪ .‬العنصرر )‪ (A‬والرذي نرغررب ان نحشررل فري القائمررة‬
‫الجزئية المرتبة‪ ،‬يحتاج ان تجد المكان المالئم له ويتم حشرل‪ .‬من هذا جراءت تسرمية‬
‫الخوارزمية بخوارزمية ترتيب الحشر‪.‬‬
‫يتم بحث المصفوفة بشركل تسلسرلي والعناصرر غيرر المرتبرة يرتم نقلهرا وحشررها فري‬
‫قائمة جزئية مرتبة (في نفس المصفوفة)‪ .‬هذل الخوارزميرة ليسرت مناسربة لمجموعرة‬
‫البيانات الكبيرة حيث ان معدل درجة التعقيد لها في اسوأ حالة هري ))‪ ,(O(n2‬حيرث‬
‫ان )‪ (n‬تمثل عدد العناصر في القائمة‪.‬‬
‫الخطوة االولى في عملية الترتيب بالحشر تعتمد ببساطة على مقارنة اول قيمتين في‬
‫المصفوفة حيث ستكون القيم الصغيرة في البداية‪ ،‬لذلك ذا كانت القيمة االولرى أكبرر‬
‫من القيمة الثانية في المصفوفة عندها تتم عملية التبديل (ترتيب تصاعدي)‪.‬‬
‫هررذل الخطرروة هرري نررواة تكرروين القائمررة الجزئيررة المرتبررة وهرري عررادة تكررون فرري بدايررة‬
‫المصفوفة‪ ،‬وتكون القائمة الجزئية المرتبة االن تحتوي على عنصر واحد مرتب‪.‬‬
‫الخطرروة الثانيررة هرري مقارنررة القيمتررين الالترري بعررد القائمررة الجزئيررة المرتبررة‪ ،‬ذا كانررت‬
‫القيميتين غير مرتبة فتتم عملية التبديل‪ ،‬مرع مالحظرة ان هرذل القيمرة التري ترم ابردالها‬
‫ستضاف الى القائمة الجزئية المرتبة‪ ،‬ولكي نحاف على القائمة الجزئية مرتبة‪ ،‬عليه‬
‫فان القيمة الجديدة تقارن مع جميع عناصر القائمة الجزئية لحين ان تكون في الموقع‬
‫المناسب لها‪.‬‬
‫ستالح ان القائمة الجزئية تكبر حجما بمرور الوقت وازدياد عدد المقارنات‪.‬‬
‫تستمر هذل العملية لحين ترتيب كامل عناصر القائمة‪.‬‬

‫‪59‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 3.6.1‬وبوات ووارزمية الحشر‬


‫ان الخطوات الالزمة لعمل هذل الخوارزمية تتلخص بما يلي‪:‬‬
‫ذا كان العنصر هو اول عنصر‪ ،‬فهو سيكون مرتب ويعتبر العنصرر االول‬ ‫‪.1‬‬
‫في القائمة الجزئية (برمجيا يتم اعادة ‪.)1‬‬
‫‪ .2‬استدعاء العنصر التالي في المصفوفة لغررض اضرافته الرى القائمرة الجزئيرة‬
‫(المرور على كل عناصر المصفوفة بالتوالي)‪.‬‬
‫‪ .3‬يتم مقارنة هذا العنصر مع كامل عناصر القائمة الجزئية لتحديرد موقعره فري‬
‫القائمة الجزئية‪.‬‬
‫‪ .4‬يتم تزحيف كرل العناصرر فري القائمرة الجزئيرة المرتبرة والتري هري أكبرر مرن‬
‫القيمة المراد ترتيبها الى اليمين مرتبة واحدة (هنا الترتيب تصاعدي)‪.‬‬
‫‪ .5‬حشر القيمة التي حصلنا عليها في الخطوة ‪ B‬في الموقع المناسب لها‪.‬‬
‫‪ .6‬طالما لم نصل الى نهاية المصفوفة‪ ،‬يتم اعادة الخطروات اعرالل مرن الخطروة‬
‫‪.2‬‬

‫‪ 3.6.2‬كيف ت م هذ الالوارزمية‬
‫لكي نفهم طريقة الحشر بشكل جيد سنستعين بالشكل ‪ ,3.4‬وهو بداية يمثرل مصرفوفة‬
‫مررن القرريم الموزعررة بشرركل عشرروائي‪ ،‬والمطلرروب ان يررتم ترتيررب هررذل القرريم ترتيررب‬
‫تصرراعدي او تزايرردي‪ .‬هنررا فرري اي موقررع )‪ (i‬مررن المصررفوفة (الحر ان المتغيررر )‪,(i‬‬
‫الررذي يظهررر بجانررب المصررفوفة فرري الشرركل )‪ (3.4‬يمثررل موقررع العنصررر الررذي سرريتم‬
‫مقارنته واضافته الى القائمة الجزئية المرتبة‪ .‬كذلك فان القائمة الجزئية المرتبرة هري‬
‫تبدأ بالنمو من بدايرة المصرفوفة كمرا فري الشركل ‪ .)3.4‬مرثال فري الموقرع صرفر هنرا‬
‫القيمة ‪ 3‬وهري اول عنصرر فري القائمرة الجزئيرة‪ .‬عنردما ننتقرل الرى الموقرع ‪(i=1) 1‬‬
‫حيث سيكون دور العنصر في الموقع ‪ 1‬لالضافة الى القائمة الجزئية‪ ،‬هنا الموقرع ‪1‬‬
‫في المصفوفة هو ذا قيمة تساوي ‪ 1‬وتتم مقارنتها مع عناصر القائمة الجزئية يجاد‬
‫المكرران المناسررب لهررا فرري القائمررة الجزئيررة‪ ،‬وحيررث ان القائمررة الجزئيررة تحترروي علررى‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫القيمة ‪ 3‬فقط‪ ،‬ونظرا الن القيمة ‪ 1‬أصغر من ‪ 3‬لذا تتم عملية تزحيرف القيمرة ‪ 3‬الرى‬
‫اليمين بمقدار موقع واحرد (المقصرود تزحيفره الرى الموقرع المجراور فري المصرفوفة)‪.‬‬
‫وتصبح القائمة الجزئية المرتبة تحتوي على القيمتين )‪.(1, 3‬‬
‫االن جاء دور )‪ (i=2‬وفي هذا الموقع القيمة ‪ ,4‬ونظررا الرى ان القيمرة ‪ 4‬هري ضرمن‬
‫الترتيب لذلك ال تنفذ عملية التزحيف وتضاف هذل القيمرة الرى نهايرة القائمرة الجزئيرة‬
‫المرتبة‪.‬‬
‫عندما تكون )‪ (i=3‬فان القيمة في هذا الموقع هي ‪ 1‬لذلك ستقارن مع القيم التي فري‬
‫ذيرل المصررفوفة الجزئيررة المرتبررة ابتررداءا وكررل قيمررة اكبررر منهررا تزحررف لليمررين موقررع‬
‫واحد‪ ,‬ستقارن مع القيمة ‪ 4‬ونظرا الن ‪ 1‬اصغر من ‪ 4‬لذا تتم عمليرة تزحيرف القيمرة‬
‫‪ 4‬الررى الموقررع االيم رن المجرراور لموقعهررا الحررالي وهررو الموقررع (‪( )3‬الح ر هنررا ان‬
‫موقعها الحالي (‪ )2‬اصبح خاليا)‪ ,‬وكما سبل واشرنا فان هذل القيمة تقارن مع جميرع‬
‫قرريم المصررفوفة الجزئيررة لحررين ان يررتم وضرعها او حشرررها فرري موقعهررا المناسررب‪ ,‬لررذا‬
‫ستقارن مع القيمة ‪ 3‬التري هري فري الموقرع ‪ ,1‬وايضرا تجررى عمليرة التزحيرف حيرث‬
‫تزحف القيمة ‪ 3‬الى الموقع الخالي على يمينها (‪ )2‬ويصبح موقعهرا (‪ )1‬هرو الفرار‬
‫او الخررالي‪ ,‬وعنررد مقارن رة القيمررة ‪ 1‬مررع القيمررة ‪ 1‬فسررتكون القيمترران متسرراويتان لررذلك‬
‫توضع القيمة ‪ 1‬في الموقع الخالي (‪.)1‬‬
‫هذل العملية تستمر لحين الوصول الى نهاية القائمة وبالتالي سنحص على قائمرة مرن‬
‫القيم مرتبة ترتيب تصاعدي‪.‬‬

‫‪61‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :3.4‬شك توضيحي لتنفيذ ووارزمية الحشر‪.‬‬

‫‪ ‬الدالة البرمجية لخوارزمية الحشر هي‬


‫) ] [‪void insertionSort(int AB‬‬

‫{‬

‫)‪for (int i=1; i ‹ array_size ; i++‬‬

‫{‬

‫; ] ‪int index = AB[ i‬‬ ‫; ‪int j = i‬‬

‫)‪while (j > 0 && AB[ j-1 ] > index‬‬

‫{‬

‫;] ‪AB[ j ] = AB[ j-1‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪j--‬‬

‫}‬

‫;‪AB[ j ] = index‬‬

‫}}‬

‫‪ 3.7‬ترتيب االوتيار ‪Selection Sort‬‬


‫ترتيب االختيار هري خوارزميرة بسريطة‪ .‬هرذل الخوارزميرة تعتمرد علرى المقارنرة فري‬
‫المكران‪ ،‬حيررث ان قائمرة القرريم (المصرفوفة) يررتم تقسريمها الررى جرزئين‪ ،‬الجررزء االيسررر‬
‫(النهاية اليسرى مرن المصرفوفة) وهرو جرزء القريم المرتبرة‪ ،‬والجرزء االيمرن (النهايرة‬
‫اليمنى من المصفوفة) وهو جزء القريم غيرر المرتبرة‪ .‬ابترداء فران جرزء القريم المرتبرة‬
‫سيكون فار ‪ ،‬بينما جزء القيم غير المرتبة يمثل جميع عناصر القائمة‪.‬‬
‫يتم بحث القائمة غير المرتبة يجاد أصغر قيمة (في حالة الترتيب التصاعدي) ويتم‬
‫ابدالها مع العنصرر فري اقصرى اليسرار مرن القائمرة غيرر المرتبرة‪ ،‬وبهرذا سريكون هرذا‬
‫العنصر هو واحد من عناصر القائمة المرتبة‪ .‬هذل العملية تستمر بنقرل أحرد عناصرر‬
‫القائمة غير المرتبة الرى القائمرة المرتبرة (بمعنرى ان القائمرة المرتبرة سريزداد حجمهرا‬
‫مقابل تقلص حجم القائمة غير المرتبة)‪.‬‬
‫واقعا ان العملية ببساطة تتم باختيار اول عنصر مرن القائمرة غيرر المرتبرة (العنصرر‬
‫في اقصى يسار القائمة غير المرتبة) ومقارنته بجميع عناصر القائمة غير المرتبرة‪،‬‬
‫ذا وجدنا عنصر أصغر منه يتم ابداله ويبقى معنا العنصر االصغر‪ ،‬فاذا وصلنا الى‬
‫نهايررة القائمررة غيررر المرتبررة تررتم اضررافة هررذا العنصررر (الررذي كرران العنصررر االول فري‬
‫القائمررة غيررر المرتبررة والررذي قيمترره أصررغر مررن قرريم برراقي العناصررر فرري القائمررة غي رر‬
‫المرتبة) الى نهاية القائمة المرتبة (اي في النهاية اليمنى للقائمة المرتبة)‪.‬‬

‫‪63‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫وبوات ووارزمية ترتيب االوتيار‬ ‫‪3.7.1‬‬


‫تحجرز القيمررة الترري فرري اول موقررع مررن مواقررع المصررفوفة (الموقررع صررفر فرري‬ ‫‪.A‬‬
‫بدايرررة العمرررل) فررري متغيرررر لنفررررض اسرررمه )‪ ،(Min‬هرررذا يعنررري ان المتغيرررر‬
‫)‪ (Min‬سيحف القيمة التي في الموقع صفر مرن المصرفوفة علرى فررض ان‬
‫هذل القيمة هي أصغر قيمة في المصفوفة او القائمة المرتبة‪.‬‬
‫يقارن هذا العنصر مع جميع العناصر االخرى في المصرفوفة‪ .‬كلمرا وجردت‬ ‫‪.B‬‬
‫قيمة أصغر من )‪ (Min‬تتم عملية التبديل مع القيمة التري فري )‪((Min‬نؤكرد‬
‫على فرض الترتيب التصاعدي)‪ .‬ليكون في نهاية بحث المصرفوفة العنصرر‬
‫االول في القائمة المرتبة‬
‫الحقرررا يرررتم اختيرررار العنصرررر الالحرررل ليحجرررز فررري المتغيرررر )‪( (Min‬يعتبرررر‬ ‫‪.C‬‬
‫العنصر االول في القائمة غير المرتبة)‪.‬‬
‫يتم بحث جميع العناصرر الباقيرة فري المصرفوفة (غيرر المرتبرة) وتقرارن مرع‬ ‫‪.D‬‬
‫)‪.(Min‬‬
‫كلمررا وجرردت قيمررة أصررغر مررن )‪ (Min‬تررتم عمليررة التبررديل مررع القيمررة الترري‬ ‫‪.E‬‬
‫في )‪.(Min‬‬
‫عند الوصول الى نهاية القائمة غير المرتبة يتم اضافة العنصر )‪ (Min‬الى‬ ‫‪.F‬‬
‫ذيل القائمة المرتبة (اي اقصى يمين القائمة المرتبة)‪.‬‬
‫ذا لرم يرتم الوصرول الرى العنصرر قبرل االخيرر فري المصرفوفة (القائمرة غيرر‬ ‫‪.G‬‬
‫المرتبة) ومعالجتة (باعتبرارل االصرغر ويقرارن مرع العنصرر االخيرر)‪ ،‬تعراد‬
‫هررذل العمليررة للخطرروات السررابقة مررن الخطرروة ‪ ,C‬لحررين ان يررتم ترتيررب كامررل‬
‫المصفوفة‪.‬‬

‫‪ 3.7.2‬كيف ت م الالوارزمية‬
‫في هذل الخوارزمية فان عملية الترتيرب ترتم بعردد مرن المراحرل تصرل الرى )‪(n – 1‬‬
‫حيث ان )‪ (n‬تمثل عدد العناصر في المصفوفة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫سنوضررح عمررل هررذل الخوارزميررة باسررتخدام الشرركل ‪ ,3.5‬فرري المرحلررة االولررى سرريتم‬
‫اختيار العنصر االول ويفرض علرى انره االصرغر ولرذلك يوضرع بمتغيرر لنقرل اسرمه‬
‫)‪ ،(Min‬هذا العنصر الذي قيمته ‪ 20‬ستتم مقارنته مع جميرع العناصرر االخررى فري‬
‫المصفوفة‪ ،‬واول عنصر هو العنصر الذي قيمته ‪ ,12‬ولما كانت ‪ 12‬أصغر من ‪20‬‬
‫لذلك ستتم عملية التبديل ويوضع كل عنصر بموقع االخر (بمعنى ان التبديل يتم بين‬
‫موقع المتغير )‪( (Min‬وهو الموقع صفر) وموقع العنصر الرذي قيمتره أصرغر وهرو‬
‫الموقررع االول‪ .‬بهررذا‪ ،‬ان المتغيررر ‪ Min‬سرريحمل القيمررة ‪ 12‬برردل مررن ‪ 20‬بعررد اجررراء‬
‫التبديل)‪ .‬تستمر عملية المقارنة وسيكون العنصرر االخرر الرذي يقرارن مرع ‪Min‬هرو‬
‫‪ ,10‬ولما كانرت ‪ 10‬أصرغر مرن ‪ 12‬لرذا ترتم عمليرة التبرديل بحيرث كرل عنصرر يحترل‬
‫موقع العنصر االخر‪ ،‬والمتغير ‪ Min‬ستكون قيمته هي ‪.10‬‬
‫تستمر عملية المقارنة وهذل المرة تكون المقارنة مرع القيمرة ‪ 15‬وحيرث ان ‪ 15‬أكبرر‬
‫من ‪ 10‬تبقى كل قيمة على وضعها وال تجرى عملية تبديل‪ .‬واخيرا جاء دور القيمرة‬
‫االخيرة والتي قيمتها ‪ 2‬وتقارن مرع ‪ ,Min‬ونظررا الن ‪ 2‬أصرغر مرن ‪ 10‬ترتم عمليرة‬
‫التبديل ولتكن كل قيمة بموقرع االخررى كمرا فري الشركل ‪ ,3.5‬ويصربح المتغيرر ‪Min‬‬
‫يحمل القيمة ‪.2‬‬
‫بهذا انتهت المرحلة االولى‪ ،‬وحان دور المرحلرة الثانيرة والتري فري هرذل الحالرة سريتم‬
‫وضع القيمة في الموقع الالحل وهو موقع ‪ 1‬في المصفوفة في المتغير ‪ ,Min‬وهري‬
‫القيمرررة ‪ .20‬وكمرررا فررري المرحلرررة االولرررى‪ ،‬تعررراد نفرررس الخطررروات لعمليرررات المقارنرررة‬
‫والتبديل‪ ،‬وهكذا لكل المراحل الالحقة وكما واضح في الشكل ‪.3.5‬‬

‫‪65‬‬
C++ ‫هياكل البيانات باستخدام‬

.‫ مالبط توضيحي لتنفيذ ووارزمية الترتيب باالوتيار‬:3.5 ‫شك‬

‫ الدالة البرمجية لخوارزمية االختيار هي‬


void selectionSort (int AB[ ] ) {

for (int i = 0 ; i ‹ array_size – 1 ; i++)

int min = i;

for (int j = i+1 ; j ‹ array_size ; j++)

if (AB [ j ] < AB [min])

min = j ;

int temp = AB[ i ];

AB [ i ] = AB [min];

AB [min] = temp;

}}
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪Merge Sort‬‬ ‫‪ 3.8‬الترتيب بالدم‬

‫ترتيب الدمج هري تقنيرة تعتمرد علرى تقنيرة (‪ ،)divide and conquer‬وهري واحردة‬
‫من الخوارزميات المعتبرة‪.‬‬

‫مع اسوأ تعقيد وقت فان ))‪.(complexity being Ο (n log n‬‬

‫ترتيب الدمج يقسم المصفوفة الى نصفين متساويين وبعدها تتم عملية دمجهم بطريقة‬
‫مرتبة‪.‬‬
‫الخوارزمية ببساطة تقسم المصفوفة بشكل متكرر الرى نصرفين‪ ،‬يرم تقسرم النراتج الرى‬
‫نصفين وهكذا لحين الحصول على عناصرر صرغيرة ال يمكرن تقسريمها أكثرر‪ .‬عمليرة‬
‫التقسيم هذل تحاف على ترتيب هذل العناصر في المصفوفة االصلية‪.‬‬
‫بعررد عمليررة التقسرريم تررتم عمليررة الرردمج بررنفس طريقررة التقسرريم اي ان كررل عنصرررين‬
‫متجاورين ناتجة من التقسيم تدمج يانية لكن وفل شرط وهو ان تكون هرذل العناصرر‬
‫مرتبررة‪ ،‬بمعنررى ان تررتم مقارنررة قرريم هررذين العنصرررين وترتررب ترتيررب تصرراعدي او‬
‫تنازلي (اجراء التبديل بينهم ذا استوجب) ومن يم تدمج‪.‬‬
‫في عملية الدمج الثانية تدمج كل قائمتين متجاورتين مع بعضهما (هنا كرل قائمرة لهرا‬
‫عنصرررين)‪ ،‬مررع االخررذ بنظررر االعتبررار بترتيررب قرريمهم‪ .‬وهكررذا تسررتمر العمليررة لحررين‬
‫اعادة الدمج لكامل القائمة‪.‬‬

‫وبوات ووارزمية الترتيب بالدم‬ ‫‪3.8.1‬‬


‫ذا كانت القائمة تحتوي على عنصر واحد‪ ،‬فان القائمة مرتبرة ويرتم اعادتهرا‬ ‫‪.A‬‬
‫كقائمة مرتبة‪.‬‬
‫تقسيم القائمة بشكل متكرر الى نصفين متساويين لحين الوصول الى حالة ال‬ ‫‪.B‬‬
‫يمكن معها اجراء تقسيم اضافي‪.‬‬
‫دمج القوائم الصغيرة بقوائم جديدة بحيث تكون عناصرها مرتبة‪.‬‬ ‫‪.C‬‬

‫‪67‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 3.8.2‬كيف ت م الالوارزمية‬
‫في الشكل ‪ 3.6‬مصفوفة من االعداد غير المرتبة‪ .‬لكي ننفذ عليها طريقرة الردمج نبردأ‬
‫بتقسيم المصفوفة والتي تتكون من ‪ 8‬عناصر الى نصرفين‪ ،‬بحيرث يكرون كرل نصرف‬
‫يحترروي علررى ‪ 4‬عناصررر كمررا واضررح فرري المرحلررة الثانيررة مررن الشرركل ‪ .3.6‬وفرري‬
‫المرحلة الثالثة ايضا يتم التقسيم لنحصرل علرى أربرع مجراميع كرل منهرا يحتروي علرى‬
‫عنصررين فقرط‪ .‬وفرري المرحلرة الرابعررة نقسرم جميررع المجراميع وسنحصررل علرى يمرران‬
‫مجرراميع كررل منهررا يحترروي عنصررر واحررد‪ ،‬ونظرررا الررى ان هررذل المجرراميع غيررر قابلررة‬
‫لالنقسام اكثر لذلك يتوقف التقسيم‪.‬‬
‫االن حرران دور الرردمج وبررنفس طريقررة التقسرريم وبشرركل عكسرري تررتم عمليررة دمررج كررل‬
‫عنصرين متجاورين مع ضرورة ان تكون العناصرر فري مرحلرة الردمج مرتبرة (هنرا‬
‫ترتيب تصاعدي)‪.‬‬
‫الح سيتم دمج )‪ (56, 29‬ونظرا الن هذين العنصرين غير مرتبة لذلك ترتم عمليرة‬
‫التبديل يم الدمج وسنحصل على )‪ ،(29, 56‬نفس الشيء للعناصرر التري بعردها وهرم‬
‫)‪ (35, 42‬يتم دمجهم دون الحاجة للتبديل نظرا ألنها مرتبة‪ .‬العنصرين االخرين هم‬
‫)‪ (15, 41‬تدمج دون تبديل ألنها مرتبة‪ .‬العناصر )‪ (75, 21‬يتم ترتيبهم يرم دمجهرم‬
‫لتكون هذل المجموعة )‪ .(21, 75‬بهذا تكون المرحلة الرابعة قد انجزت‪.‬‬
‫في المرحلة الخامسة يرتم دمرج المجراميع الناتجرة والتري عرددها أربرع مجراميع لنكرون‬
‫منهم مجموعتين‪ ،‬في هذل المرحلة ايضا من المفروض ان يتم التبرديل برين العناصرر‬
‫االربع ذا استوجب ذلك‪ .‬واخيرا في المرحلة السادسة يتم دمج المجموعتين لنحصل‬
‫على قائمة مرتبة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :3.6‬مالبط توضيحي لبريقة تنفيذ ووارزمية الدم ‪.‬‬

‫م حظةةة ‪ :‬عنرردما يكررون عرردد عناصررر المصررفوفة لرريس زوجرري وبالتررالي فرران عمليررة‬
‫التقسيم ال تتم بتقسيم المصفوفة الى قسمين متساويين كمرا فري الشركل ‪ ,3.6‬لرذلك فري‬
‫هذل الحالة سيتم التقسيم الى قسمين غير متساوين وتنجز كل االعمال بشكل اعتيادي‬
‫كما سبل ووضحنا‪ ،‬الشكل ‪ 3.7‬يوضح هذل الحالة‪.‬‬

‫‪69‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :3.7‬مالبط توضيحي لتنفيذ ووارزمية الدم عندما يكول عد عناصر المصفوفة فر ي‪.‬‬

‫‪ ‬الدالة البرمجية لخوارزمية الترتيب بالدمج‬


‫دمج اثنان من المصفوفات الثانوية للمصفوفة ][‪// arr‬‬

‫المصفوفة الثانوية االولى هي ]‪// arr[l..m‬‬

‫المصفوفة الثانوية الثانية هي ]‪// arr[m+1..r‬‬

‫)‪void merge(int arr[], int l, int m, int r‬‬

‫{‬

‫;‪int i, j, k‬‬

‫; ‪int n1 = m‬‬

‫;‪int n2 = r - m‬‬

‫‪ */‬خلق مصفوفات مؤقتة *‪/‬‬

‫;]‪int L[n1], R[n2‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪*/‬نسخ البيانات الى المصفوفات المؤقتة ] [‪/* L[ ] and R‬‬

‫)‪for (i = 0; i < n1; i++‬‬

‫;]‪L[i] = arr[l + i‬‬

‫)‪for (j = 0; j < n2; j++‬‬

‫;]‪R[j] = arr[m + 1+ j‬‬

‫‪*/‬دمج المصفوفات المؤقتة في المصفوفة ]‪/* arr[l..r‬‬

‫;‪i = 0‬‬ ‫ابتداء الدليل (الفهرس) الى المصفوفة الثانوية االولى ‪//‬‬

‫;‪j = 0‬‬ ‫ابتداء الدليل (الفهرس) الى المصفوفة الثانوية الثانية ‪//‬‬

‫;‪k = l‬‬ ‫ابتداء الدليل (الفهرس) الى مصفوفة الدمج الثانوية ‪//‬‬

‫)‪while (i < n1 && j < n2‬‬

‫{‬

‫)]‪if (L[i] <= R[j‬‬

‫{‬

‫;]‪arr[k] = L[i‬‬

‫;‪i++‬‬

‫}‬

‫‪else‬‬

‫{‬

‫;]‪arr[k] = R[j‬‬

‫;‪j++‬‬

‫}‬

‫‪71‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪k++‬‬

‫}‬

‫‪ */‬استنساخ العناصر المتبقية للمصفوفة ][‪ ,L‬اذا كان هناك عناصر *‪/‬‬

‫)‪while (i < n1‬‬

‫{‬

‫;]‪arr[k] = L[i‬‬
‫;‪i++‬‬

‫;‪k++‬‬

‫}‬

‫استنساخ العناصر المتبقية للمصفوفة][‪ ,R‬اذا كان هناك عناصر*‪/‬‬

‫‪are any */‬‬

‫)‪while (j < n2‬‬

‫{‬

‫;]‪arr[k] = R[j‬‬

‫;‪j++‬‬

‫;‪k++‬‬

‫}‬

‫}‬

‫*‪ l /‬هو الفهرس االيسر‪ r ,‬هو الفهرس االيمن للمصفوفة الثانوية المطلوب ترتيبها ‪*/ arr‬‬

‫)‪void mergeSort(int arr[], int l, int r‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫{‬

‫)‪if (l < r‬‬

‫{‬

‫‪// Same as (l+r)/2, but avoids overflow for‬‬

‫‪// large l and h‬‬

‫;‪int m = l+(r-l)/2‬‬

‫ترتيب النصف االول والثاني ‪//‬‬

‫;)‪mergeSort(arr, l, m‬‬

‫;)‪mergeSort(arr, m+1, r‬‬

‫;)‪merge(arr, l, m, r‬‬

‫}‬

‫}‬

‫الترتيب ببريقة ش ‪Shell Sort‬‬ ‫‪3.9‬‬


‫ترتيب شريل ترم تسرميتها باسرم مكتشرفها‪ .‬فبردال مرن مقارنرة العناصرر المتجراورة مثرل‬
‫خوارزمية الفقاعة‪ ,‬فان ترتيب شيل يكرر عملية المقارنة للعناصر التي يفصل بينهرا‬
‫مسافة معينة (لنفرض ‪ d‬تمثل المسافة)‪ .‬ان قيمة ‪ d‬االبتدائية تبدا بمرا يسراوي نصرف‬
‫حجررم المصررفوفة المدخلررة وفرري كررل دورة يررتم تنصرريف هررذل المسررافة‪ .‬العناصررر تررتم‬
‫مقارنتها وتبدل عند الحاجة‪ .‬العالقة التالية يتم استخدامها‬
‫‪d = (N + 1) / 2‬‬

‫ان قيمة ‪ d‬دائما هي عدد صحيح‪ ,‬وان ‪ N‬تمثل عدد عناصر المصفوفة‪.‬‬

‫‪73‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫هذل الخوارزمية كفروءة لمجراميع البيانرات متوسرطة الحجرم وهري فري اسروأ الحراالت‬
‫تكون درجة التعقيد لها ))‪ (complexity is O(n‬حيث ان ‪ n‬تمثل عدد العناصر‪.‬‬

‫وبوات ووارزمية ش‬ ‫‪3.9.1‬‬


‫احسب قيمة )‪ ،(d‬وفقا للعالقة ‪.d = (N-1) / 2‬‬ ‫‪.A‬‬
‫قسم القائمة الى مجاميع يانوية صغيرة بمديات تساوي ‪.d‬‬ ‫‪.B‬‬
‫رتب هذل المجاميع الثانوية باستخدام خوارزمية الحشر‪.‬‬ ‫‪.C‬‬
‫كرر هذل االعمال لحين ان يتم ترتيب القائمة‪.‬‬ ‫‪.D‬‬

‫‪ 3.9.2‬كيفية عم الالوارزمية‬
‫عملية الترتيب بطريقة شل تعتمد اساسا على حساب قيمة )‪ (d‬والتي يتم حسابها فري‬
‫كل مرحلة‪ ،‬ان هذل المسافة سيتم االعتماد عليها لتحديرد العناصرر التري يرتم مقارنتهرا‬
‫مررع بعررض‪ .‬لتبسرريط الموضرروع دعنررا نرررى الشرركل ‪ 3.8‬والررذي يمثررل مصررفوفة مررن ‪6‬‬
‫عناصر موزعرة بشركل عشروائي‪ .‬بدايرة يرتم حسراب قيمرة المسرافة )‪ .(d‬فري المرحلرة‬
‫االولى تحسب المسافة وفقا للعالقة ادنال‪ ،‬اما في المراحل الالحقة فيتم تنصريف قيمرة‬
‫المسررافة فرري كررل مرحلررة (كررل مرحلررة لهررا قيمررة مسررافة تسرراوي نصررف قيمررة مسررافة‬
‫المرحلة السابقة)‪.‬‬
‫‪d = (N + 1 ) / 2‬‬

‫‪d = (6 + 1 ) / 2 = 3‬‬

‫هذا يعني ان العنصر االول سيتم مقارنته مع العنصر الرابع‪ ،‬والعنصر الثاني يقارن‬
‫مع العنصر الخامس‪ ،‬والعنصر الثالث يقارن مع العنصر السادس‪.‬‬
‫عند مقارنة العنصر االول مع العنصر الرابرع )‪ (86, 84‬نالحر ان ‪ 84‬أصرغر مرن‬
‫‪ 86‬لررذلك يررتم التبررديل بحيررث كررل عنصررر يبرردل الررى موقررع العنصررر االخررر (ترتيررب‬
‫تصاعدي)‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مقارنة العنصر الثاني مع العنصر الخامس )‪ (94, 69‬ايضا ترتم عمليرة تبرديل وذلرك‬
‫الن ‪ 69‬أصغر من ‪.94‬‬
‫الحالررة االخرررى مقارنررة العنصررر الثالررث مررع العنصررر السررادس )‪ (76, 91‬هنررا كررل‬
‫عنصر يبقى بمكانه دون تبديل الن العنصرين مرتبين‪.‬‬

‫شك ‪ :3.8‬مالبط يوضح كيفية تنفيذ ووارزمية ش ‪.‬‬

‫‪ ‬الدالة البرمجية لخوارزمية الترتيب بطريقة شل‬

‫)‪for (increment = size/2;increment > 0; increment /= 2‬‬


‫{‬
‫)‪for(i = increment; i<size; i++‬‬
‫{‬
‫;]‪temp = array[i‬‬
‫)‪for(j = i; j >= increment ;j-=increment‬‬

‫‪75‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫{‬
‫‪//perform the insertion sort for this section‬‬
‫)]‪if (temp < array[j-increment‬‬
‫{‬
‫;]‪array[j] = array[j-increment‬‬
‫}‬
‫‪else‬‬
‫{‬
‫;‪break‬‬
‫}‬
‫}‬
‫;‪array[j] = temp‬‬
‫}‬
‫}‬

‫‪ 3.10‬الترتيب السريع ‪Quick Sort‬‬


‫هررذل الخوارزميررة ربمررا تكررون االكثررر شرريوعا واسررتخداما‪ ،‬حيررث انهررا عررادة االسرررع‬
‫عمليا‪.‬‬
‫خوارزمية الترتيب السريع هي خوارزمية كفوءة جردا وتعتمرد علرى تقسريم مصرفوفة‬
‫البيانررات الررى مصررفوفات صررغيرة‪ .‬المصررفوفة الكبيرررة تقسررم الررى مصررفوفتين واحرردة‬
‫تحمل قيم صغيرة واخرى تحمل قيم كبيرة‪ ،‬وعندما نقول صغيرة وكبيررة هري نسربة‬
‫الى قيمة مقترحة‪ ،‬فالقيم التي أكبر من هذل القيمة المقترحرة توضرع بمصرفوفة والقريم‬
‫التي اقل من هذل القيمة المقترحة توضع بمصفوفة اخرى‪.‬‬
‫فرراذا كانررت لررديك مصررفوفة كبيرررة‪ ،‬فيجررب اخررذ قيمررة عشرروائية مررن المصررفوفة والترري‬
‫بموجبها سيتم تجزئة المصفوفة‪ .‬عندما يتم اختيار هذل القيمة فعليرك ان تقرارن جميرع‬
‫القيم الباقية في المصفوفة مع هذل القيمة‪ .‬القيم التي هي أكبر من القيمة المختارة مرن‬
‫الممكررن وضررعها فرري جررزء المصررفوفة االيمررن‪ ،‬بينمررا القرريم الترري أصررغر مررن الممكررن‬
‫وضعها في جزء المصفوفة االيسر‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫هررذل الخوارزميررة كفرروءة جرردا لمجموعررة البيانررات الكبيرررة‪ ،‬علمررا برران اسرروأ حالررة لهررا‬
‫لتعقيرد الوقرت هرو ))‪ (Time complexity is O (n log n‬حيرث ان ‪ n‬هرو عردد‬
‫العناصر في المصفوفة‪.‬‬

‫وبوات ووارزمية الترتيب السريع‬ ‫‪3.10.1‬‬


‫‪ .A‬اختيار القيمة ذات الفهرس االعلى في المصفوفة (اخر قيمة بالمصفوفة) لتعتبر‬
‫قيمة المحور )‪( (pivot‬احيانا يتم اختيار القيمة التي في وسط المصفوفة لتعتبر‬
‫قيمة المحور‪.‬‬
‫‪ .B‬اختيررار متغيرررين ل شررارة الررى الجانررب االيمررن وااليسررر مررن القائمررة باسررتثناء‬
‫المحور‪.‬‬
‫‪ .C‬المؤشر االيسر يؤشر الى فهرس ‪ index‬المصفوفة االدنى‪.‬‬
‫‪ .D‬المؤشر االيمن يؤشر الى فهرس المصفوفة االعلى‪.‬‬
‫‪ .E‬يتم تحريك المؤشر االيسر الى اليمين بواقع موقع واحد في المصرفوفة كرل مررة‬
‫طالما القيمرة التري يؤشرر عليهرا المؤشرر االيسرر هري أصرغر مرن قيمرة المحرور‪.‬‬
‫ويقف المؤشر عند وجود قيمة اعلى من قيمة المحور‪.‬‬
‫‪ .F‬المؤشر االيمن يتحر موقع واحد في كل مرة باتجال اليسار طالمرا قريم المواقرع‬
‫التي يمر عليها أكبر من قيمة المحور ويتوقف المؤشر على القيمة التي هي اقل‬
‫من قيمة المحور‪.‬‬
‫‪ .G‬ذا كرال المؤشررين فري الخطروات )‪ (E, F‬توقفرا علرى مروقعين مختلفرين (اي ان‬
‫المؤشر االيسر أصغر من المؤشر االيمن)‪ ،‬عند ذلك يرتم تبرديل القريم فري هرذين‬
‫الموقعين‪.‬‬
‫‪ .H‬ذا كانت قيمة المؤشر االيسر (رقم موقعه فري المصرفوفة) أكبرر او تسراوي مرن‬
‫قيمة المؤشر االيمن‪ ،‬فان نقطة االلتقاء ستكون هي قيمة المحور‪.‬‬
‫استخدام خوارزمية المحور بشركل متكررر بطريقرة االسرتدعاء الرذاتي سيوصرلنا الرى‬
‫اجزاء صغيرة محتملة‪ .‬كل جزء يعالج بطريقة الترتيب السريع‪.‬‬

‫‪77‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫ان خوارزمية االستدعاء الذاتي للترتيب السريع هي‪:‬‬


‫‪ )a‬اجعل قيمة الفهرس في اقصرى اليمرين (اي القيمرة العليرا) علرى انره المحرور‪.‬‬
‫من الممكن اختيار المحور على انه معدل القيمتين العليا والدنيا‬
‫‪a. Pivot = (High + Low) / 2‬‬
‫‪ )b‬قسم المصفوفة اعتمادا على قيمة المحور‪.‬‬
‫‪ )c‬رتب الجزء االيسر بطريقة االستدعاء الذاتي لخوارزمية الترتيب السريع‪.‬‬
‫‪ )d‬رتب الجزء االيمن بطريقة االستدعاء الذاتي لخوارزمية الترتيب السريع‪.‬‬

‫كيفية عم ووارزمية الترتيب السريع‬ ‫‪3.10.2‬‬


‫لكي يتم تنفيذ خوارزمية الترتيب السريع سيتم االستعانة بالشكل ‪ 3.9‬لمتابعة حركرة‬
‫البيانات‪.‬‬
‫بدايررة البررد مررن تحديررد قيمررة المحررور )‪ (pivot‬وهنررا أكثررر مررن طريقررة لتحديررد هررذل‬
‫القيمة‪ ،‬في هذا المثال سريتم اختيرار يرالث قريم ونخترار القيمرة الوسرطى مرن برين هرذل‬
‫القرريم الررثالث‪ ،‬القرريم الررثالث الالئري سرريتم اختيررارهن هررن القيمررة االولررى بالمصرفوفة‪،‬‬
‫والقيمة االخيرة بالمصفوفة‪ ،‬فضال عن القيمة الوسطى في المصفوفة‪.‬‬
‫فرري الشرركل ‪ 3.9‬تررم اختيررار مجموعررة مررن القرريم موزعررة عشرروائيا‪ ،‬وتررم خزنهررا فرري‬
‫مصفوفة ومن هذل القيم سيتم اختيار القيم )‪ (57, 81, 24‬ونظرا الن القيمة ‪ 57‬هي‬
‫القيمة الوسطى بين القيمتين االخريين‪ ،‬لذلك سيتم اختيارها على انها قيمة المحور‪.‬‬
‫توضع قيمة المحور بمتغير خارجي‪ ،‬وتحر القيمة )‪ (24‬الرى موقرع المحرور الرذي‬
‫تم اختيارل (اي تنقل القيمة ‪ 24‬الى الموقع صرفر فري المصرفوفة وذلرك ألنهرا أصرغر‬
‫من قيمة المحور)‪ ،‬ويبقى الموقع االخير خالي لحين انتهاء مرحلة تقسيم المصفوفة‪.‬‬
‫ولغرض ترتيب هذل القيم ترتيب تصاعدي فان أحرد اهرداف الخوارزميرة هرو تقسريم‬
‫المصررفوفة الررى قسررمين‪ ،‬القسررم االول الررذي يمثررل المواقررع ابتررداءا مررن الموقررع )‪(0‬‬
‫وصعودا سيحتوي على القيم التي هي أصغر من قيمة المحور‪ .‬والقسرم الثراني الرذي‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫سيكون باالتجال المعاكس اي يبدأ من اخر موقع في المصفوفة ويتجه باتجرال اليسرار‬
‫اي نررزوال باتجررال بدايررة المصررفوفة سرريحتوي علررى القرريم الترري هرري أكبررر مررن قيمررة‬
‫المحرور‪ .‬لتنفيررذ ذلررك سنضررع مؤشرررين أحرردهما فري بدايررة القائمررة واالخررر علررى اخررر‬
‫عنصر في القائمة‪ .‬كما في الشكل ‪.3.9‬‬
‫المؤشر االيمن سيتحر الى اليسار كما سبل وأشرنا ليمر على عناصر المصفوفة‬
‫واحد بعد االخر‪ ،‬فاذا كان العنصر الذي يمر عليه أكبر من المحرور يتركره ويسرتمر‬
‫بالحركررة‪ ،‬و ذا كرران أصررغر مررن قيمررة المحررور يقررف عليرره‪ ،‬بالمقابررل المؤشررر االيسرر‬
‫يتحر باتجال اليمين ليتوقف عند اول عنصر يصادفه أكبر من قيمة المحور‪.‬‬
‫في مثالنا هذا‪ ،‬يبدأ المؤشرين بالحركة فيتحر المؤشر االيمن ويقف عنرد اول قيمرة‬
‫تصادفه وهي القيمة )‪ (49‬والتي هي أصغر من قيمة المحور‪ .‬بالمقابل فان المؤشرر‬
‫االيسر ايضرا يتحرر ويقرف عنرد القيمرة )‪ (70‬وذلرك ألنهرا أكبرر مرن قيمرة المحرور‪.‬‬
‫عليه سيتم ابدال هاتين القيميتين واحدة بمكان االخرى‪.‬‬
‫بعررد اجررراء التبررديل تسررتمر حركررة المؤشرررات ويتحررر المؤشررر االيمررن ليقررف عنررد‬
‫القيمة )‪ (16‬ألنها أصغر من قيمرة المحرور‪ ،‬بينمرا المؤشرر االيسرر يقرف عنرد القيمرة‬
‫)‪ (97‬ألنهررا أكبررر مررن قيمررة المحررور‪ .‬تجرررى عمليررة التبررادل بيررنهم‪ .‬وتسررتمر حركررة‬
‫المؤشرات فيقف المؤشر االيمرن عنرد القيمرة )‪ (55‬ألنهرا أصرغر مرن قيمرة المحرور‪،‬‬
‫والمؤشر االيسر سيقف عند القيمرة )‪ (63‬كونهرا أكبرر مرن قيمرة المحرور وايضرا ترتم‬
‫عملية التبديل‪ .‬تستمر هذل العملية كما واضح في الشكل ‪ 3.9‬لحين ان يصل المؤشر‬
‫االيمررن الررى القيمررة )‪ (9‬والمؤشررر االيسررر يصررل الررى القيمررة )‪ ،(76‬وحيررث ان قيمررة‬
‫المؤشرر االيمرن (اي رقررم الموقرع الررذي يقرف عليره فرري المصرفوفة) أصررغر مرن قيمررة‬
‫المؤشر االيسر لذلك تتوقف الخوارزمية‪.‬‬
‫وبهررذا فأنن را قسررمنا المصررفوفة الررى قسررمين تكررون قرريم القسررم االول الررذي فرري بدايررة‬
‫المصفوفة هي أصغر من قيم عناصر القسم الثاني الذي هو في نهاية المصفوفة كما‬
‫واضح من الشكل ‪.3.9‬‬

‫‪79‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫خطرروة واحرردة اضررافية وهرري ان القيمررة الكبيرررة الترري يؤشررر عليهررا المؤشررر االيسررر‬
‫ستوضع في الموقرع االخيرر الفرار ‪ ،‬ليصربح موقعهرا خرالي حيرث ستوضرع بره قيمرة‬
‫المحور والذي سيكون في موقعه الصحيح‪.‬‬
‫بعررد هررذل المرحلررة سرريتم اسررتدعاء خوارزميررة الترتيررب السررريع لترتيررب قرريم النصررف‬
‫االول من المصفوفة والتي قيمها اقل من )‪( (57‬طبعرا هرذا االسرتدعاء هرو اسرتدعاء‬
‫ذاتي ويتم تكرارل لحين اكمال ترتيب كل العناصر)‪.‬‬
‫ايضرررا سررريتم اختيرررار يرررالث قررريم لتحديرررد قيمرررة المحرررور )‪ (pivot‬لهرررذا الجرررزء مرررن‬
‫المصفوفة‪ ،‬هنا القيم الثالث هي )‪ (24, 38, 9‬وبذلك فستكون قيمة المحرور تسراوي‬
‫‪.24‬‬
‫ونظررا الن القرريم ‪ 9‬أصرغر مررن قيمرة المحررور فسريتم نقلهررا الرى الموقررع صرفر ويبقرى‬
‫موقعها فار لحين انتهاء عملية ترتيب هذا الجزء من المصفوفة‪.‬‬
‫ايضا يستخدم مؤشرين ايمن وأيسر فيتحر المؤشر االيمن ليقف عند القيمرة )‪,(21‬‬
‫بينمرررا يقرررف المؤشرررر االيسرررر بعرررد ان يتحرررر علرررى القيمرررة )‪ ,(49‬يرررتم ابررردال القررريم‬
‫)‪ (21, 49‬واحد بدل االخر‪ .‬يستمر المؤشران بالحركرة ليقرف المؤشرر االيمرن علرى‬
‫القيمة )‪ ،(16‬ويقف المؤشر االيسر على القيمة )‪ ،(38‬وتجرى عملية التبديل‪.‬‬
‫الح هنا ان المؤشرين أصبحا بموقعين متعاكسين بمعنرى ان قيمرة المؤشرر االيسرر‬
‫أكبر من قيمة المؤشر االيمن‪ ،‬لذلك نتوقف‪.‬‬
‫فرري هررذل الحالررة ونظرررا الن القيمررة الترري يؤشررر عليهررا المؤشررر االيسررر كبيرررة فسريتم‬
‫تحريكها ونقلها الى الموقع الخالي في نهايرة هرذا القسرم مرن المصرفوفة‪ ،‬ويرتم وضرع‬
‫قيمة المحور في مكانها الذي أصبح خاليا‪.‬‬
‫االن سيتم استدعاء دالة الترتيب السريع على النصرفين المتولردين اخيررا مرن نصرف‬
‫المصفوفة التي قيمها أصغر من ‪ ,57‬وتعاد نفس الخطوات ألجل ترتيبها‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫نفس الشيء يتم بالنسبة لعناصر القسرم الثراني مرن المصرفوفة والتري قيمهرا أكبرر مرن‬
‫‪ 57‬لغررررض ترتيرررب عناصررررل‪ .‬متابعرررة الشررركل ‪ 3.9‬يسررراعد علرررى فهرررم أفضرررل‬
‫للخوارزمية‪.‬‬

‫‪81‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪83‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪85‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :3.9‬رسم توضيحي لالبوات ترتيب قيم ببريقة الترتيب السريع‪.‬‬

‫‪ ‬الدالة البرمجية لخوارزمية الترتيب السريع‬


‫هذل الدالة تستخدم معدل القيمة العليا والسفلى ليكون المحور‬

‫‪87‬‬
C++ ‫هياكل البيانات باستخدام‬

void quickSort(int arr[ ], int left, int right)


{
int i = left, j = right ;
int tmp;
int pivot = arr[(left + right) / 2];

/* ‫* التقسيم‬/
while (i <= j) {
while (arr[i] < pivot)
i++;
while (arr[j] > pivot)
j--;
if (i <= j) {
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
}
/* ‫* االستدعاء الذاتي‬/
if (left < j)
quickSort(arr, left, j);
if (i < right)
quickSort(arr, i, right);
}
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 3.11‬البحث ‪Searching‬‬
‫اسررتعادة المعلومررات هرري واحرردة مررن اهررم تطبيقررات الحاسرربات‪ .‬عررادة تتضررمن اعطرراء‬
‫جررزء مررن المعلومررات تسررمى المفترراح‪ ,‬ويررتم السررؤال عررن ايجرراد القيررد الررذي يحترروي‬
‫معلومات مشتركة اخرى‪ .‬هذل تنجز بالذهاب اوال الى القائمة لمعرفة ذا كان المفتاح‬
‫موجود او ال‪ ،‬هذل العملية تسمى بحث ‪ .searching‬انظمة الحاسوب تستخدم لخزن‬
‫كميات كبيررة مرن البيانرات‪ ،‬وتبررز دائمرا الحاجرة السرتعادة قيرود مفرردة وفقرا لربعض‬
‫صفات البحث‪ .‬ان عملية البحث عن عنصر معين في هياكل البيانات من الممكرن ان‬
‫يكون بسيط او معقد جدا‪.‬‬
‫البحررث مررن الممكررن ان يكررون علررى شرركل هياكررل بيانررات داخليررة او هياكررل بيانررات‬
‫خارجيررة‪ .‬اسررتعادة المعلومررات حسررب الصرريغة المطلوبررة هرري الفعاليررة المركزيررة لكرل‬
‫تطبيقات الحاسبات‪.‬‬
‫هنررا طرررق بحررث مختلفررة وهرري بشرركل عررام مررن الممكررن ان نجملهررا بنرروعين‪ ،‬وهمررا‬
‫البحث الخطي والبحث غير الخطي‪.‬‬

‫البحث الالبي ‪Linear Search‬‬ ‫‪3.11.1‬‬


‫البحررث الخطرري هررو خوارزميررة بحررث اساسررية وبسرريطة‪ .‬البحررث الخطرري يبحررث عررن‬
‫عنصر او قيمة في مصفوفة لحين ان يتم ايجاد العنصر المطلروب او لرم يرتم ايجرادل‪،‬‬
‫وطريقة البحث تكون ببحث تعاقبي او متتالي‪ .‬هي تقارن المفتاح مع جميع العناصر‬
‫االخرى التي في القائمة‪ ،‬فاذا تم مطابقرة المفتراح الرذي نبحرث عنره مرع أحرد عناصرر‬
‫القائمة فيتم اعادة موقع هذا المفتاح او العنصر وبخرالف ذلرك يرتم اعرادة (كلمرة خطرا‬
‫او مررن الممكررن ‪ 1-‬او أي ترتيررب اخررر يشررير الررى عرردم وجررود العنصررر فرري القائمررة)‪.‬‬
‫البحث الخطي يطبل على القروائم المرتبرة والقروائم غيرر المرتبرة عنردما يكرون هنرا‬
‫عدد قليل من العناصر في القائمة‪.‬‬
‫تحررردد كفررراءة الخوارزميرررة عرررن طريرررل حسررراب عررردد المقارنرررات التررري تقررروم بهرررا‬
‫الخوارزمية‪.‬‬

‫‪89‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫م حظة‪ :‬خوارزمية البحث المثالية هي التي تصل الى البيانات المرغوبة بأقرل عردد‬
‫من المقارنات الممكنة‪.‬‬
‫م حظة‪ :‬عملية البحث تنتهي بواحدة مرن نتيجترين‪ ،‬واحردة للبحرث النراجح واالخررى‬
‫للبحث غير الناجح‪.‬‬
‫مثةال ‪ :‬فري الشركل ‪ 3.10‬فران البحرث عرن القيمرة )‪ (45‬تعيرد (غيرر موجرود)‪ ..‬وهرذل‬
‫عملية بحث عير ناجح‪.‬‬
‫امررا البحررث عررن القيمررة )‪ (12‬سررتعيد الرررقم )‪ (4‬وهررو يمثررل موقررع القيمررة الترري تررم‬
‫ايجادها‪ ..‬وهذل عملية بحث ناجحة‪.‬‬

‫شك ‪ :3.10‬مصفوفة قيم يتم البحث فيها عن قيمة مفتاح‪.‬‬


‫تحليل كفاءة خوارزمية البحث تحدد بعدد مرات المقارنة كما سبل وأسلفنا‪.‬‬
‫ففي حالة البحث الناجح‪ ،‬فان أفضل حالة هري عنردما نجرد العنصرر المطرابل للمفتراح‬
‫في الموقع االول وبالتالي فان عدد مررات المقارنرة ألفضرل حالرة فري البحرث النراجح‬
‫هي مرة واحدة فقط ))‪.(O (1‬‬
‫اما اسوأ حالة في البحث الناجح عندما يكون العنصر الرذي نبحرث عنره اخرر عنصرر‬
‫في القائمة وبالتالي فان عدد المقارنات ستكون ))‪.(O(N‬‬
‫امررا فرري حالررة البحررث غيررر النرراجح فرران أفضررل حالررة واسرروأ حالررة متسرراوية وهرري‬
‫))‪.(O(N‬‬

‫‪ ‬دالة برمجية لتنفيذ عملية البحث الخطي‪:‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫)‪function findIndex(values, target‬‬


‫{‬
‫)‪for(int i = 0; i < values.length; ++i‬‬
‫{‬
‫)‪if (values[i] == target‬‬
‫;‪return i‬‬
‫}‬
‫;‪return -1‬‬
‫}‬
‫من الممكن اسرتدعاء الدالرة اعرالل مرع تمريرر المصرفوفة والعنصرر المطلروب البحرث‬
‫عنه كما يلي‪:‬‬
‫;)]‪findIndex ([2, 5, 0, 9, 4, 3, 10, 7, 22, 12‬‬

‫البحث الثنائي ‪Binary Search‬‬ ‫‪3.11.2‬‬


‫هي طريقة اخرى من طرق البحث والتري تعمرل علرى القروائم المرتبرة (قيمهرا مرتبرة‬
‫ترتيب تصاعدي او تنازلي)‪ .‬البحث الثنائي ينفذ على المصفوفات او القوائم المرتبة‪,‬‬
‫في البداية يتم مقارنة المفتاح الذي نبحث عنره مرع القيمرة التري فري وسرط المصرفوفة‪.‬‬
‫فاذا ك انت متطابقة (متساوية) فان هرذل القيمرة يرتم اعادتهرا‪ .‬ذا القيمرة اقرل مرن القيمرة‬
‫التي في وسط المصفوفة‪ ،‬فان القيمة التي نبحث عنها ستكون في النصف االسرفل او‬
‫النصررف االول مررن المصررفوفة‪ ،‬امررا ذا كانررت أكبررر مررن القيمررة الترري فرري الوسررط فهررذا‬
‫يعنرري انهررا تقررع فرري النصررف العلرروي او النصررف الثرراني مررن المصررفوفة (فرري حررال ان‬
‫المصفوفة مرتبة تصاعديا)‪ .‬هذل العملية تكرر وفي كل مرة ننصف جزء المصرفوفة‬
‫الذي حدد في المرة السابقة‪ ،‬ونحدد في اي جزء يقع المفتاح لنعمل علرى ذلرك الجرزء‬
‫مع اهمال باقي االجزاء‪.‬‬

‫مثال‪ :‬في الشكل ‪ 3.11‬مصفوفة مرتبة مطلوب البحث عن القيمة (‪.)44‬‬

‫‪91‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :3.11‬مصفوفة مرتبة‪.‬‬

‫‪ ‬خطوات البحث الناجح‪..‬‬


‫الالبوة االولل ‪ :‬في هذل المرحلة مرن المفرروض ان نجرد الموقرع الوسرط وبعردها ترتم‬
‫عملية مقارنة القيمة التي نبحث عنها مع هذل القيمة في المنتصف‪.‬‬
‫موقع الوسط = (اعلى موقع ‪ +‬أدني موقع) ‪2 /‬‬
‫موقع الوسط = ‪4 = (8 + 0) / 2‬‬
‫الح هنا ان القيمة في الموقع الوسط كمرا فري الشركل ‪ 3.12‬هري (‪ ,)38‬ونظررا الن‬
‫القيمة التي نبحث عنها (‪ )44‬أكبر من قيمة الوسط (‪ ,)38‬لرذلك سرنتوجه للبحرث فري‬
‫النصف االعلى ونهمل النصف االدنى‪ .‬ان الموقع االسفل في نصف المصفوفة الذي‬
‫تم اختبارل سيكون (‪( )5‬الن المنتصف هو ‪ 4‬لذلك سيكون الموقع االسرفل الرى يمرين‬
‫المنتصف اي المنتصف ‪ ،)1 +‬والموقع االعلى سيكون (‪.)8‬‬

‫شك ‪ :3.12‬تحديد المنتصف فض عن القيمة السفلل وال ليا للمصفوفة‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫الالبةةوة الثانيةةة‪ :‬ايضررا نحرراول ايجرراد المنتصررف للنصررف االعلررى مررن المصررفوفة‪،‬‬
‫ونقارن‪.‬‬
‫موقرع الوسرط = ‪( 6 = (8 + 5) / 2‬دائمرا الكسرور تقررب الرى اقررب عردد صرحيح‬
‫باستخدام عملية تدوير فمثال ‪ 6.5‬تقرب الى ‪ 6‬وهكذا)‪.‬‬
‫االن‪ ،‬القيمة في موقع الوسط هي ‪ 77‬كما فري الشركل ‪ ,3.13‬ونظررا الن ‪ 44‬اصرغر‬
‫من ‪ 77‬لذلك فانا الخطوة الالحقة ستكون البحرث فري النصرف االدنرى مرن المصرفوفة‬
‫الجديرردة‪ ،‬وسرريكون الموقررع االعلررى هررو (‪( )5‬الح ر هنررا ان الموقررع االعلررى سرريكون‬
‫الوسط ‪ ،)1-‬بينما الموقع االدنى سيكون (‪.)5‬‬

‫شك ‪ :3.13‬تحديد المنتصف للنصف ال لوي من المصفوفة‪.‬‬

‫م حظة‪ :‬عندما نختار النصف االدنى مرن المصرفوفة فران الموقرع االدنرى للمصرفوفة‬
‫هو ذات الموقع االدنى لهذا النصف من المصفوفة‪ ،‬بينما الموقع االعلرى لهرا يسراوي‬
‫(موقع الوسط ‪.)1 -‬‬
‫اما ذا اخترنا النصف العلوي من المصفوفة فان الموقع االعلرى للمصرفوفة هرو ذات‬
‫الموقع االعلى لهذا النصف من المصفوفة‪ ،‬بينما الموقع االدنى لهذا النصرف يسراوي‬
‫(موقع الوسط ‪.)1 +‬‬

‫الالبوة الثالثة‪ :‬في هذل الخطة فان موقع الوسط هرو ‪ 5‬وهرو الموقرع الوحيرد المتبقري‬

‫‪93‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫في المصفوفة والقيمة التي فيره هري (‪ ,)44‬وهري ذات القيمرة التري نبحرث عنهرا لرذلك‬
‫سيتم اعادة موقع القيمة وبيان ان البحث تم بنجاح‪ .‬الح الشكل ‪.3.14‬‬

‫شك ‪ :3.14‬تنصيف الجزء االوير من المصفوفة‪.‬‬

‫لنعيد العمل بالمثال السابل ولكن لنبحث (بحث غير ناجح) عن القيمة (‪.)45‬‬
‫الالبوة االولل‪ :‬موقع الوسط يحتوي على القيمة ‪ 38‬كما فري الشركل ‪ ,3.12‬ونظررا‬
‫الن )‪ (45 > 38‬فسيتم البحث في نصف المصفوفة االعلى‪.‬‬
‫الالبةوة الثانيةة‪ :‬نسرتعين بالشركل ‪ ,3.13‬ونالحر ان قيمرة الوسرط )‪ (77>45‬لرذلك‬
‫سيتم البحث في الخطوة الالحقة في النصف االسفل من المصفوفة‪.‬‬
‫الالبةةوة الثالثةةة‪ :‬يالحر هنررا وحسررب الشرركل ‪ 3,14‬ان القيمررة فرري الوسررط هرري ‪,44‬‬
‫ونظرا الى ان )‪ (44<45‬لذلك فان البحث في المرحلة الالحقرة سريكون فري النصرف‬
‫االعلى من المصفوفة‪.‬‬
‫هنا الموقع االعلى للمصفوفة الجديدة سيكون ذات الموقع االعلى لها وهو (‪ ،)5‬بينما‬
‫الموقررع االدنررى سرريكون (‪ .. )6=1+5‬مررن ذلررك نالح ر ان الموقررع االدنررى أكبررر مررن‬
‫الموقع االعلى وهذا داللة علرى انتهراء البحرث دون ان نجرد القيمرة التري نبحرث عنهرا‬
‫لذلك تتوقف عملية البحث‪.‬‬

‫‪ ‬كفاءة البحث الثنائي‪:‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫البحث الناجح‪ :‬أفضل بحث يكون فيه عدد المقارنات = ‪1‬‬


‫اسوأ بحث يكون عدد المقارنات يساوي ‪ ,log2 N‬حيث ان ‪ N‬يمثل حجم المصفوفة‪.‬‬
‫البحث غير الناجح‪ :‬أفضل بحث ال يوجد‬
‫اسوا بحث يساوي ‪log2 N‬‬
‫فقط للمقارنرة ذا كران لردينا مصرفوفة بحجرم ‪ 1000‬عنصرر فران اسروا بحرث بالبحرث‬
‫الخطي يساوي ‪ 1000‬مقارنة‪ ،‬بينما عند البحث الثنائي فران عردد المقارنرات تسراوي‬
‫‪.14‬‬

‫شك ‪ :3.15‬شك توضيحي لبريقة البحث الثنائي‪.‬‬

‫‪95‬‬
C++ ‫هياكل البيانات باستخدام‬

:‫ دالة برمجية لطريقة البحث الثنائي هو‬


function findIndex(values, target)
{
return binarySearch(values, target, 0, values.length - 1);
};

function binarySearch(values, target, start, end) {


if (start > end) { return -1; } // ‫غير موجود‬

int middle = (start + end) / 2 ;


int value = values[middle];

if (value > target)


{ return binarySearch (values, target, start, middle-1); }
if (value < target)
{ return binarySearch(values, target, middle+1, end); }
return middle; // ‫موجود‬
}

:‫من الممكن استدعاء الدالة مع تمرير قائمة القيم والمفتاح كما يلي‬ 

findIndex ([2, 4, 7, 9, 13, 15], 13)


‫هياكل البيانات باستخدام ‪C++‬‬

‫البحث باالستيفاء ‪Interpolation Search‬‬ ‫‪3.11.3‬‬


‫البحث باالستيفاء هي طريقة بديلرة لطريقرة البحرث الثنرائي والتري تسرتخدم معلومرات‬
‫حررول التوزيررع الضررمني للبيانررات الترري يررتم البحررث عنهررا‪ .‬باسررتخدام هررذل المعلوم رات‬
‫االضررافية‪ ،‬فرران خوارزميررة البحررث االسررتيفائي مررن الممكررن ان تكررون أسرررع بدرجررة‬
‫)))‪ ,O(log(log(n‬حيث ان ‪ n‬هو حجم المصفوفة‪.‬‬
‫فرري البحررث الثنررائي فأنهررا دائمررا تختررار العنصررر الررذي فرري وسررط المصررفوفة ألجررل‬
‫المقارنة‪ ،‬مع اهمال نصف فضاء البحث‪ .‬البحث االستيفائي يحاول ان يتنبأ اين يوجد‬
‫المفتاح الذي نبحث عنه فري فضراء البحرث بواسرطة االسرتيفاء الخطري‪ ،‬فهري تحسرب‬
‫الموقررع االفتراضرري للمفترراح و ذا لررم يررتم ايجرراد المفترراح فرري ذلررك الموقررع فأنهررا تقلررص‬
‫فضاء البحث لجزء قبل او بعد الموقع االفتراضي للمفتاح‪ .‬هذل الطريقة تستخدم فقط‬
‫ذا كانت حسابات الفرق بين عناصر المصفوفة المتعاقبة معقولة‪.‬‬

‫‪ ‬الموقع التقديري للمفتاح يحسب كما يلي‪:‬‬


‫نفرررض ان فضرراء البحررث الحررالي هررو ]‪ A[i…j‬وكرران البحررث عررن القيمررة ‪ ,x‬االن‬
‫باستخدام االستيفاء الخطي للقيم‪ ،‬فان ‪ x‬يفترض ان تكون في الموقع‪:‬‬

‫)]‪middle = i + ((j - i) * (x - A[i])) / (A[j] - A[i‬‬

‫يمكن اعادة كتابة العالقة اعالل لغرض تفسير الرموز الواردة فيها كما يلي‪:‬‬

‫الموقةةع الوسةةط و الموقةةع اال نةةلي ((الموقةةع االعلةةل – الموقةةع اال نةةل) × (قيمةةة‬
‫المفتاح – القيمة في الموقةع اال نةل)) ÷ (القيمةة فةي الموقةع االعلةل – القيمةة فةي‬
‫الموقع اال نل)‬

‫‪97‬‬
C++ ‫هياكل البيانات باستخدام‬

.‫ برنامج تنفيذ طريقة البحث باالستيفاء‬


#include "stdio"
#include "stdlib"

#define MAX 200


using namespace std ;
int interpolation_search (int a[], int bottom, int top, int item) {

int mid;
while (bottom <= top) {
mid = bottom + (top - bottom) * ((item - a[bottom]) / (a[top] -
a[bottom])) ;
if (item == a[mid])
return mid + 1;
if (item < a[mid])
top = mid - 1;
else
bottom = mid + 1;
}
return -1;
}

int main() {
int arr[MAX];
C++ ‫هياكل البيانات باستخدام‬

int i, num;
int item, pos;

cout<< "\n Enter total elements (num< MAX) " ;


cin >> num ;

cout<< "Enter Values to Elements : " ;


for (i = 0; i < num; i++)
cin>> arr[i] ;

cout << "\n Display Elements " ;


for (i = 0; i < num; i++)
cout<< arr[i]<< “\t” ;

cout<< "\n Enter value you Search For : " ;


cin>>item ;
pos = interpolation_search (&arr[0], 0, num, item);
if (pos == -1)
cout<< "\n Element” << item<< “not found \n”;
else
cout<< "\n Element” <<item<<” found at position \n” ;

return 0;
}

99
‫هياكل البيانات باستخدام ‪C++‬‬

‫طريقة البحث بالقفز ‪Jump Search‬‬ ‫‪3.11.4‬‬


‫هذل الطريقة تنفذ على المصفوفات المرتبة‪ .‬في هذل الطريقة سنسرتخدم قفرزات يحردد‬
‫طولها بطريقة تسراعد علرى تحقيرل الوصرول الرى النتيجرة المطلوبرة (ايجراد العنصرر‬
‫الررذي نبحررث عنرره) بأقررل وقررت ممكررن‪ .‬وعنرردما نقررول قفررزات هررذا يعنرري ان المقارنررة‬
‫ستكون مع عناصر تبعد عن بعضها مسافة (غالبا تعتمد على عدد العناصر) تحسب‬
‫مسبقا تسمى قفرزة‪ .‬غالبرا يحردد طرول القفرزات بمسرافة ( ( حيرث ان ‪ n‬هري حجرم‬
‫المصفوفة‪.‬‬
‫عند تحديد طول القفزة فهذا يعني امكانية تحديد المواقع التي سيتم المقارنة مع قيمها‪.‬‬
‫فمررثال ذا كرران طررول القفرررزة يسرراوي ‪ 3‬فهررذا يعنرري ان المواقرررع الترري سرريتم مقارنرررة‬
‫عناصرها هي )… ‪.(3, 6, 9, 12, 15, 18‬‬
‫يقارن المفتاح مع قيمة اول موقع فراذا كران المفتراح أكبرر (فري حالرة كرون المصرفوفة‬
‫مرتبة تصاعديا‪ ،‬اما ذا تنازلي فيكون بالعكس) ينتقل الى المقارنة مع الموقرع الترالي‬
‫وتستمر المقارنة لحين ان يجد قيمة موقع أصغر مرن قيمرة المفتراح‪ .‬فري هرذل الحالرة‪،‬‬
‫فان قيمة ال مفتاح ستكون بين الموقع الذي كان اخر مقارنة معه والموقرع السرابل لره‪،‬‬
‫هنا ستكون مقارنة خطية مع القيم بين هذين الموقعين‪ .‬فأما ان يتم ايجاد تطابل او ال‬
‫يوجد‪.‬‬

‫مثال‪ :‬في المصفوفة التالية مطلوب البحث عن القيمة (‪ )20‬باستخدام البحث الثنائي‪،‬‬
‫البحث االستيفائي‪ ,‬والبحث بالقفز‪.‬‬

‫}‪int[] a = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30‬‬

‫‪ ‬الح ببريقة البحث الثنائي‬

‫المصفوفة هي بين الموقع االدنى صفر‪ ،‬والموقع االعلى ‪.15‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫اذن الوسط = ‪7 = (0 + 15) / 2‬‬


‫القيمة في الموقع (‪ )7‬هي (‪ ،)14‬والتري هري أصرغر مرن قيمرة المفتراح (‪ .)20‬لرذلك‪،‬‬
‫فان الموقع االدنى سيكون )‪ (7 + 1 = 8‬والموقع االعلى يبقى (‪.)15‬‬
‫االن الموقع الوسط = ‪11 = (8 + 15) / 2‬‬
‫القيمة في الموقع (‪ )11‬هري (‪ ،)22‬والتري هري أكبرر مرن قيمرة المفتراح (‪ .)20‬لرذلك‪،‬‬
‫فان الموقع االدنى سيكون )‪ (8‬والموقع االعلى يكون )‪.(11-1=10‬‬
‫الموقع الوسط = ‪9 = (8 + 10) / 2‬‬
‫القيمة في الموقع (‪ )9‬هي (‪ ،)18‬والتري هري أصرغر مرن قيمرة المفتراح (‪ .)20‬لرذلك‪،‬‬
‫فان الموقع االدنى سيكون )‪ (9 + 1 = 10‬والموقع االعلى يبقى (‪.)10‬‬
‫الموقع الوسط = ‪10 = (10 + 10) / 2‬‬
‫القيمة في الموقع (‪ )10‬تساوي (‪ )20‬والذي هو يساوي قيمة المفتاح (‪ )20‬لذلك فان‬
‫المفتاح تم ايجادل في الموقع (‪.)10‬‬

‫‪ ‬البحث االستيفائي‬

‫الموقع االدنى =‪ ,0‬الموقع االعلى = ‪ ,15‬القيمة التي في الموقع االدنرى = ‪ ,0‬القيمرة‬


‫التي في الموقع االعلى = ‪ ,30‬المفتاح = ‪ .20‬اذن الموقع الوسط يساوي‬

‫)) ]‪Middle =low +(high-low)*( (key –a[low]) /(a[high] –a[low‬‬


‫‪middle = 0 +ceil(15 –0)* ( (20 –0) / (30–0) )= 0 +10 =10‬‬

‫القيمة التي في الموقع (‪ )10‬تساوي (‪ )20‬وهي تساوي قيمة المفتاح‪ .‬بهرذا يكرون قرد‬
‫تم ايجاد قيمة المفتاح‪.‬‬

‫‪101‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ ‬البحث بالقفز‬

‫(‪.‬‬ ‫هنا سيكون طول القفزة الواحدة يساوي‬


‫بموجب هذا الطول‪ ،‬فان الخوارزمية ستنظر الرى قريم العناصرر فري المواقرع ‪(4, 8,‬‬
‫)…‪.12,‬‬
‫االن القيمة في الموقع (‪ )4‬هي (‪ )6‬وهذل القيمة أصغر من المفتاح (‪ ،)20‬لذلك سيتم‬
‫النظر الى موقرع القفرزة التاليرة وهري الموقرع (‪ )8‬ونالحر ان القيمرة فري هرذا الموقرع‬
‫تساوي (‪ )14‬وهي ايضا اقل من قيمة المفتاح‪ ،‬عليه يتم االنتقال الى القفرزة االخررى‬
‫ويتم المقارنة مع القيمة التي في الموقرع (‪ ،)12‬القيمرة فري الموقرع (‪ )12‬تسراوي ‪22‬‬
‫وهي أكبر من قيمة المفتاح (‪ ،)20‬من المقارنة االخيرة فان قيمة المفتاح ستكون بين‬
‫الموقع (‪ )8‬والموقرع (‪ ) 11‬ولرذلك سريتم البحرث عنهرا هنرا بحرث تسلسرلي ابترداءا مرن‬
‫الموقع (‪ .)8‬سيتم ايجاد قيمة المفتاح في الموقع ‪.10‬‬

‫دول التجزئة ‪Hashing Table‬‬ ‫‪3.12‬‬


‫هو هيكل بيانات يقوم بخزن البيانات بطريقة الترابط‪ .‬في جدول التجزئرة‪ ،‬يرتم خرزن‬
‫البيانات في مصفوفة بحيث ان كل قيمة بيانات لها رقم فهرس (موقع في المصفوفة)‬
‫وحيد‪ .‬الوصول الى البيانات يصبح سريع ذا عرفنا رقم الفهرس للبيانات المطلوبة‪.‬‬
‫عليه‪ ،‬سيتولد هيكل بيانات بحيث ان عمليات الحشر والبحث تكون سريعة جدا نسبة‬
‫لحجررم البيانررات‪ .‬جرردول التجزئررة يسررتخدم المصررفوفة كوسررط خررزن ويسررتخدم تقنيررة‬
‫التجزئة لتوليد الفهرس الذي سيتم به حشر العنصر‪.‬‬

‫التجزئة ‪Hashing‬‬ ‫‪3.12.1‬‬


‫جدول التجزئة هو هيكل بيانات لخزن قيم ينائية تمثل (المفتاح‪ ،‬القيم)‪ .‬وهي ال تشبه‬
‫المصرفوفات التري تسرتخدم ارقرام الفهرسرة للوصرول الرى العناصرر‪ ،‬فجردول التجزئررة‬
‫يستخدم المفاتيح للبحث في مدخالت الجدول‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫في ‪ C++‬يتم تنفيذ جردول التجزئرة عرادة علرى شركل مصرفوفة قروائم موصرولة‪ .‬فهري‬
‫تخررز ن علررى شرركل مصررفوفة ينائيررة االبعرراد‪ .‬بالنسرربة لمصررفوفة ينائيررة االبعرراد‪ ،‬فرران‬
‫العناصر تتكون من صفوف يابتة االبعاد‪ .‬لكن‪ ،‬في جدول التجزئة فان العناصر مرن‬
‫الممكن ان تتمدد وتتقلص لتستوعب (افتراضيا) ما النهاية من مدخالت الجدول‪.‬‬

‫مررن حيررث الكفرراءة فرران جرردول التجزئررة يعتبررر حررل وسررط بررين المصررفوفات والقرروائم‬
‫الموصولة‪ .‬فهو يسرتخدم كرل مرن الفهرسرة والمررور علرى القائمرة لخرزن واسرترجاع‬
‫البيانات‪.‬‬
‫البحث عن العناصر باسرتخدام الفهرسرة يجعرل المصرفوفة كفروءة جردا‪ .‬بغرض النظرر‬
‫عررن موقررع خررزن العنصررر فرري المصررفوفة‪ ،‬هرري دائمررا تأخررذ نفررس الوقررت السررتعادة‬
‫البيانررات‪ .‬حسررب المصررطلحات الفنيررة‪ ،‬الحصرررول علررى عنصررر مررن مصررفوفة هرررو‬
‫))‪ (O(1‬من العمليات او (وقت يابت)‪.‬‬
‫البحث عن عناصر في القروائم الموصرولة هري اقرل كفراءة بكثيرر‪ .‬ألنرك ال يمكنرك ان‬
‫تصررل بشرركل مباشررر الررى اي عقرردة فرري القائمررة‪ .‬فبرردل الوصررول المباشررر فأنررك مررن‬
‫المفررروض ان تمررر علررى القائمررة مررن البدايررة لحررين الوصررول الررى العنصررر المطلرروب‬
‫بطريقة البحث التسلسلي‪ .‬ذا وجدت العنصر المطلوب في بداية القائمة فان استعادته‬
‫تتطلب ))‪ (O (1‬من العمليات حيث أنك مررت على عنصر واحد فقرط فري القائمرة‪.‬‬
‫اما ذا كان العنصر الذي تبحث عنره فري ذيرل القائمرة فأنرك تحتراج الرى ))‪ (O(n‬مرن‬
‫العمليات‪ ،‬حيث ان ‪ n‬تمثل العدد الكلي للعقد في القائمة‪.‬‬
‫بشكل عام فان جدول التجزئة مشابه للمصفوفات فهو يبحث بوقت يابت كمعدل وهو‬
‫))‪ ,(O(1‬بغض النظر عن عدد العناصر في الجدول‪.‬‬

‫كيف ت م داول التجزئة‬ ‫‪3.12.2‬‬


‫عندما نتحدث عن عمل جداول التجزئة‪ ،‬فيجب ان نتحردث عرن يرالث امرور رئيسرية‬
‫وهي‪:‬‬

‫‪103‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .1‬ينررائي القيمررة والمفترراح‪ :‬ان الثنررائي (القيمررة‪ ،‬المفترراح) هرري جرروهر هيكررل بيانررات‬
‫جدول التجزئة‪ .‬للحاالت المناسبة‪ ،‬فأنها تجعل البحث حقيقة كفوء ومثالي‪.‬‬
‫في بعض الحاالت ليس بالضرورة استخدام مفتاح مع القيمة وانما تسرتخدم ذات‬
‫القيمة على انها قيمة ومفتاح بذات الوقت‪.‬‬
‫‪ .2‬دالة التجزئة‪ :‬دالة التجزئة تقرر اين يتم خزن او من ايرن يرتم اسرتعادة العناصرر‬
‫في جدول التجزئة‪ .‬هي تأخذ مفتاح العنصر على انره معامرل ادخرال وتعيرد رقرم‬
‫الفهرس او الموقع لهرذا العنصرر‪ .‬بشركل عرام‪ ،‬دالرة التجزئرة تسرتخدم رياضريات‬
‫باقي القسمة‪ .‬عمليا‪ ،‬قيمة المفتاح تقسم على طول الجدول لتوليد رقم فهرسة في‬
‫الجدول‪ .‬رقم الفهرسة هذا يشير الى الموقع في جدول التجزئة‪.‬‬

‫)‪int hash( string key‬‬


‫{‬
‫;‪int value = 0‬‬
‫)‪for ( int i = 0; i < key.length(); i ++‬‬
‫;]‪value += key[i‬‬
‫;‪return value % tableLength‬‬
‫}‬

‫‪ .3‬تصةةا عناصةةر ةةدول التجزئةةة‪ :‬التصررادم يعنرري ان اينرران او ربمررا اكثررر مررن‬
‫المفاتيح لها نفس رقم الفهرس‪ .‬لغرض تعظيم كفاءة خرزن واسرترجاع العناصرر‬
‫في جدول التجزئة‪ ،‬فاننرا نحتراج الرى تقليرل عردد التصرادم الرى الحرد االدنرى‪ .‬كرل‬
‫تصادم يعني عنصر اخر في القائمة‪ ،‬او عقدة في القائمة الموصرولة‪ .‬نحرن نعلرم‬
‫بان خزن واستعادة العناصرر فري القروائم الموصرولة تنمرو أكثرر فري مجرال عردم‬
‫الكفررراءة عنررردما تكبرررر القائمرررة‪ .‬لرررذلك مرررن المحبرررذ ان نحررراف علرررى هرررذل القررروائم‬
‫الموصولة لتكون أقصر ما يمكن‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫هنا عدة طرق لكتابة دالة تجزئة كفوءة بحيث تعالج حاالت التصادم بكفاءة‪ ،‬منها‪:‬‬
‫‪ .A‬جعل حجم الجدول رقم اولري (اي رقرم ال يقبرل القسرمة اال علرى واحرد او نفسره)‬
‫هي طريقة جيدة لتقليل التصادم الى الحرد االدنرى‪ .‬بشركل عرام‪ ،‬ان دالرة التجزئرة‬
‫الجيدة هي التي تمأل جدول التجزئة بشكل متجانس وعادل‪.‬‬
‫ان السربب باسرتخدام العرردد االولري‪ ،‬هرو ان القيمررة الناتجرة مرن دالررة التجزئرة فرري‬
‫حالة عدم استخدام عدد اولي لحجم المصفوفة ستكون صفر (باقي القسرمة) لكرل‬
‫مفترراح يقبررل القسررمة علررى الحجررم‪ .‬لكررن‪ ،‬ذا اسررتخدمنا عرردد اولرري للحجررم فأننررا‬
‫سنقلص فرص ان يكون المفتاح يقبل القسمة على الحجم‪.‬‬
‫‪ .B‬واحدة من الحلول المسرتخدمة هري عنردما نسرتخدم دالرة التجزئرة ويكرون الموقرع‬
‫الناتج محتل من قبل عنصر اخر فيتم البحث عن أقرب موقع فار لهرذا الموقرع‬
‫وتحشررر القيمررة الجديرردة فيرره‪ .‬هررذل الطريقررة ال تعتبررر طريقررة جيرردة‪ ،‬مررن الممك رن‬
‫استخدامها عندما يكون حجم الجدول يابت‪.‬‬
‫في الشكل ‪ 3.16‬توضيح لكيفية تنفيذ هذل الطريقة على القيم التالية عندما يكرون‬
‫حجم الجدول مساوي الى ‪:20‬‬

‫)‪(1, 2, 42, 4, 12, 14, 17, 13, 37‬‬

‫‪ .C‬حل اخر هو تقنية سلسلة جدول التجزئة البسيط‪ ،‬فكل موقع في المصفوفة يشرير‬
‫الى قائمة موصولة بحيث تتكون عناصر هذل القائمة من العناصر التي تتصرادم‬
‫في ذلك الموقع‪ .‬ان عملية الحشر تتطلب ايجاد الموقع الصرحيح وربرط العنصرر‬
‫بنهاية القائمة في ذلك الموقع‪ .‬اما عملية الحذف فهري تتطلرب البحرث فري القائمرة‬
‫ضمن الموقع المحدد زالة العنصر‪ ،‬الح الشكل ‪.3.17‬‬

‫‪105‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫بعرررررررررد تالفررررررررري‬ ‫الفهرسة في‬ ‫التسلسل المفتاح دالة التجزئة‬


‫التصادم‬ ‫المصفوفة‬
‫‪1‬‬ ‫‪1‬‬ ‫‪1 % 20 = 1‬‬ ‫‪1‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪2‬‬ ‫‪2 % 20 = 2‬‬ ‫‪2‬‬ ‫‪2‬‬
‫‪3‬‬ ‫‪2‬‬ ‫‪42 % 20 = 2‬‬ ‫‪42‬‬ ‫‪3‬‬
‫‪4‬‬ ‫‪4‬‬ ‫‪4 % 20 = 4‬‬ ‫‪4‬‬ ‫‪4‬‬
‫‪12‬‬ ‫‪12‬‬ ‫‪12 % 20 = 12‬‬ ‫‪12‬‬ ‫‪5‬‬
‫‪14‬‬ ‫‪14‬‬ ‫‪14 % 20 = 14‬‬ ‫‪14‬‬ ‫‪6‬‬
‫‪17‬‬ ‫‪17‬‬ ‫‪17 % 20 = 17‬‬ ‫‪17‬‬ ‫‪7‬‬
‫‪13‬‬ ‫‪13‬‬ ‫‪13 % 20 = 13‬‬ ‫‪13‬‬ ‫‪8‬‬
‫‪18‬‬ ‫‪17‬‬ ‫‪37 % 20 = 17‬‬ ‫‪37‬‬ ‫‪9‬‬
‫شك ‪ :3.16‬توضيح كيفية حساب مواقع المصفوفة وم الجة التصا باوتيار أقرب موقع‪.‬‬

‫شك ‪ :3.17‬توضيح لم الجة التصا ببريقة مصفوفة القوائم‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫مثال‪ :‬لو فرضنا ان القيم التالية مطلوب خزنها في جدول تجزئة حجمه ‪.20‬‬

‫)‪(1, 2, 42, 4, 12, 14, 17, 13, 37‬‬


‫النتيجة ستكون كما في الشكل ‪.3.18‬‬

‫الفهرسة في المصفوفة‬ ‫التسلسل المفتاح دالة التجزئة‬


‫‪1‬‬ ‫‪1 % 20 = 1‬‬ ‫‪1‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪2 % 20 = 2‬‬ ‫‪2‬‬ ‫‪2‬‬
‫‪2‬‬ ‫‪42 % 20 = 2‬‬ ‫‪42‬‬ ‫‪3‬‬
‫‪4‬‬ ‫‪4 % 20 = 4‬‬ ‫‪4‬‬ ‫‪4‬‬
‫‪12‬‬ ‫‪12 % 20 = 12‬‬ ‫‪12‬‬ ‫‪5‬‬
‫‪14‬‬ ‫‪14 % 20 = 14‬‬ ‫‪14‬‬ ‫‪6‬‬
‫‪17‬‬ ‫‪17 % 20 = 17‬‬ ‫‪17‬‬ ‫‪7‬‬
‫‪13‬‬ ‫‪13 % 20 = 13‬‬ ‫‪13‬‬ ‫‪8‬‬
‫‪17‬‬ ‫‪37 % 20 = 17‬‬ ‫‪37‬‬ ‫‪9‬‬

‫شك ‪ :3.18‬توضيح لحساب مواقع القيم في دول التجزئة مع م الجة التصا ببريقة‬
‫مصفوفة القوائم‪.‬‬

‫‪ ‬برنامج لتنفيذ جداول التجزئة مع العمليات األساسية على القيم‪.‬‬


‫>‪#include <string‬‬
‫;‪using namespace std‬‬

‫{ ‪struct datar‬‬

‫‪public:‬‬

‫لحمل تعريف وحيد لكل عنصر ‪int id; //‬‬

‫‪107‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫بيانات كل عنصر تم هنا استخدام اعداد صحيحة‪int data; //‬‬

‫;}‬

‫{ ‪class hasher‬‬

‫الجدول الذي سيحمل عناصر جدول التجزئة ‪datar dt[51]; //‬‬

‫عدد العناصر في المصفوفة‪ ,‬لفحص انه مملوء‪int numel; //‬‬

‫‪public:‬‬

‫;)(‪hasher‬‬
‫;)‪int hash(int &id‬‬

‫;)‪int rehash(int &id‬‬

‫;)‪int add(datar &d‬‬

‫;)‪int remove(datar &d‬‬

‫;)(‪void output‬‬

‫;}‬

‫دالة اعطاء ‪ id‬لجدول التجزئة *‪/‬‬

‫من المفضل استخدام رقم اولي لذا استخدم الرقم ‪ 11‬فهو افضل لتقليل التصادم‬

‫‪*/‬‬

‫{ )‪int hasher::hash(int &id‬‬

‫;)‪return (id%51‬‬

‫}‬

‫‪*/‬في حالة حدوث تصادم فسيتم استخدام دالة ‪/* rehash‬‬

‫{ )‪int hasher::rehash(int &id‬‬


C++ ‫هياكل البيانات باستخدام‬

return ((id+1)%51);

hasher::hasher() {

// ‫خلق مصفوفة‬

int i;

for (i=0;i<=50;i++) {

dt[i].id = -1; //‫ لبيان انها فارغة‬1- ‫ الى‬ids ‫ضبط قيمة‬

dt[i].data = 0; //0 ‫تكون افتراضا كل القيم تساوي‬

numel = 0;

int hasher::add (datar &d) {

if (numel < 51) {

// ‫الجول له مواقع فارغة‬

int hashed = hash(d.id);

if (hashed >= 0 && hashed <= 50 && dt[hashed].id == -1) {

//‫الموقع فارغ اسناد قيمة جديدة‬

dt[hashed].id = d.id;

dt[hashed].data = d.data;

return 0;

} else {

// rehash ‫ يحتاج الى‬id

int i=0;

109
C++ ‫هياكل البيانات باستخدام‬

// ‫حاول مع كل موقع في الجدول إليجاد الموقع الفارغ‬

while(i<=50) {

hashed = rehash(hashed);

if(dt[hashed].id == -1) {

dt[hashed].id = d.id;

dt[hashed].data = d.data;

return 0;
} else if (i==50) {

//‫عدم امكانية ايجاد موقع فارغ‬

return -1; // ‫انهاء الدالة بوجود خطأ‬

i++; // i ‫تحديث قيمة‬

} else {

//‫الجدول مملوء‬

return (-1);

int hasher::remove (datar &d) {

int hashed = hash(d.id);

if(dt[hashed].id == d.id) {

// ‫هذا افضل واحد للحذف‬


C++ ‫هياكل البيانات باستخدام‬

dt[hashed].id = -1;

numel -= 1;

return 0;

} else {

//‫ اليجاد واحد‬a rehash ‫نحن نحتاج الى‬

int i=0;

while (i<=50) {

hashed = rehash (hashed);

if (dt[hashed].id == d.id) {

dt[hashed].id = -1; //‫ النها ستصبح فارغة‬1- ‫ الى‬id ‫ ضبط‬empty

numel -= 1; //‫تقليل واحد من عدد العناصر‬

return 0;

//success

} else if (i==50) {

return -1;

// ‫انهاء الدالة‬

i++; // i ‫تحديث قيمة‬

void hasher::output() {

int i;

111
‫هياكل البيانات باستخدام ‪C++‬‬

‫{ )‪for (i=0;i<51;i++‬‬

‫"<<‪cout<<i<<" -> "<<dt[i].id‬‬ ‫;‪"<<dt[i].data<<endl‬‬

‫}‬ ‫}‬

‫{ )(‪int main‬‬

‫اول ‪int id=45; // id‬‬

‫;‪int ret‬‬

‫;‪ret = 0‬‬
‫;‪datar d‬‬

‫قيمة لكل القيود‪ ,‬ببساطة‪d.data = 52005; //‬‬

‫;‪hasher h1‬‬

‫{ )‪while (ret != -1‬‬

‫;‪d.id=id‬‬

‫اضافة هذا القيد للجدول ‪ret = h1.add(d); //‬‬

‫تحديث قيمة ‪ id‬الحظ كيف تختلف قيمة ‪//id += (id/5); // id,‬‬

‫}‬

‫حدث قيمة واحد من ‪ id‬الذي تم اضافته في التكرار اعاله‪d.id = 271861; //‬‬

‫حذف القيد من الجدول‪h1.remove(d); //‬‬

‫‪h1.output(); //‬‬ ‫الحررظ المخرجررات سرريكون قيررد واحررد فررارغ فرري ‪id = 271861‬‬
‫الفهرس او الموقع ‪ 33‬وهو القيد الذي له‬

‫;‪return 0‬‬

‫}‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص الرابع‬
‫المكدس ‪STACK‬‬

‫‪ 4.1‬المقدمة‬
‫المكدس هرو هيكرل مشرابه للقائمرة بحيرث ان عمليرة االضرافة والحرذف ترتم مرن نهايرة‬
‫واحدة‪ .‬هذل القيود تجعل المكدس اقل مرونة من القوائم‪ ،‬لكنهرا ايضرا تجعرل المكردس‬
‫اكثررر كفرراءة (بالنسرربة للعمليررات الترري يقرروم بهررا) وكررذلك سررهل بالتنفيررذ‪ .‬العديررد مررن‬
‫التطبيقررات تتطلررب فقررط نمرروذج تحديرردات عمليررات االضررافة والحررذف الترري يوفرهررا‬
‫المكدس‪ .‬بالرغم من هذل التحديدات فان المكدس له الكثير من التطبيقات‪.‬‬

‫‪ 4.2‬ت ريف المكدس‬


‫هرررو طريقرررة خاصرررة لخرررزن البيانرررات والتعامرررل معهرررا‪ ,‬وهرررو نسرررخة محرررددة مرررن‬
‫المصررفوفات‪ ,‬العناصررر الجديرردة مررن الممكررن ان تضرراف الررى المكرردس او تحررذف مررن‬
‫المكدس من نهاية واحدة‪ ,‬فهو مستودع بيانات‪.‬‬
‫ويتبررع المكرردس هيكليررة الررداخل اوال خررارج اخيرررا ويمكررن ان يمثررل ماديررا كمصررفوفة‬
‫ويدعى حينها هياكل البيانات المستقرة ‪ static data structure‬وعنردها سريرث‬
‫جميع صفات المصفوفات‪ ,‬او من الممكرن ان يمثرل كقائمرة موصرولة ويردعى هياكرل‬
‫البيانات الديناميكيرة ‪ dynamic data structure‬وسريمتلك جميرع خرواص القروائم‬
‫الموصولة وبغض النظر عن طريقة تمثيل المكردس فران عمليرات االضرافة والحرذف‬
‫تحدث في اعلى المكدس فقط‪.‬‬

‫‪113‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :4.1‬نماكج تصف المكدس‬

‫يستخدم عادة المكردس هياكرل البيانرات عنرد كتابرة الشرفرة‪ .‬مبردأ المكردس فري الحقيقرة‬
‫بسرريط‪ ,‬والررذي يجعل ره حتررى ابسررط لكتابررة شررفرتة‪ .‬افرررض هررذل الحالررة‪ ,‬لررديك اربعررة‬
‫قمصرران موضرروعة علررى طاولررة فرروق بعضررها الرربعض (شرركل ‪ )4.1‬فرراذا رغبررت ان‬
‫تضرريف قمرريص خررامس لهررا‪ ,‬فمرراذا تعمررل بكررل تاكيررد ستضررع القمرريص الخررامس فرروق‬
‫القمصرران االربررع‪ ,‬االن مرراذا لررو اردت ان تسررحب القمرريص الثالررث (االبرريض) مررن‬
‫القمصان االربع التي لديك‪ ,‬هنا عليك ان تزيل القميص األعلى يم الرذي بعردل وهكرذا‬
‫لحين ان يصبح القميص الثالث في األعلل ليتسنى لك الحصول عليره ومرن يرم اعرادة‬
‫القمصان التي ازلتهرا الرى مكانهرا وحسرب ترتيبهرا اي ان تضرعها قمريص بعرد االخرر‬
‫(فوق او أعلل القمصان االخرى)‪.‬‬
‫الح هنا‪ ,‬اني اشرت الى كلمة األعلى بحروف غامقة‪ ,‬نعرم الن أعلرى المكردس هرو‬
‫اكثررر كلمررة مهمررة فرري التعامررل مررع المكرردس‪ .‬البيانررات تخررزن فرري المكرردس بحيررث ان‬
‫اضافة البيانات اليسمح بها اال من األعلى فقرط‪ .‬ان اضرافة وحرذف البيانرات اليسرمح‬
‫به اال من أعلى المكدس فقط (االعلى كلمة افتراضية وليس حقيقية)‪.‬‬
‫م حظة‪ :‬لكي اليحدث سوء فهم عندما نقول اعلى المكردس فهرو اليعنري ان المكردس‬
‫وعاء وله اعلى واسفل‪ ,‬المقصود هنا اعلى منطقيا فمثال لو مثلنا المكدس على شركل‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مصفوفة فانك اليمكنك العمل على بداية المصفوفة او الوصرول الرى أي عنصرر فري‬
‫المصفوفة وانما فقط الى اخر عنصر في المصفوفة‪.‬‬

‫‪ 4.3‬ال مليات األساسية التي تجرى علل المكدس‬


‫هنا عدد من العمليات المحددة التي من الممكن ان نتعامل بها مع المكدس وهي‪:‬‬
‫الدفع او االضافة ‪ :Push‬وهي عملية اضافة عنصر جديد الى أعلى المكدس‪.‬‬
‫السحب او الحذف ‪ :Pop‬وهي عملية سحب عنصر من أعلى المكدس‪.‬‬
‫هذل العمليات ( االضافة والحذف) موضحة بالشركل ‪ ,4.2‬حيرث نالحر ان االضرافة‬
‫تتم من اعلى المكدس وعنصر واحد في كل مرة‪ ,‬وكرذلك فران الحرذف يرتم مرن اعلرى‬
‫المكدس‪ ..‬الح هنا في حالة االضافة يجب ان تحدد القيمة المضافة‪ ,‬مرع مراعراة ان‬
‫جميع عناصر المكدس هي من ذات النوع‪ ,‬اما في حالة الحذف فاننا نحذف العنصرر‬
‫الذي في اعلى المكدس بغض النظر عن قيمتة‪.‬‬
‫الح وجود مؤشر يشير الرى موقرع اعلرى عنصرر بالمكردس (يمثرل عنروان العنصرر‬
‫الذي فري اعلرى المكردس بالرذاكرة المخصصرة للمكردس) او هرو يمثرل موقرع العنصرر‬
‫االعلى في المصفوفة‪.‬‬
‫في كرل عمليرة اضرافة او حرذف فران موقرع المؤشرر يجرب ان يتغيرر‪ ,‬تغييرر المؤشرر‬
‫يكررون زيررادة او نقصرران بمقرردار رقررم واحررد‪ .‬فعنرردما تكررون هنررا عمليررة اضررافة فرران‬
‫المؤشر يزاد بمقدار واحد‪ ,‬وفي عملية الحذف يتم انقاص المؤشر بمقدار واحرد‪ .‬فري‬
‫هررذل الحالررة فرران المؤشررر سيؤشررر علررى موقررع اخررر فرري المكرردس الشرركل ‪ 4.3‬يوضررح‬
‫عمليات االضافة والحذف في المكدس‪.‬‬

‫‪115‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :4.2‬يوضح تاثير عمليات السحب واالضافة‬

‫شك ‪ :4.3‬يوضح عمليات االضافة والحذذ من المكدس‪.‬‬


‫‪ 4.4‬تببيقات المكدس‬
‫المكدس له تطبيقات كثيرة‪ .‬ادنال بعض تطبيقات المكدس‪:‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 4.4.1‬عند تنفيذ اي برنامج فان المعرالج سريكون لره الردور االسراس بعمليرة التنفيرذ‪,‬‬
‫لذلك اذا حدث وان تم اسرتدعاء دالرة معينرة فري البرنرامج فران المعرالج سريتوقف عرن‬
‫اكمررال تنفيررذ البرنررامج حسررب تسلسررل االيعررازات او االوامررر فرري البرنررامج ويتفرررع‬
‫الكمال تنفيذ الدالة يم العودة الى ذات الموقرع الرذي تفررع منره الكمرال التنفيرذ حسرب‬
‫تسلسل االيعازات‪ ,‬في هذل الحالة فان المعالج يجب ان تكون له االمكانية للعودة الى‬
‫البرنامج في الموقع الذي تفرع منه لتنفيذ الدالة التي تم استدعائها مع المحافظة على‬
‫جميع القيم الوسطية‪ ,‬لذلك فان العنوان الحرالي للبرنرامج (اي االيعراز الرذي كران مرن‬
‫المفروض ان ينفذ قبل ان يتفرع المعرالج الرى تنفيرذ الدالرة) سريدفع الرى المكردس ليرتم‬
‫حفظة‪ ,‬وعندما ينتهي المعالج من تنفيذ الدالة‪ ,‬فان العنوان الذي تم خزنة سيتم سحبة‬
‫من المكدس ليوجه المعالج اليه الكمال التنفيذ‪ ,‬نفس الشيء بالنسربة للنترائج الوسرطية‬
‫سيتم حفظها ودفعها الى المكدس لكي يتم العمل عليها عند العودة من تنفيذ الدالة‪.‬‬

‫‪ 4.4.2‬المكردس يردعم طريقررة االسرتدعاء الرذاتي‪ .‬والمكرردس يسرتخدم ايضرا بواسررطة‬


‫المترجمات بعملية معالجة او تقييم التعابير وتوليد شفرة لغة الماكنة‪.‬‬

‫‪ 4.4.3‬يستخدم المكدس بشكل كبير في انظمرة الحواسريب الحديثرة‪ ,‬مثرال الحاسربات‬


‫الشخصية الحديثة تستخدم المكدس على مستوى معماريرة الحاسروب‪ ,‬حيرث يسرتخدم‬
‫في التصميم االساس لنظام التشغيل الغراض تنفيرذ المقاطعرة واسرتدعاء دوال نظرام‬
‫التشررغيل‪ ,‬ومررن بررين االسررتخدامات االخرررى‪ ,‬فرران المكرردس يسررتخدم لتشررغيل او تنفي رذ‬
‫ماكنرة جافرا االفتراضرية ‪ Java virtual machine‬ولغرة جافرا نفسرها لرديها صرنف‬
‫يسمى المكدس‪ ,‬والذي من الممكن اسرتخدامة مرن المبررمج‪ .‬المكردس فري كرل مكران‪,‬‬
‫انظمة الحاسروب التري تعتمرد علرى المكردس هري واحردة مرن التري تخرزن المعلومرات‬
‫بشكل مؤقت في المكدس بدال من مسجالت وحدة المعالجة المركزية‪.‬‬

‫‪117‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 4.4.4‬تطبيل اخر للمكدس‪ ,‬نفرض انك تقوم بعمليرة جمرع أعرداد كبيررة جردا‪ ,‬علرى‬
‫سبيل المثال افرض انك ترغب بجمع العددين‬
‫‪o‬‬ ‫‪353,120,457,764,910,452,008,700,786‬‬
‫‪o‬‬ ‫‪234,765,000,129,654,080,277,543‬‬
‫اوال الح التالي انه من الصعب تمثيل اي من العددين كمتغير من نروع االعرداد‬
‫الصحيحة )‪ (long int‬الن هرذا المتغيرر اليمكنرة مرن اسرتيعاب العردد الكبيرر اعرالل‪.‬‬
‫هذل المشكلة باالمكان حلهرا وذلرك بمعاملرة العردد كسلسرلة رمزيرة مرن االرقرام‪ ,‬ويرتم‬
‫خرررزنهم بمكدسرررين‪ ,‬بعررردها تجررررى عمليرررة االضرررافة او الجمرررع بسرررحب ارقرررام مرررن‬
‫المكدسين‪.‬‬

‫‪ 4.4.5‬ايجاد نتيجة تعبير حسابي‪ :‬المكدس مفيد اليجاد نتيجة تعبير حسابي‪ ,‬افرض‬
‫لديك التعبير التالي‬
‫‪5 * 3 +2 + 6 * 4‬‬
‫من ال ممكن ايجاد نتيجة التعبير وذلك بايجاد‪ ,‬اوال نتيجرة حاصرل ضررب ‪ 5‬فري‬
‫‪ , 3‬بعد ذلك تخزن النتيجة في متغير مثال ‪ ,A‬يم قم باضافة الرقم ‪ 2‬الى المتغير ‪A‬‬
‫واخزن النتيجة برالمتغير ‪ .A‬االن اجرري عمليرة الضررب للررقمين ‪ 6‬فري ‪ 4‬واخرزن‬
‫النرراتج بررالمتغير ‪ .B‬عنررد ذلررك سررتنتهي العمليررة باضررافة ‪ A‬الررى ‪ B‬واتررر النتيج رة‬
‫النهائية بالمتغير ‪. A‬‬
‫‪A = 15‬‬ ‫)‪(5×3‬‬
‫‪A = 15 + 2‬‬ ‫)‪(15 + 2‬‬
‫‪= 17‬‬
‫‪B=6×4‬‬ ‫)‪(6 × 4‬‬
‫‪=24‬‬
‫‪A = 17 + 24‬‬ ‫)‪( 17 + 24‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪= 41‬‬
‫هذل الفكرة االولية من الممكن انجازها بسهولة وكفاءة باستخدام المكدس بعرد اجرراء‬
‫بعض التحويرات على التعبير الرياضي‪.‬‬

‫‪ 4.5‬الت ابير الجبرية ‪Algebraic Expression‬‬


‫التعبير الجبري‪ :‬هو ترتيب رياضي يحتوي على معرامالت وعوامرل رياضرية‪ ,‬مثرل‬

‫‪x+y*z‬‬
‫‪ ‬المعامالت‪ :‬هي كميات (وحدة بيانات ) والتي تجرى عليها العمليات الرياضية‪.‬‬
‫والمعامالت ممكرن ان تكرون متغيررات مثرل ‪ x, y, z‬او يوابرت مثرل ‪,2, -1‬‬
‫‪.. 12 ,34‬الا‬
‫‪ ‬العوامررل الرياضرررية‪ :‬هررري رمرروز تررردل علرررى عمليررات رياضرررية او منطقيرررة برررين‬
‫المعامالت‪ ,‬مثال على بعض العوامل الشائعة =< ‪+, ‐, *, /, ^,‬‬
‫واقعا هنا يالث أنواع من التعابير الرياضية‪ .‬وهي‪:‬‬

‫‪ 4.5.1‬ت بير ال مة القياسية ‪ :infix‬وهرذا هرو النروع الرذي اعتردنا علرى التعامرل‬
‫معررره فررري الرياضررريات منرررذ االيرررام االولرررى للمدرسرررة‪ ,‬حيرررث يكرررون موضرررع العامرررل‬
‫الرياضي (العالمة الرياضية) بين المعاملين الذين مرن المفرروض ان تجررى علريهم‬
‫العملية الرياضية وفقا لهذا العامل‪ ,‬مثل‬
‫‪A+B‬‬
‫‪ 4.5.2‬ت بيةر ال مةة ال حقةة ‪ :Postfix‬فري هررذا التعبيرر يكرون العامرل الرياضري‬
‫تابع او الحل الى المعاملين اي بعد المعاملين الذين من المفروض ان تجررى علريهم‬
‫العملية الرياضية وفقا لهذا العامل‪ ,‬مثل‬
‫‪AB+‬‬

‫‪119‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 4.5.3‬ت بيةةر ال مةةة السةةابقة ‪ :Prefix‬هنررا يكررون مكرران العامررل الرياضرري قبررل‬
‫المعاملين الذين من المفروض ان تجرى عليهم العملية الرياضرية وفقرا لهرذا العامرل‪,‬‬
‫مثل‬
‫‪+AB‬‬

‫الحر ان تعبيرر العالمررة القياسري اليمكررن ان تسرتخرج نتيجتررة باسرتخدام ترتيررب‬


‫العوامل الرياضية مرن اليسرار الرى اليمرين داخرل التعبيرر‪ .‬بينمرا العالمرات الرياضرية‬
‫داخل تعبير العالمة الالحقة دائما تكون في مكان التقيريم الصرحيح‪ ,‬عليره فران التقيريم‬
‫او الحسرراب لتعبيررر العالمررة القياسرري ينجررز بخط روتين ‪ ..‬االولررى هررو تحويررل تعبي رر‬
‫العالمة القياسية الى مايكاف ره مرن تعبيرر العالمرة الالحقرة‪ ,‬والخطروة الثانيرة تتضرمن‬
‫حساب تعبير العالمة الالحقرة‪ .‬سروف نررى ذلرك فري هرذا الفصرل‪ ,‬كيرف ان المكردس‬
‫مفيد بالتعامل مع كال الخطوتين بكفاءة‪ ,‬دعنرا اوال نختبرر العمليرة االساسرية للتحويرل‬
‫من تعبير العالمة القياسية الى تعبير العالمة الالحقة ‪.‬‬

‫‪ 4.6‬تحوي ت بير ال مة القياسية الل ت بير ال مة ال حقة‬

‫‪ 4.6.1‬اسباب استالدا ت بير ال مة ال حقة وت بير ال مة السابقة‬


‫بالتاكيررد فرران القرراريء ربمررا يتسررائل لمرراذا نسررتخدم هررذا الشرركل الغريررب مررن تعررابير‬
‫العالمة السابقة والعالمة الالحقة‪.‬‬
‫عندما يكون لدينا تعبير عالمة قياسية بسيط‪ ,‬فسيكون من المفاجأ ان تعرف ان تعبير‬
‫العالمة القياسية ليس بسيط كما يبدو‪ ,‬خصوصا عندما ترغب بايجاد نتيجتة‪ .‬لغرض‬
‫حساب قيمة تعبير العالمة القياسية فانرك تحتراج الرى االعتمراد علرى افضرلية العوامرل‬
‫والصفات المشتركة معة‪ ,‬مثال‪:‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫التعبيرررر )‪ (3+5*4‬مرررن الممكرررن ايجررراد نتيجتررره علرررى انررره يسررراوي ‪ 32‬وهرررو يعنررري‬
‫)‪ ,((3+5)*4‬او مرررن الممكرررن لشرررخص اخرررر يجرررد نتيجتررره علرررى انهرررا ‪ 23‬بمعنرررى‬
‫))‪ .(3+(5*4‬السؤال هو اي من هاتين النتيجتين هي الصحيحة‪.‬‬
‫ولحل هذل المشكلة فان استخدام العوامل الرياضية المرافقة للتعبير الرياضري سروف‬
‫اليكون اختياريا او عشوائيا وانما يخضع لضوابط وقواعد تمثل اسبقية استخدام كرل‬
‫عامل رياضي في التعبير‪ .‬ان اسبقية العوامرل ترتحكم بترتيرب وتنظريم عمليرة حسراب‬
‫النتائج للعمليات الحسابية المختلفة ضمن التعبير الحسابي الواحد‪.‬‬
‫القاعدة ال امةة تشرير الرى ان العامرل ذو االسربقية االعلرى يرتم حسرابة او تطبيقرة قبرل‬
‫العامل ذو االسبقية االوطأ‪.‬‬
‫ان استخدام هذل االسربقيات فري الحاسروب سريولد نروع مرن التعقيرد ولرذلك فران تعبيرر‬
‫العالمررة القياسرري مررن الصررعب تحليلررة‪ ,‬النرره يحترراج الررى تحديررد افضررلية العوامررل‪,‬‬
‫المحددات‪ ,‬وكسر التعادل (اي عنردما يكرون عراملين برنفس االفضرلية)‪ ,‬وهرذا يجعرل‬
‫تقييم الحاسوب للتعبير صعب اكثر من الالزم‪.‬‬
‫هذا التعقيد من الممكن تجاوزل عنرد اسرتخدام تعبيرر العالمرة السرابقة وتعبيرر العالمرة‬
‫الالحقة النهما اليعتمدان على افضرلية العوامرل‪ ,‬المحرددات‪ ,‬وكسرر التعرادل‪ .‬لرذا فران‬
‫تقييم التعابير بهذل الصيغ يكون اسهل‪.‬‬

‫دول ‪ : 4.1‬يوضح اسبقية ال وام الرياضية والمنبقية في الحاسوب‬

‫االفضلية الم حظـــــــــــــــــــــــــــــــات‬ ‫ال وامـــــــــــــ‬

‫^ تعني الرفع الى اس معين‪ ,‬اما العوامل االحادية فهي‬ ‫كررل العوامررل االحاديررة‪6 ,‬‬

‫تعني العوامل الرياضية التي تسبل معامل واحد فقط مثل‬ ‫^‬

‫‪121‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫(‪.)-7‬‬

‫(‪ )%‬تشير الى باقي القسمة‬ ‫‪5‬‬ ‫‪% ,‬‬ ‫*‬ ‫‪, /‬‬

‫الثنائيررة تعنرري انهررا تسررتخدم معرراملين واحررد قبررل العامررل‬ ‫‪4‬‬ ‫‪ - , +‬الثنائية‬
‫الرياضي واالخر بعدل مثل (‪.)12 + 4‬‬

‫تمثل العالمات المنطقية فقط‬ ‫‪3 = =, <,‬‬ ‫‪>, <=,‬‬


‫=! ‪>=,‬‬

‫النفي في العالمات المنطقية‬ ‫‪2‬‬ ‫) ! ( ‪Not‬‬

‫عالمتي ‪and, or‬‬ ‫‪1‬‬ ‫‪&&,‬‬ ‫||‬

‫المساواة التي تستخدم باسناد قيمة معينة الى متغير‬ ‫‪0‬‬ ‫=‬

‫‪ 4.6.2‬ووارزمية تحوي ت بير ال مة القياسي الل ت بير ال مة ال حقة‬

‫يعامل تعبير العالمة القياسري علرى انره سلسرلة مرن الرمروز (معرامالت وعوامرل‬ ‫‪.1‬‬
‫رياضية) ويتم فحصها او قرراءة هرذل الرمروز واحرد بعرد االخرر مرن اليسرار الرى‬
‫اليمرررررين (يعتبرررررر تعبيرررررر العالمرررررة القياسرررررية هرررررو المررررردخل ويخرررررزن بسلسرررررلة‬
‫رمزية )‪.) (string‬‬
‫يررتم اسررتخدام المكرردس كخررزان وسررطي (يكررون المكرردس ابتررداءا فررار )‪ ,‬وسلسررلة‬ ‫‪.2‬‬
‫رمزية للمخرجات تكون بداية خالية من اي رمز‪.‬‬
‫افحص العنصر الالحل بالمدخالت (اي ضمن تعبير العالمة القياسية)‪.‬‬ ‫‪.3‬‬
‫اذا كان هذا العنصر معامل (متغير او يابت) يتم وضرعة فري سلسرلة المخرجرات‬ ‫‪.4‬‬
‫مباشرة‪.‬‬
‫اذا كان قوس مفتوح يتم دفعة الى المكدس‪.‬‬ ‫‪.5‬‬
‫اذا كان عامل رياضي قم بمايلي‪:‬‬ ‫‪.6‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ )a‬اذا كان المكدس فار ادفع العامل الى المكدس‪ .‬اذهب الى الخطوة ‪7‬‬
‫‪ )b‬اذا كان ماموجود باعلى المكدس هو قوس مفتوح ادفع العامل الرى المكردس‪.‬‬
‫اذهب الى الخطوة ‪.7‬‬
‫‪ )c‬اذا كان هذا العامل له اسبقية اعلرى مرن العامرل فري اعلرى المكردس ادفرع هرذا‬
‫العامل الى المكدس‪ .‬اذهب الى الخطوة ‪.7‬‬
‫‪ )d‬اذا كان هذا العامل له اسبقية اوطأ مرن العامرل الموجرود فري اعلرى المكردس‪,‬‬
‫في هذل الحالة اسحب العامل مرن اعلرى المكردس واخرجرة ليرتم وضرعة فري‬
‫سلسلة المخرجات‪ ,‬اذهب الى الخطوة ‪ a‬في بداية الفقرة ‪6‬‬
‫‪ .7‬اذا كان قوس مغلل اسحب العوامرل مرن المكردس واحرد بعرد االخرر‪ ,‬وكرل عامرل‬
‫يتم سحبه يوضع في سلسلة المخرجات واحد بعد االخر‪ ,‬لحين تصل الى القوس‬
‫المفترروح‪ .‬عمليررة السررحب سررتهمل القرروس المفترروح‪( .‬عمليررة االضررافة الررى سلسررلة‬
‫المخرجات هي عملية جمع )‪) (concatenation‬‬
‫‪ .8‬اذا كان هنا مزيد من المدخالت اذهب الى الخطوة ‪.3‬‬
‫‪ .9‬اذا لررم يكررن هنررا مزيررد مررن المرردخالت‪ ,‬اسررحب العوامررل المتبقيررة فرري المكرردس‬
‫واضفهم الى سلسلة المخرجات (واحد بعد االخر)‪.‬‬

‫‪ 4.6.3‬امث لرررة لتحويرررل تعبيرررر العالمرررة القياسررري الرررى تعبيرررر العالمرررة الالحقرررة (هنرررا‬
‫باستخدام االسبقيات وليس المكدس)‬

‫مثال ‪ :1‬ت بير ال مة القياسية ‪a + b * c‬‬


‫)‪a + (b * c‬‬ ‫اسبقية عامل الضرب اكبر من اسبقية عامل الجمع ‪//‬‬
‫)*‪a+(bc‬‬ ‫تحويل الضرب الى تعبير العالمة الالحقة ‪//‬‬
‫‪a (b c * ) +‬‬ ‫تحويل الجمع الى تعبير العالمة الالحقة ‪//‬‬
‫‪abc*+‬‬ ‫ازالة االقواس ‪//‬‬
‫شك ت بير ال مة ال حقة ‪a b c * +‬‬

‫‪123‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫م حظة‪ :‬التوجد حاجة الى االقواس في تعبير العالمة الالحقة‪ ,‬أي ان تعبير العالمة‬
‫الالحقة اليحتوي اقواس‪.‬‬

‫مثال ‪ :2‬ت بير ال مة القياسية ‪( A + B ) * C‬‬


‫الح هنا ان اسبقية االقرواس اكبرر مرن اسربقية العمليرات االخررى (اكبرر مرن اسربقية‬
‫عامل الضرب)‪ ,‬لذلك سيكون داخل القوس له اسبقة عليا‪.‬‬
‫‪(AB+)*C‬‬ ‫تحويل الجمع الى تعبير العالمة الالحقة ‪//‬‬
‫* ‪(A B + ) C‬‬ ‫تحويل الضرب الى تعبير العالمة الالحقة ‪//‬‬
‫*‪AB+C‬‬ ‫ازالة االقواس ‪//‬‬
‫*‪AB+C‬‬ ‫شك ت بير ال مة ال حقة‬
‫الحاجة لالقواس باي شكل من االشكال‬

‫مثال ‪ :3‬تعبير العالمة القياسية ( ‪a + (b * c / d‬‬


‫بدايررة فرران االسرربقة لالقررواس‪ ,‬داخررل االقررواس هنررا عمليترران الضرررب والقسررمة‪ ,‬ان‬
‫اسبقية عالمة الضرب وعالمة القسرمة متسراويتان (عنرد تسراوي عالمترين باالسربقية‬
‫فان العالمة التي على اليسار تنفذ اوال)‪,‬‬
‫) ‪a + (b c * /d‬‬ ‫تحويل الضرب الى تعبير العالمة الالحقة ‪//‬‬
‫)‪a+(bc*d/‬‬ ‫تحويل القسمة الى تعبير العالمة الالحقة ‪//‬‬
‫‪a (b c * d /) +‬‬ ‫تحويل الجمع الى تعبير العالمة الالحقة ‪//‬‬
‫‪abc*d/+‬‬ ‫‪//‬‬ ‫ازالة االقواس‬

‫مثةةال ‪ :4‬مثررال توضرريحي لكيفيررة تنفيررذ خوارزميررة تحويررل تعبيررر العالمررة القياسررية‬
‫باستخدام المكدس‪:‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪a+b*c-d‬‬ ‫تعبيررررررررررررررررررر العالمررررررررررررررررررة القياسررررررررررررررررررية‬

‫ابتداءا فان المكدس يكون فار وسلسلة التعبير الالحل ليس فيهرا اي رمروز كمرا فري‬
‫الشكل ‪.4.4‬‬

‫شك ‪ :4.4‬وضع المكدس وسلسلة المالر ات والمدو ت في بداية التنفيذ‪.‬‬

‫االن‪ ,‬الرمز االول الذي يتم فحصه هرو ’‪ ‘a‬والرذي سرتتم اضرافتة الرى سلسرلة تعبيرر‬
‫العالمة الالحقة (النه ليس عالمة رياضية) الح الشكل ‪.4.5‬‬

‫شك ‪ :4.5‬وضع المكدس ب د قراءة الرمز االول‪.‬‬

‫الرمز الثراني الرذي يرتم فحصرة هرو عالمرة الجمرع ’‪ ‘+‬وهرذا برالطبع عامرل رياضري‬
‫والعوامل الرياضية تضاف الى المكدس‪ ,‬الشكل ‪ 4.6‬يوضح النتيجة‪.‬‬

‫‪125‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الشك ‪ :4.6‬وضع المكدس ب د قراءة الرمز الثاني‬

‫الرمررز التررالي الررذي سرريتم قرائتررة هررو الرمررز ’‪ ‘b‬والررذي سيوضررع فرري سلسررلة تعبيررر‬
‫العالمة الالحقة‪ .‬بعدها يكون الدور للرمز الذي سيتم قرائته هو عالمة الضررب ’*‘‬
‫والذي هو عامل رياضي‪ .‬االن هذا يجب ان يودع في المكدس ويجرب ان نالحر ان‬
‫اعلررى المكرردس يحترروي العامررل الرياضرري ’‪ ‘+‬والررذي هررو ذو اسرربقية اقررل مررن عامررل‬
‫الضرب‪ ,‬لذلك فان عامل الضرب سيدفع الرى اعلرى المكردس‪ ,‬الحر وضرع المكردس‬
‫في الشكل ‪.4.7‬‬

‫شك ‪ :4.7‬وضع المكدس وسلسلة المالر ات ب د قراءة رمزين اضافيين‪.‬‬

‫الرمز الالحل هو ’‪ ‘c‬والذي سيوضع في تعبير العالمة الالحقة‪ ,‬شكل ‪.4.8‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :4.8‬المكدس ب د اضافة الرمز ‪c‬‬

‫الرمز االخر الذي سيتم قرائته هو عالمة الطرح ‘‪ ‘-‬وهذا عامل رياضي المفروض‬
‫ان يوضع في المكدس‪ ,‬الح ان اعلى المكدس يحتروي عالمرة الضررب ’*‘ والرذي‬
‫هو ذو اسبقية اعلى من عامل الطرح ونظرا لعدم امكانية ان يوضرع عامرل رياضري‬
‫ذو اسرربقية دنيررا فرروق عامررل رياضرري ذو اسرربقية اعلررى فرري المكردس‪ ,‬لررذا سرريتم سررحب‬
‫العامل ’*‘ من المكردس ويضراف الرى سلسرلة تعبيرر العالمرة الالحقرة (المخرجرات)‪.‬‬
‫حتى االن فان المكدس ليس فار ‪ .‬االن بعد سحب عالمة الضرب فان عالمة الجمع‬
‫’‪ ‘+‬هي في اعلى المكدس وهذا العامرل مسراوي باالسربقية لعامرل الطررح‪ ,‬ولرذا فران‬
‫عاملين متساويين باالسبقية اليمكن ان يكونا احردهما فروق االخرر مباشررة بالمكردس‪,‬‬
‫لررذا فرران العامررل ’‪ ‘+‬يسررحب ايضررا مررن المكرردس ويوضررع فرري سلسررلة تعبيررر العالمررة‬
‫الالحقة‪ ,‬عند ذا يتم دفع العامل ‘‪ ‘-‬الى المكدس‪ ,‬الح الشكل ‪.4.9‬‬

‫شك ‪ : 4.9‬وضع المكدس ب د اضافة ال مة )‪(-‬‬

‫الرمز الذي سيقرا االن هو الرمز ’‪ ‘d‬والرذي سيضراف الرى تعبيرر العالمرة الالحقرة‪,‬‬
‫وبعد قراءة الرمز ‪ d‬نكون قد قرأنا جميع الرمروز فري تعبيرر العالمرة القياسرية وبهرذا‬
‫وصررلنا الررى حالررة هرري عرردم وجررود اي رمررز اخررر لررم يررتم قرائتررة وعليررة فرران جميررع‬
‫العناصرر الموجررودة فرري المكرردس سرريتم سررحبها واحرد بعررد االخررر‪ ,‬وتررتم اضررافتها الررى‬

‫‪127‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫سلسلة تعبير العالمة الالحقة بالتعاقرب‪ .‬فيرتم هنرا سرحب عامرل الطررح ويضراف الرى‬
‫سلسررلة تعبيررر العالمررة الالحقررة‪ .‬لررذا بعررد ان يررتم قررراءة جميررع الرمرروز فرران المكرردس‬
‫وسلسلة تعبير العالمة الالحقة سيكونان كما في الشكل ‪.4.10‬‬

‫شك ‪ :4.10‬وضع المكدس ب د قراءة اور رمز‪.‬‬

‫النتيجة النهائية ستكون‪:‬‬

‫‪ abc*+d-‬سلسلة تعبير العالمة الالحقة‬ ‫‪‬‬

‫تمرين ‪ :1‬حول تعبير العالمة القياسية في االمثلة التالية الرى تعبيرر العالمرة الالحقرة‬
‫باستخدام االسبقيات واستخدام المكدس‪ ( .‬االجوبة في نهاية الفصل)‬
‫‪1.‬‬ ‫)‪(a + b) * (c – d‬‬
‫‪2.‬‬ ‫)‪a – b / (c + d * e‬‬
‫‪3.‬‬ ‫)‪((a + b) * c – (d – e))/(f + g‬‬

‫مثال ‪ :5‬مطلوب تحويل تعبيرر العالمرة القياسري ‪ 2*3/(2-1)+5*3‬الرى تعبيرر‬


‫العالمة الالحقة باستخدام المكدس؟‬

‫‪2*3/(2-1)+5*3‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫المكدس عناصر ت بير ال مة القياسية‬ ‫سلسلة المالر ات‬


‫(المدو ت)‬ ‫ت بير ال مة ال حقة‬
‫‪2‬‬ ‫فار‬ ‫‪2‬‬
‫*‬ ‫*‬ ‫‪2‬‬
‫‪3‬‬ ‫*‬ ‫‪23‬‬
‫‪/‬‬ ‫‪/‬‬ ‫*‪23‬‬
‫(‬ ‫(‪/‬‬ ‫*‪23‬‬
‫‪2‬‬ ‫(‪/‬‬ ‫‪23*2‬‬
‫‪-‬‬ ‫‪/(-‬‬ ‫‪23*2‬‬
‫‪1‬‬ ‫‪/(-‬‬ ‫‪23*21‬‬
‫)‬ ‫‪/‬‬ ‫‪23*21-‬‬
‫‪+‬‬ ‫‪+‬‬ ‫‪23*21-/‬‬
‫‪5‬‬ ‫‪+‬‬ ‫‪23*21-/5‬‬
‫*‬ ‫*‪+‬‬ ‫‪23*21-/5‬‬
‫‪3‬‬ ‫*‪+‬‬ ‫‪23*21-/53‬‬
‫فار‬ ‫‪23*21-/53*+‬‬
‫تعبير العالمة الالحقة‬ ‫‪23*21-/53*+‬‬

‫‪ 4.7‬حساب (ايجا نتيجة) ت بير ال مة ال حقة‬


‫باالمكان حساب نتيجة تعبير العالمة الالحقة باسرتخدام المكردس‪ .‬خوارزميرة حسراب‬
‫نتيجة تعبير العالمة الالحقة هي‪:‬‬
‫‪ .1‬ابدأ بمكدس فار ‪.‬‬

‫‪129‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫تعبير العالمرة الالحقرة يتكرون عرادة مرن معرامالت وعوامرل رياضرية‪ ,‬باالمكران‬ ‫‪.2‬‬
‫اعتبارهررا كسلسررلة مررن الرمرروز‪ ,‬يررتم قرائتهررا او فحصررها مررن اليسررار الررى اليمرين‬
‫تباعا‪.‬‬
‫يتم قراءة رمز واحد من السلسلة في كل مرة‪.‬‬ ‫‪.3‬‬
‫اذا كان الرمز هو معامل يتم دفعة الى داخل المكدس‪.‬‬ ‫‪.4‬‬
‫اذا كان الرمز عامل رياضي‪ ,‬عندها يتم مايلي‪:‬‬ ‫‪.5‬‬
‫‪ )a‬سررحب اينررين مررن المعررامالت مررن اعلررى المكرردس (اي المعامررل االعلررى فرري‬
‫المكدس والمعامل الذي يليه)‪.‬‬
‫‪ )b‬اجررراء العمليررة الحسررابية علررى المعرراملين الررذين تررم سررحبهما ووفقررا للعام رل‬
‫الرياضي الذي تم قرائتة‪.‬‬
‫‪ )c‬يتم دفع النتيجة المستحصلة من الخطوة ‪ b‬الى داخل المكردس (توضرع عرادة‬
‫في اعلى المكدس)‬
‫اذا لم تكن السلسلة فارغة االنتقال الى الخطوة ‪.3‬‬ ‫‪.6‬‬

‫مثال ‪ :6‬مثال توضيحي اليجاد نتيجة تعبير العالمة الالحقة التالي‪:‬‬


‫*‪6523+8*+3+‬‬
‫الحةةة ‪ :‬يرررتم التعامرررل مرررع تعبيرررر العالمرررة الالحقرررة علرررى انررره سلسرررلة مرررن الرمررروز‬
‫(الشكل ‪ 4.11‬سيسراعد علرى متابعرة الحرل)‪ ,‬وفري كرل مررة يقررأ احرد هرذل الرمروز‬
‫وذلررك مررن اليسررار الررى اليمررين‪ .‬اوال يقرررأ الرررقم ‪ 6‬ويرردفع الررى داخررل المكرردس الفررار‬
‫(االرقررام (المعررامالت) ترردفع الررى المكرردس) بعرردها يرراتي الرررقم ‪ 5‬فيرردفع الررى المكرردس‬
‫ايضا‪ ,‬يم يراتي الررقم ‪ 2‬ويردفع الرى المكردس ايضرا حسرب القاعردة‪ ,‬الرمرز االخرر هرو‬
‫الرقم ‪ 3‬ويدفع ايضا الى المكردس‪ ,‬بعرد دفرع الررقم ‪ 3‬الرى المكردس نصرل الرى عالمرة‬
‫الجمع وكما اسلفنا ان العوامل الرياضية ال تردفع الرى المكردس ومايحردث هرو ان يرتم‬
‫سحب رقمين من اعلى المكدس واجراء هذل العملية الرياضية عليهما‪ ,‬هنا في اعلرى‬
‫المكدس الرقم ‪ 3‬وبعدة الرقم ‪ 2‬يتم سحبهما من المكدس وتجرى عليهم عملية الجمرع‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫ليكون الناتج ‪ 5‬هذا الناتج يعاد دفعة الرى المكردس وطبعرا سريكون فري اعلرى المكردس‬
‫(الخطوة ‪ ,)5‬تستمر عملية قراءة رموز تعبيرر العالمرة الالحقرة فنقررأ الررقم ‪ 8‬وهرذا‬
‫رقررم فيرردفع الررى المكرردس كمررا فرري الخطرروة (‪ )6‬فرري الشرركل‪ ,4.11‬بعرردها نقرررأ عالمررة‬
‫الضرب وبهذا يتم سحب رقمين من اعلى المكدس وهما الرقم ‪ 8‬والذي يلية الررقم ‪5‬‬
‫لتتم عليهم عملية الضرب ويكون الناتج ‪ 40‬الذي يدفع الى اعلى المكدس (خطوة ‪)7‬‬
‫فرري الشرركل ‪ 4.11‬تسررتمر عمليررة قررراءة رمرروز تعبيررر العالمررة الالحقررة حيررث عالمررة‬
‫الجمع عندها يسحب اعلى رقمين وهرم ‪ 40‬والررقم ‪ 5‬وتجررى عمليرة الجمرع والنراتج‬
‫هو ‪ 45‬يدفع الى اعلى المكدس‪ ,‬بعدها يتم قراءة الرقم ‪ 3‬ويدفع الى اعلى المكدس يم‬
‫نقرأ عالمرة الجمرع ونسرحب الررقم ‪ 45‬والررقم ‪ 3‬مرن اعلرى المكردس وتجررى علريهم‬
‫عمليررة الجمررع ليكررون النرراتج ‪ 48‬يرردفع الررى اعلررى المكرردس (الخطرروة ‪ )10‬فرري الشرركل‬
‫‪ ,4.11‬واخيرررا تررتم عمليررة قررراءة عامررل الضرررب ويررتم سررحب الرررقم ‪ 48‬والرررقم ‪6‬‬
‫الجراء عملية الضرب وينتج الرقم ‪ 288‬الذي يدفع الى المكدس وبهذا تنتهي العملية‬
‫الرياضية نظرا النتهاء جميع رموز تعبير العالمة الالحقة‪ ,‬ولم يبقى بالمكدس سوى‬
‫الناتج الذي هو ‪.288‬‬
‫العملية تتوقف عندما تنتهي جميع العوامل الرياضية والمعامالت في السلسلة (تعبير‬
‫العالمة الالحقة)‪ ,‬نتيجة حساب التعبير المتحصلة يرتم سرحبها مرن المكردس وسرتكون‬
‫هي الوحيدة في المكدس اي معامل واحد يبقى بالمكدس‪.‬‬

‫‪131‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :4.11‬وبوات ح المثال ‪.6‬‬

‫مثال ‪ : 7‬مثال اخر توضيحي اليجاد نتيجة تعبير العالمة الالحقة باسرتخدام المكردس‬
‫للتعبير‪:‬‬
‫‪623+-382/+*2^3+‬‬

‫تكون البداية باستخدام مكدس فار ‪.‬‬

‫‪623+-382/+*2^3+‬‬

‫الم حظات‬ ‫المكدس‬ ‫الرمز‬

‫معامل يدفع الى المكدس‬ ‫‪6‬‬ ‫‪6‬‬

‫معامل يدفع الى المكدس‬ ‫‪6, 2‬‬ ‫‪2‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫معامل يدفع الى المكدس‬ ‫‪6, 2, 3‬‬ ‫‪3‬‬

‫عامررل رياضرري‪ ,‬يررتم سررحب اعلررى معرراملين مررن المكرردس‪ ,‬وتجرررى‬ ‫‪6, 5‬‬ ‫‪+‬‬
‫علرريهم العمليررة الرياضررية وفقررا للعامررل الرياضرري هنررا عمليررة جمررع‬
‫)‪ (2+3‬يم تعاد النتيجة (‪ )5‬الى اعلى المكدس‬

‫عامل‪ ,‬يسحب اعلى معاملين ويجرى عليهم عملية الطرح‬ ‫‪1‬‬ ‫‪-‬‬

‫)‪ (6-5‬وتدفع النتيجة (‪ )1‬الى اعلى المكدس‬

‫معامل يدفع الى المكدس‬ ‫‪1, 3‬‬ ‫‪3‬‬

‫معامل يدفع الى المكدس‬ ‫‪1, 3, 8‬‬ ‫‪8‬‬

‫معامل يدفع الى المكدس‬ ‫‪1, 3, 8, 2‬‬ ‫‪2‬‬

‫عامل القسمة‪ ,‬يسحب اعلى معاملين بالمكدس وتجرى عليهم القسمة‬ ‫‪1, 3, 4‬‬ ‫‪/‬‬
‫)‪ (8/2‬وتدفع النتيجة (‪ )4‬الى اعلى المكدس‪.‬‬

‫م حظةةة‪ :‬الم امةة االول الةةذي يسةةحب مةةن المكةةدس يوضةةع ب ةةد‬
‫ال ام الرياضي بينما الم ام الثاني يوضع قب ال ام الرياضي‪.‬‬

‫جمع المعاملين )‪ (3+4‬ودفع النتيجة (‪ )7‬الى اعلى المكدس‬ ‫‪1, 7‬‬ ‫‪+‬‬

‫عمليررة ضرررب العلررى معرراملين بالمكرردس )‪ (7*1‬ودفررع النتيجررة (‪)7‬‬ ‫‪7‬‬ ‫*‬
‫الى اعلى المكدس‬

‫معامل يدفع الى المكدس‬ ‫‪7, 2‬‬ ‫‪2‬‬

‫عامل الرفرع (اس) العلرى معراملين بالمكردس )‪ (7^2‬وتردفع النتيجرة‬ ‫‪49‬‬ ‫^‬
‫(‪ )49‬الى اعلى المكدس‬

‫معامل يدفع الى المكدس‬ ‫‪49, 3‬‬ ‫‪3‬‬

‫اجرراء عمليررة الجمرع علررى اعلرى معرراملين بالمكردس (‪ )3+49‬ودفررع‬ ‫‪52‬‬ ‫‪+‬‬
‫النتيجة (‪ )52‬الرى اعلرى المكردس‪ ,‬وهري اخرر عمليرة وتمثرل النتيجرة‬
‫النهائية‪.‬‬

‫‪133‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫نتيجة حساب تعبير العالمة الالحقة‬ ‫‪52‬‬

‫مثال ‪ :8‬تحويل تعبير العالمة القياسي ‪ 1+2*3^4/5-6‬الى تعبير العالمة الالحقة‬


‫باستخدام المكدس‪.‬‬

‫‪1+2*3^4/5-6‬‬

‫المكدس رموز ت بير ال مةالقياسية‬ ‫سلسلة المالر ات‬

‫(المدو ت)‬ ‫ت بير ال مة ال حقة‬

‫‪1‬‬ ‫‪1‬‬

‫‪+‬‬ ‫‪+‬‬ ‫‪1‬‬

‫‪2‬‬ ‫‪+‬‬ ‫‪12‬‬

‫*‬ ‫*‪+‬‬ ‫‪12‬‬

‫‪3‬‬ ‫*‪+‬‬ ‫‪123‬‬

‫^‬ ‫^*‪+‬‬ ‫‪123‬‬

‫‪4‬‬ ‫^*‪+‬‬ ‫‪1234‬‬

‫‪/‬‬ ‫‪+*^/‬‬ ‫‪1234‬‬

‫‪+*/‬‬ ‫^‪1234‬‬

‫‪+/‬‬ ‫*^‪1234‬‬

‫‪5‬‬ ‫‪+/‬‬ ‫‪1234^*5‬‬

‫‪-‬‬ ‫‪+/-‬‬ ‫‪1234^*5‬‬

‫‪+-‬‬ ‫‪1234^*5/‬‬

‫‪-‬‬ ‫‪1234^*5/+‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪6‬‬ ‫‪-‬‬ ‫‪1234^*5/+6‬‬

‫تعبير العالمة الالحقة‬ ‫فار‬ ‫‪1234^*5/+6-‬‬

‫مثال ‪ :9‬حول تعبير العالمة القياسي ‪ 1-(2+3)*4‬الى تعبير العالمة الالحقرة‬


‫باستخدام المكدس‪.‬‬

‫‪1-(2+3)*4‬‬

‫المكدس رموز ت بير ال مة القياسية‬ ‫سلسلة المالر ات‬

‫(المدو ت)‬ ‫ت بير ال مة ال حقة‬

‫‪1‬‬ ‫‪1‬‬

‫‪-‬‬ ‫‪-‬‬ ‫‪1‬‬

‫)‬ ‫(‪-‬‬ ‫‪1‬‬

‫‪2‬‬ ‫(‪-‬‬ ‫‪12‬‬

‫‪+‬‬ ‫‪-(+‬‬ ‫‪12‬‬

‫‪3‬‬ ‫‪-(+‬‬ ‫‪123‬‬

‫)‬ ‫(‪-‬‬ ‫‪123+‬‬

‫‪-‬‬ ‫‪123+‬‬

‫*‬ ‫*‪-‬‬ ‫‪123+‬‬

‫‪4‬‬ ‫*_‬ ‫‪123+4‬‬

‫‪-‬‬ ‫*‪123+4‬‬

‫تعبير العالمة الالحقة‬ ‫فار‬ ‫‪123+4*-‬‬

‫‪135‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مثال ‪ :10‬حول تعبير العالمة القياسي ))‪ (4+8)*(6-5)/((3-2)*(2+2‬الى تعبيرر‬


‫العالمة الالحقة‪.‬‬

‫))‪(4+8)*(6-5)/((3-2)*(2+2‬‬

‫المكدس عناصر ت بير ال مة القياسي‬ ‫سلسلة المالر ات‬

‫(المدو ت)‬ ‫ت بير ال مة ال حقة‬

‫(‬ ‫(‬

‫‪4‬‬ ‫(‬ ‫‪4‬‬

‫‪+‬‬ ‫‪(+‬‬ ‫‪4‬‬

‫‪8‬‬ ‫‪(+‬‬ ‫‪48‬‬

‫)‬ ‫‪48+‬‬

‫*‬ ‫*‬ ‫‪48+‬‬

‫(‬ ‫(*‬ ‫‪48+‬‬

‫‪6‬‬ ‫(*‬ ‫‪48+6‬‬

‫‪-‬‬ ‫‪*(-‬‬ ‫‪48+6‬‬

‫‪5‬‬ ‫‪*(-‬‬ ‫‪48+65‬‬

‫)‬ ‫*‬ ‫‪48+65-‬‬

‫‪/‬‬ ‫‪*/‬‬ ‫‪48+65-‬‬

‫‪/‬‬ ‫*‪48+65-‬‬

‫(‬ ‫(‪/‬‬ ‫*‪48+65-‬‬

‫(‬ ‫((‪/‬‬ ‫*‪48+65-‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪3‬‬ ‫((‪/‬‬ ‫‪48+65-*3‬‬

‫‪-‬‬ ‫‪/((-‬‬ ‫‪48+65-*3‬‬

‫‪2‬‬ ‫‪/((-‬‬ ‫‪48+65-*32‬‬

‫)‬ ‫(‪/‬‬ ‫‪48+65-*32-‬‬

‫*‬ ‫*(‪/‬‬ ‫‪48+65-*32-‬‬

‫(‬ ‫(*(‪/‬‬ ‫‪48+65-*32-‬‬

‫‪2‬‬ ‫(*(‪/‬‬ ‫‪48+65-*32-2‬‬

‫‪+‬‬ ‫‪/(*(+‬‬ ‫‪48+65-*32-2‬‬

‫‪2‬‬ ‫‪/(*(+‬‬ ‫‪48+65-*32-22‬‬

‫)‬ ‫*(‪/‬‬ ‫‪48+65-*32-22+‬‬

‫)‬ ‫‪/‬‬ ‫*‪48+65-*32-22+‬‬

‫تعبير العالمة الالحقة‬ ‫‪ 48+65-*32-22+*/‬فار‬

‫االن لو اردنا ان نحول تعبير العالمة الالحقة الى تعبير العالمة القياسي‪ .‬ترتم بعمليرة‬
‫بسيطة وهي مشابهة جدا الى عملية ايجاد ناتج تعبير العالمة الالحقة‪ ,‬الفارق هو في‬
‫ايجرراد النرراتج عنرردما نقرررا عالمررة رياضررية كنررا نسررحب اعلررى عنصرررين فرري المكرردس‬
‫وتجرى عليهم العملية الرياضية يرم يردفع النراتج الرى اعلرى المكردس‪ ,‬فري هرذل الحالرة‬
‫لغرض التحويل الى العالمة القياسة نعمل نفرس الشريء عنردما نقررا عالمرة رياضرية‬
‫نسحب اعلى عنصرين في المكدس ونضع العالمرة بينهمرا يرم نردفع هرذل النتيجرة الرى‬
‫اعلى المكدس‪ ..‬هذا الموضوع سيكون اكثر وضوحا عند متابعة المثال ‪.11‬‬

‫مثال ‪ : 11‬تحويل تعبير العالمة الالحقة الى تعبير العالمة القياسية‬


‫*–‪ab–c/de+f‬‬

‫‪137‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫*–‪ab–c/de+f‬‬

‫عناصةةر ت بيةةر‬ ‫المكدس‬ ‫الم حظات‬


‫ال مةةةةةةةةةةةةةةةةةةة‬
‫ال حقة‬

‫‪a‬‬ ‫‪a‬‬ ‫معامل يدفع الى المكدس‬

‫‪b‬‬ ‫‪a,b‬‬ ‫معامل يدفع الى المكدس‬

‫‪-‬‬ ‫عامررل رياضرري يررتم سررحب اعلررى عنصرررين بالمكرردس‬


‫وهمررا ‪ a, b‬ووضررع العالمررة الرياضررية بينهمررا‪ ,‬يرردفع‬
‫الناتج الى المكدس‬

‫تعتبر النتيجة عنصر واحد عند دفعها الى المكدس لذا )‪(a-b‬‬
‫توضررع بررين قوسررين للتعامررل معهررا علررى انهررا عنصررر‬
‫واحد‬

‫‪c‬‬ ‫‪(a-b),c‬‬ ‫معامل يدفع الى المكدس‬

‫‪/‬‬ ‫عامل رياضي‪ ,‬لذا يسرحب اعلرى عنصررين بالمكردس‬


‫‪ (a-b), c‬وتوضع بينهم العالمة الرياضرية‬ ‫وهما‬
‫لتكون عنصر واحد يدفع للمكدس‬

‫يكررون العنصررر االول الررذي يسررحب مررن المكرردس هررو ‪(a-b)/c‬‬


‫العنصررر الررذي يوضررع بعررد العالمررة الرياضررية بينمررا‬
‫العنصر الثاني الذي يسرحب مرن المكردس يوضرع قبرل‬
‫العالمة الرياضية‬

‫‪d‬‬ ‫‪(a-b)/c,d‬‬ ‫معامل يدفع الى المكدس‬

‫‪e‬‬ ‫‪(a-b)/c,d,e‬‬ ‫معامل يدفع الى المكدس‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪+‬‬ ‫عامل رياضي‪ ,‬يسحب اعلى معاملين بالمكردس وهمرا ‪(a-b)/c‬‬


‫‪d, e‬‬

‫توضع بيرنهم العالمرة الرياضرية لتكرون عنصرر واحرد )‪(a-b)/c,(d+e‬‬


‫يدفع الى المكدس‬

‫‪f‬‬ ‫‪(a-b)/c,(d+e),f‬‬ ‫معامل يدفع الى المكدس‬

‫‪-‬‬ ‫عامررل رياضرري‪ ,‬يسررحب اعلررى معرراملين فرري المكرردس ‪(a-b)/c‬‬


‫‪(d+e), f‬‬ ‫وهما‬

‫توضع العالمرة الرياضرية بيرنهم ليكرون عنصرر واحرد ‪(a-b)/c,(d+e)-f‬‬


‫يدفع الى المكدس‬

‫‪(a-b)/c,(d+e)-f‬‬

‫*‬ ‫عامل رياضي يسحب اعلى عنصرين بالمكدس وهما‬


‫‪ ((a-b)/c),‬ويوضررررع بيررررنهم العالمررررة‬ ‫)‪((d+e)-f‬‬
‫الرياضية ليتكون عنصر واحد يدفع الى المكدس‬

‫‪(a-b)/c*(d+e)-f‬‬

‫‪(a-b)/c*(d+e)-f‬‬ ‫النتيجة النهائية حيث اليوجد عناصر اخرى اضافية‬

‫تمرين ‪ :2‬حول كل تعبير من تعابير العالمة القياسية ادناة الى تعبير العالمة الالحقة‬
‫باستخدام المكدس ( االجابة في نهاية الفصل)‬

‫‪1.‬‬ ‫‪A+B*C–D*E/F‬‬
‫‪2.‬‬ ‫‪A+B^C/D*E+F–A‬‬
‫‪3.‬‬ ‫‪A^B^C/2*B+4‬‬
‫‪4.‬‬ ‫‪A/B+C/D–E*F^2/B‬‬
‫‪5.‬‬ ‫‪(A + B) * (C – B) / 2 ^ 4‬‬

‫‪139‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪6.‬‬ ‫)‪(A + B) * (C – D‬‬


‫‪7.‬‬ ‫)‪A – B / (C + D * E‬‬
‫‪8.‬‬ ‫)‪((A + B) * C – (D – E))/(F + G‬‬

‫‪ 4.8‬ووارزميةةةة تحويةةة ت بيةةةر ال مةةةة القياسةةةية الةةةل ت بيةةةر ال مةةةة‬


‫السابقة‬

‫ان تحويل تعبير العالمة القياسية الى تعبير العالمة السابقة يتبع الخطوات التالية بعد‬
‫ان يتم فحص تعبير العالمة القياسية من اليمين الل اليسار ويتم تكرار الخطوات‬
‫التالية على كل عنصر من عناصر التعبير لحين ان يفر المكدس‪.‬‬
‫‪ .1‬قراءة عنصر جديد من تعبير العالمة القياسية‪.‬‬
‫‪ .2‬اذا كان العنصر هو معامل فيتم اضافتة الى سلسلة المخرجات‪.‬‬
‫‪ .3‬اذا كان العنصر هو عامل رياضي فيتم اجراء مايلي‪:‬‬
‫‪ 3.1‬اذا كان العامل قوس ايمن " ( " يتم وضعة في المكدس‪.‬‬
‫‪ 3.2‬اذا كان العامل قوس ايسر " ) " في هرذل الحالرة يرتم سرحب جميرع العوامرل‬
‫الموجودة في المكدس لحين الوصول الى القوس االيمن‪ .‬جميع هذة العوامل‬
‫التي سريتم سرحبها مرن المكردس تكترب فري سلسرلة المخرجرات بالتعاقرب (اي‬
‫واحد بعد االخر)‪ .‬االقواس تهمل‪.‬‬
‫‪ 3.3‬اذا كان العنصر عامل رياضي فيتم اجراء مايلي‪:‬‬
‫‪ 3.3.1‬اذا كان المكدس فار فيتم اضافة العامل الرياضي الى المكدس‪.‬‬
‫‪ 3.3.2‬اما اذا كان المكدس غير فار ‪ ,‬عليك بالقيام بمايلي‪:‬‬
‫‪ )a‬ايجاد االفضلية للعامل الرياضي‪.‬‬
‫‪ )b‬ايجاد االفضلية للعامل الرياضي الموجود في اعلى المكدس‪.‬‬
‫مقارنررة االفضررليات للعرراملين‪ ,‬فرراذا كانررت افضررلية العامررل الرياضرري المررراد‬ ‫‪)c‬‬
‫اضررافتة اعلررى مررن افضررلية العامررل الرياضرري الموجررود فرري اعلررى المكرردس فرري ه رذل‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الحالررة يررتم دفررع هررذا العامررل الررى المكرردس ليكررون فرري اعلررى المكرردس‪ .‬امررا اذا كانررت‬
‫افضلية العامل المراد اضافتة اقل من افضرلية العامرل الرياضري الموجرود فري اعلرى‬
‫المكدس عندها يتم اخراج العامل الرياضي في اعلرى المكردس ويضراف الرى سلسرلة‬
‫المخرجات‪ ..‬تستمر عملية المقارنة مع العامل الذي سريكون فري اعلرى المكردس بعرد‬
‫سحب العامل السابل وتطبل نفس الطريقة‪ ,‬وهكذا لحين الوصول الرى مكردس فرار‬
‫او عامل رياضي في اعلى المكدس افضليتة اقرل مرن العامرل المرراد اضرافتة عنردها‬
‫يضاف العامل الى اعلى المكدس‪.‬‬
‫‪ .4‬اذا كان هنا عناصر اخرى في تعبير العالمة القياسية‪ ,‬الذهاب الى الخطروة ‪.1‬‬
‫في خالف ذلك الذهاب الى الخطوة ‪.5‬‬
‫‪ .5‬افرا جميع محتويات المكدس (ازالة كل العوامل من اعلى المكدس) واضافتها‬
‫الى سلسلة المخرجات‪.‬‬
‫‪ .6‬بعد االنتهاء من افرا المكدس يتم عكس رمروز سلسرلة المخرجرات ( اي يكرون‬
‫الرمز االيسر باليمين والرمز الذي باليمين باليسار) حيرث سرتكون هرذل السلسرلة‬
‫الناتجة تمثل تعبير العالمة السابقة‪.‬‬
‫م حظةةةة‪ :‬باالمكررران عكرررس رمررروز تعبيرررر العالمرررة القياسرررية ابترررداءا وتطبيرررل‬
‫الخوارزميررة اعررالل عليهررا‪ ,‬دون الحاجررة الررى عكررس النتيجررة النهائيررة‪ ,‬لكررن هررذا‬
‫اليتبع في السالسل الحرفية ايناء البرمجة‪.‬‬
‫م حظة‪ :‬اهم الفروق بين خوارزمية التحويل الى العالمة الالحقة والتحويل الى‬
‫العالمة السابقة هو‪:‬‬
‫‪ ‬فرري حالررة التحويررل الررى العالمررة الالحقررة فرران السلسررلة تقرررا مررن اليسررار الررى‬
‫اليمين بينمرا فري حالرة التحويرل الرى العالمرة السرابقة فران السلسرلة تقررا مرن‬
‫اليمين الى اليسار‪.‬‬
‫‪ ‬في حالرة العالمرة الالحقرة اليجروز ان تكرون اسربقيتين متسراويتين احرداهما فروق‬
‫االخرى في المكدس‪ ,‬بينما هذا الشرط غير متوفر فري التحويرل للعالمرة السرابقة‬

‫‪141‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫ويجررروز ان تكرررون عالمترررين رياضررريتين باسررربقيتين متسررراويتين احرررداهما فررروق‬


‫االخرى‪.‬‬
‫‪ ‬الح ايضا ان االقواس تستخدم بالعكس‪ ,‬حيث ان القوس االيمرن “)“ فري حالرة‬
‫العالمة الالحقة هو من يفر المكدس لغاية القوس االيسرر“(” ‪ ,‬بينمرا فري حالرة‬
‫العالمة السابقة فان القوس االيسر هو من يفر المكدس لغاية القوس االيمن‪.‬‬
‫‪ ‬النتيجة التي نحصل عليها في سلسرلة االخرراج يجرب ان تعكرس لتكروين النتيجرة‬
‫النهائية‪.‬‬

‫مثال ‪ :12‬حول تعبير العالمرة القياسرية ) ‪ ( a – b ) / c * ( d + e – f / g‬الرى‬


‫تعبير العالمة السابقة‬

‫)‪(a–b)/c *(d+e–f/g‬‬
‫رمةةةوز ت بيةةةر‬ ‫ت بيةةةةةةر ال مةةةةةةة المكدس‬ ‫الم حظات‬
‫ال مةةةةةةةةةةةةةةةةة‬ ‫السابقة‬
‫القياسةةةةةةةةةةةةةية‬ ‫(المالر ات)‬
‫(المدو ت)‬
‫)‬ ‫)‬ ‫قوس ايمن يدفع للمكدس‬

‫‪g‬‬ ‫)‬ ‫‪g‬‬ ‫رمز يكون في المخرجات‬

‫‪/‬‬ ‫‪)/‬‬ ‫‪g‬‬ ‫عالمة رياضية تدفع للمكدس‬

‫‪f‬‬ ‫‪)/‬‬ ‫‪gf‬‬ ‫رمز يكون في المخرجات‬

‫‪-‬‬ ‫‪)/-‬‬ ‫عالمررررة رياضررررية ترررردفع للمكرررردس‪gf ,‬‬


‫ولكررون اسرربقية عالمررة الطرررح اقررل‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مررن القسررمة فتخرررج القسررمة لتكررون‬


‫في المخرجات‬

‫‪)-‬‬ ‫تدخل بدال عنها في المكدس عالمة ‪gf/‬‬


‫الطرح‬

‫‪e‬‬ ‫‪)-‬‬ ‫‪gf/e‬‬ ‫رمز يكون في المخرجات‬

‫‪+‬‬ ‫‪)-+‬‬ ‫عالمة رياضية (الجمع) تدفع اعلى ‪gf/e‬‬


‫المكرررردس النهررررا مسرررراوية للعالمررررة‬
‫الطرح في االسبقية‬

‫‪d‬‬ ‫‪)-+‬‬ ‫‪gf/ed‬‬ ‫رمز يرسل الى المخرجات‬

‫(‬ ‫قوس مغلل يخرج جميرع مراموجود ‪gf/ed+-‬‬


‫في المكدس لغاية القوس المفتوح‬

‫*‬ ‫*‬ ‫عالمة الضررب تردفع الرى المكردس ‪gf/ed+-‬‬


‫الفار‬

‫‪c‬‬ ‫*‬ ‫‪gf/ed+-c‬‬ ‫رمز يرسل الى المخرجات‬

‫‪/‬‬ ‫‪*/‬‬ ‫عالمررة القسررمة ترردفع الررى المكرردس ‪gf/ed+-c‬‬


‫اعلرررررى عالمرررررة الضررررررب النهرررررا‬
‫متسرراوية فرري االسرربقية مررع عالمررة‬
‫الضرب‬

‫)‬ ‫)‪*/‬‬ ‫‪gf/ed+-c‬‬ ‫قوس مفتوح يدفع للمكدس‬

‫‪b‬‬ ‫)‪*/‬‬ ‫‪gf/ed+-cb‬‬ ‫رمز يرسل الى المخرجات‬

‫‪-‬‬ ‫‪*/)-‬‬ ‫عالمررة الطرررح ترردفع الررى المكرردس ‪gf/ed+-cb‬‬


‫اعلى القوس‬

‫‪a‬‬ ‫‪*/)-‬‬ ‫‪gf/ed+-cba‬‬ ‫رمز يرسل الى المخرجات‬

‫(‬ ‫‪*/‬‬ ‫قوس مغلل يفر المكدس ويرسلها ‪gf/ed+-cba-‬‬

‫‪143‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الررى المخرجررات واحررد بعررد االخررر‬


‫لحين الوصول الى القوس المفتوح‬

‫*‪ gf/ed+-cba-/‬تعكررس هررذل النتيجررة للحصررول‬


‫على تعبير العالمة السابقة‬
‫ت بير ال مة السابقة‬ ‫‪*/–abc–+de/fg‬‬

‫مثال ‪ :13‬حول تعبيرر العالمرة القياسرية )‪ 2*3/(2-1)+5*(4-1‬الرى تعبيرر العالمرة‬


‫السابقة باستخدام المكدس‪.‬‬

‫)‪2*3/(2-1)+5*(4-1‬‬
‫رموز ت بير ال مة القياسية‬ ‫المكدس‬ ‫سلسلة المالر ات‬
‫(المدو ت)‬ ‫ت بير ال مة السابقة‬
‫)‬ ‫)‬
‫‪1‬‬ ‫)‬ ‫‪1‬‬
‫‪-‬‬ ‫‪)-‬‬ ‫‪1‬‬
‫‪4‬‬ ‫‪)-‬‬ ‫‪14‬‬
‫(‬ ‫فار‬ ‫‪14-‬‬
‫*‬ ‫*‬ ‫‪14-‬‬
‫‪5‬‬ ‫*‬ ‫‪14-5‬‬
‫‪+‬‬ ‫‪+‬‬ ‫*‪14-5‬‬
‫)‬ ‫)‪+‬‬ ‫*‪14-5‬‬
‫‪1‬‬ ‫)‪+‬‬ ‫‪14-5*1‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪-‬‬ ‫‪+)-‬‬ ‫‪14-5*1‬‬


‫‪2‬‬ ‫‪+)-‬‬ ‫‪14-5*12‬‬
‫(‬ ‫‪+‬‬ ‫‪14-5*12-‬‬
‫‪/‬‬ ‫‪+/‬‬ ‫‪14-5*12-‬‬
‫‪3‬‬ ‫‪+/‬‬ ‫‪14-5*12-3‬‬
‫*‬ ‫*‪+/‬‬ ‫‪14-5*12-3‬‬
‫‪2‬‬ ‫*‪+/‬‬ ‫‪14-5*12-32‬‬
‫هذة النتيجة يتم عكسها‬ ‫فار‬ ‫‪14-5*12-32*/+‬‬
‫ت بير ال مة السابقة‬ ‫‪+/*23-21*5-41‬‬

‫‪145‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مثةال ‪ : 14‬تحويرل تعبيرر العالمرة السرابقة ‪ * / – a b c – + d e f‬الرى تعبيرر‬


‫العالمة القياسية‪.‬‬
‫م حظة‪ :‬يتم قراءة عناصر تعبير العالمة السابقة من اليمين الل اليسار‬

‫‪*/–abc–+def‬‬
‫عناصةةر ت بيةةر ال مةةة‬ ‫المكدس‬ ‫الم حظات‬
‫السابقة (المدو ت)‬
‫‪f‬‬ ‫‪f‬‬ ‫معامل يدفع الى المكدس‬
‫‪e‬‬ ‫‪f,e‬‬ ‫معامل يدفع الى المكدس‬
‫‪d‬‬ ‫‪f,e,d‬‬ ‫معامل يدفع الى المكدس‬
‫‪+‬‬ ‫عامل رياضي‪ ,‬يتم سرحب اعلرى معراملين ‪f‬‬
‫بالمكرررردس وتوضررررع العالمررررة الرياضررررية‬
‫بينهما‪ ,‬وهما ‪ ..d, e‬ويتم دفع النتيجة الرى‬
‫اعلى المكدس‬
‫م حظة‪ :‬الم ام االول الذي يسحب مةن )‪f,(d+e‬‬
‫اعلةةةةل المكةةةةدس يوضةةةةع قبةةةة ال مةةةةة‬
‫الرياضةةية ب بينمةةا الم امةة الثةةاني الةةذي‬
‫يسحب مةن المكةدس يوضةع ب ةد ال مةة‬
‫الرياضية‪.‬‬
‫‪-‬‬ ‫عامل رياضي‬
‫‪(d+e)-f‬‬
‫‪c‬‬ ‫‪(d+e)-f,c‬‬ ‫معامل يدفع الى المكدس‬
‫‪b‬‬ ‫‪(d+e)-‬‬ ‫معامل يدفع الى المكدس‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪f,c,b‬‬
‫‪a‬‬ ‫‪(d+e)-‬‬ ‫معامل يدفع الى المكدس‬
‫‪f,c,b,a‬‬
‫‪-‬‬ ‫عامل رياضي‪ ,‬يتم سرحب اعلرى معراملين ‪(d+e)-f,c‬‬
‫بالمكدس‬
‫وهمررا ‪ ..a, b‬وضررع العالمررة الرياضررية‬
‫بينهما ودفع النتيجة الى اعلى المكدس‬
‫‪(d+e)-‬‬
‫)‪f,c,(a-b‬‬
‫‪/‬‬ ‫‪(d+e)-f‬‬
‫‪(d+e)-f,(a-‬‬
‫‪b)/c‬‬
‫*‬
‫* ‪(a-b)/c‬‬ ‫تعبير العالمة القياسية‬
‫‪(d+e)-f‬‬

‫مثال ‪ : 15‬تحويل تعبير العالمة القياسية ‪ (a-b)/c * (d+e)-f‬الى تعبير العالمرة‬


‫السابقة‪.‬‬

‫‪147‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪(a-b)/c * (d+e)-f‬‬
‫رمروز تعبيرر العالمرة القياسرية (مرن اليمررين‬ ‫سلسرررررلة المخرجرررررات المكدس‬
‫الى اليسار) (المدخالت)‬ ‫تعبير العالمة السابقة‬
‫‪f‬‬ ‫‪f‬‬
‫‪-‬‬ ‫‪-‬‬ ‫‪f‬‬
‫)‬ ‫)‪-‬‬
‫‪e‬‬ ‫)‪-‬‬ ‫‪fe‬‬
‫‪+‬‬ ‫‪-)+‬‬ ‫‪fe‬‬
‫‪d‬‬ ‫‪-)+‬‬ ‫‪fed‬‬
‫(‬ ‫‪-‬‬ ‫‪fed+‬‬
‫*‬ ‫*‪-‬‬ ‫‪fed+‬‬
‫‪c‬‬ ‫*‪-‬‬ ‫‪fed+c‬‬
‫‪/‬‬ ‫‪-*/‬‬ ‫‪fed+c‬‬
‫)‬ ‫)‪-*/‬‬
‫‪b‬‬ ‫)‪-*/‬‬ ‫‪fed+cb‬‬
‫‪-‬‬ ‫‪-*/)-‬‬ ‫‪fed+cb‬‬
‫‪a‬‬ ‫‪-*/)-‬‬ ‫‪fed+cba‬‬
‫(‬ ‫‪-*/‬‬ ‫‪fed+cba-‬‬
‫*‪-‬‬ ‫‪fed+cba-/‬‬
‫‪-‬‬ ‫*‪fed+cba-/‬‬
‫فار‬ ‫‪fed+cba-/*-‬‬
‫يتم عكس النات للحصول علل ت بير ال مة السابقة‬ ‫‪-*/-abc+def‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫تمرين ‪ :3‬حول تعابير العالمة الالحقة التالية الى تعرابير العالمرة القياسرية‪ ,‬موضرحا‬
‫محتويات المكدس بعد كل عملية ( االجوبة في نهاية الفصل) (تم وضةع فةوارز بةين‬
‫القيم للتمييز)‪.‬‬
‫‪1.‬‬ ‫‪5, 3, + , 2 , * , 6 , 9 , 7 , - , / , -‬‬
‫‪2.‬‬ ‫‪3, 5, + , 6 , 4 , - , * , 4 , 1 , - , 2 , ^ , +‬‬
‫‪3.‬‬ ‫‪3, 1, + , 2, ^ 7 , 4, - , 2 , * , + , 5 , -‬‬
‫‪4.‬‬ ‫* ‪20, 45, + 20 , 10 , - , 15 , + ,‬‬

‫‪ 4.9‬ب ض البرام ال زمة لتببيقات المكدس باستالدا لغة ‪C++‬‬

‫‪ 4.9.1‬دالة باستخدام ‪ C++‬النجراز عمليتري (الردفع والسرحب) )‪ ( push, pop‬فري‬


‫مكدس يمثل كمصفوفة‪.‬‬

‫) ‪void PUSH ( int Stack [ ], int &Top, int Val‬‬

‫{‬

‫البد من التاكد من المكدس ليس مملوء قبل االضافة ‪if ( Top = = size -1 ) //‬‬

‫{‬

‫; ” ‪cout << “ Stack Overflow‬‬

‫; )‪exit(0‬‬ ‫}‬

‫‪else‬‬

‫{‬

‫; ‪Top + +‬‬

‫‪149‬‬
C++ ‫هياكل البيانات باستخدام‬

Stack [ Top ] = Val ;

} // end PUSH function

void POP ( int Stack [ ] , int & Top )

int R ;

if ( Top = = -1 ) // ‫البد من التاكد من المكدس ليس فارغ قبل الحذف‬


{

cout<< “ Stack Underflow” ;

exit(0) ; }

else

R = Stack [ Top ] ;

Top - - ;

} // end POP function

‫ اكمال الدوال اعالة لتكون صنف كامل‬4.9.2

class Stack

int Data [ 10] ;


C++ ‫هياكل البيانات باستخدام‬

int Top ;

public:

Stack ( ) { Top = -1; }

void PUSH ( ) ; // ‫لدفع عنصر في المكدس‬

void POP ( ) ; // ‫لسحب عنصر من المكدس‬

};

void Stack :: PUSH ( )

int Val ;

cout <<”Enter the value to be push.” ;

cin>> Val ;

if ( Top = = 9 )

cout << “ Stack Overflow”;

exit ( 0) ; }

else

{ Top + + ;

Data [ Top ] = Val ;

void Stack :: POP( )

int R ;

151
C++ ‫هياكل البيانات باستخدام‬

if ( Top = = -1 )

{ cout<<”Stack Underflow”;

exit (0) ;

else

{ R = Data [Top ] ;

Top - - ;
}

‫ برنامج يستخدم لتحويل تعبير العالمة القياسية الى تعبير العالمة الالحقة‬4.9.3

#include<iostream>
#include<stdio>
#include<conio>
#include<string>
#include<stdlib>
using namespace std ;

const int size =50;

char infix[size], postfix[size], stack[size];

int top = -1;

int precedence(char ch); // ‫دالة للحصول على افضليات العوامل‬


C++ ‫هياكل البيانات باستخدام‬

char pop(); // ‫دالة لسحب عنصر من المكدس‬

char topelement(); // ‫اعادة اعلى عنصر في المكدس‬

void push(char ch); // ‫دفع عنصر ما الى المكدس‬

int main( )

{
char ele, elem, st[2];

int prep, pre, popped, j=0, chk=0 ;

strcpy (postfix,” “) ;

gets(infix);
for (int i=0 ; infix[i] !=0 ; i++)

{
if (infix [i] != ’(‘ && infix[i] != ’)’ && infix[i] != ’^’ && infix[i] != ’*’
&& infix[i] != ’/’ && infix[i] != ’+’ && infix[i] != ’-‘ )
postfix [j++] = infix[i] ;

else

if (infix[i] = = ’(‘ )

{
elem = infix [i] ;

push(elem);
}
else

if (infix[i] = = ’)’ )

{
while (popped = pop( ) != ‘(‘ )

153
C++ ‫هياكل البيانات باستخدام‬

postfix [j++] = popped ;

}
else
{
elem=infix[i];
pre = precedence (elem) ; //‫خزن افضلية العامل الذي ياتي من تعبير العالمة القياسية‬

ele = topelement ( ) ;
prep = precedence (ele) ; //‫خزن االفضلية للعامل الموجود في اعلى المكدس‬

if(pre > prep)

push(elem);
else
{
while(prep >= pre)

{
if(ele = = ’#’ )

break;
popped=pop();
ele=topelement();
postfix[j++] = popped ;

prep=precedence(ele);
}
push(elem);
}
C++ ‫هياكل البيانات باستخدام‬

}
}

while ((popped = pop( )) != ’#’ )

postfix[j++] = popped ;

postfix[j]=’\0’;

cout<<”\n post fix :”<<postfix<<endl;

system(“pause”);
return 0;

int precedence(char ch)

{
switch(ch)
{
case ‘^’ : return 5;

case ‘/’ : return 4;

case ‘*’ : return 4;

case ‘+’ : return 3;

case ‘-‘ : return 3;

default : return 0;

155
‫هياكل البيانات باستخدام ‪C++‬‬

‫}‬
‫}‬

‫)(‪char pop‬‬ ‫دالة لسحب عنصر من المكدس‪//‬‬

‫{‬
‫;‪char ret‬‬
‫)‪if(top!=-1‬‬
‫;]‪{ ret =stack[top‬‬

‫;‪top--‬‬
‫;‪return ret‬‬

‫}‬
‫‪else‬‬
‫;’‪return ‘#‬‬

‫}‬

‫دالة العادة العنصر االعلى في المكدس دون ان تسحبهة من المكدس ‪char topelement() //‬‬

‫{‬
‫;‪char ch‬‬
C++ ‫هياكل البيانات باستخدام‬

if(top!=-1)
ch=stack[top];
else
ch=’#’;
return ch;

void push(char ch) // ‫دالة لدفع عنصر الى المكدس‬

{
if(top!=size-1)
{
top++;
stack[top]= ch;

}
}

‫ حساب قيمة تعبير العالمة الالحقة‬4.9.4

#include <iostream>

#include <stdlib>

#include <math>

#include <ctype>
using namespace std ;

157
C++ ‫هياكل البيانات باستخدام‬

const int MAX = 50 ;

class postfix

private :

int stack[MAX] ;
int top, nn ;

char *s ;

public :

postfix( ) ;

void setexpr ( char *str ) ;

void push ( int item ) ;

int pop( ) ;

void calculate( ) ;

void show( ) ;

};

postfix :: postfix( )

top = -1 ;

void postfix :: setexpr ( char *str )


C++ ‫هياكل البيانات باستخدام‬

s = str ;

void postfix :: push ( int item )

if ( top == MAX – 1 )

cout << endl << “Stack is full” ;

else

top++ ;

stack[top] = item ;

int postfix :: pop( )

if ( top == -1 )

cout << endl << “Stack is empty” ;

return NULL ;

int data = stack[top] ;

top-- ;

return data ;

159
C++ ‫هياكل البيانات باستخدام‬

void postfix :: calculate( )

int n1, n2, n3 ;

while ( *s )

if ( *s == ‘ ‘ || *s == ‘\t’ )
{

s++ ;

continue ;

if ( isdigit ( *s ) )

nn = *s – ‘0’ ;

push ( nn ) ;

else

n1 = pop( ) ;

n2 = pop( ) ;

switch ( *s )

{
C++ ‫هياكل البيانات باستخدام‬

case ‘+’ :

n3 = n2 + n1 ;

break ;

case ‘-‘ :

n3 = n2 – n1 ;

break ;

case ‘/’ :

n3 = n2 / n1 ;

break ;

case ‘*’ :

n3 = n2 * n1 ;

break ;

case ‘%’ :

n3 = n2 % n1 ;

break ;

case ‘$’ :

n3 = pow ( n2 , n1 ) ;

break ;

default :

cout << “Unknown operator” ;

exit ( 1 ) ;

161
C++ ‫هياكل البيانات باستخدام‬

push ( n3 ) ;

s++ ;

void postfix :: show( )

{
nn = pop ( ) ;

cout << “Result is: “ << nn ;

void main( )

char expr[MAX] ;

cout << “\nEnter postfix expression to be evaluated : “ ;

cin.getline ( expr, MAX ) ;

postfix q ;

q.setexpr ( expr ) ;

q.calculate( ) ;

q.show( ) ;

}
‫هياكل البيانات باستخدام ‪C++‬‬

‫تمةةرين ‪ :4‬حررول تعررابير العالمررة القياسررية التاليررة الررى مايكاف هررا مررن تعررابير العالمررة‬
‫الالحقة موضحها حالة المكدس‪:‬‬
‫) ‪1. ((A – B ) * ( D / E )) / ( F * G * H‬‬
‫‪2. ( A + B ^ D ) / ( E – F ) + G‬‬
‫) ‪3. A * ( B + D ) / E – F – ( G + H / K‬‬
‫‪4. A * ( B + ( C + D ) * ( E + F ) / G ) * H‬‬
‫‪5. A + ( ( B + C ) + ( D + E ) * F ) / G‬‬
‫‪6. NOT A OR NOT B AND NOT C‬‬
‫‪7. NOT ( A OR B ) AND C‬‬

‫تمرين ‪ :5‬اكتب تعبير العالمة القياسية المكافيء لتعابير العالمة الالحقة التالية‪:‬‬

‫‪1. 10 , 3 , * , 7 , 1 , - , * , 23 , +‬‬
‫‪2. 12, 7, 3, - , / , 2 , 1 , 5 + , * , +‬‬
‫‪3. ABCD^*E/+F-‬‬

‫‪ 4.10‬ا وبة التمارين‬

‫تمرين ‪:1‬‬
‫‪1.‬‬ ‫*‪ab+cd-‬‬
‫‪2.‬‬ ‫‪abcde*+/-‬‬
‫‪3.‬‬ ‫‪ab+c*de--fg+/‬‬

‫‪163‬‬
C++ ‫هياكل البيانات باستخدام‬

:2 ‫تمرين‬
1. ABC*+DE*F/–
2. ABC^D/E*+F+A–
3. A B^^C 2/B*4+
4. AB/CD/+EF2^*B/–
5. AB+CB-*24^/
6. AB+CD–*
7. ABCDE*+/–
8. AB+C*DE––FG+/

:3 ‫تمرين‬
1. 13
2. 25
3. 17
4. 1625

:4 ‫تمرين‬

1. AB – DE / * FG * H * /
2. ABD ^ + E F - / G +
3. ABD+*E/F–GHK/+-
4. ABCD+EF+*G/+*H*
5. ABC+DE+F*+G/+
6. A NOT B NOT C NOT AND OR
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪7.‬‬ ‫‪A B OR NOT C AND‬‬

‫تمرين ‪:5‬‬
‫‪1.‬‬ ‫‪10 * 3 * ( 7 – 1 ) + 23‬‬
‫‪2.‬‬ ‫‪12 / ( 7 – 3 ) + ( 1 + 5 ) * 2‬‬
‫‪3.‬‬ ‫‪A+B*C^D/E-F‬‬

‫‪165‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص الالامس‬
‫البابور ‪QUEUE‬‬
‫‪ 5.1‬المقدمة‬

‫في حياتنا اليومية هنا الكثير من الحاالت التري نررى فيهرا النراس يقفرون علرى هي رة‬
‫طوابير لشراء سلعة او انجاز عمل‪ ,‬هي موجودة غالبا الي خدمة‪ ..‬من دفع الفرواتير‬
‫في السوبرماركت الى صعود الباص وليس انتهراءا فري البنرو والمصرارف‪ .‬فعنردما‬
‫يكون مجهز الخدمة غير قادر على انجاز خدمة عميل قبل ان يصرل العميرل الالحرل‬
‫فعنررد ذا نحترراج الررى الطررابور‪ .‬تخيررل مايحرردث عنرردما يخرردم مقرردم الخدمررة (مررثال‬
‫المحاسب في البنك) شخص ما بشكل عشوائي قبل االخرين الذين ربما وصرلوا قبلره‬
‫دون مراعاة لزمن وصول االشخاص للحصول على هذل الخدمة‪.‬‬

‫تشبه قوائم االنتظار في الحاسبات طوابير االنتظرار فري الحيراة اليوميرة عنردما يقرف‬
‫الناس على هي ة طرابور لشرراء سرلعة أو نجراز عمرل‪ ،‬ويطبرل فري كالهمرا مبردأ مرن‬
‫يأتي أوالً يخدم أوالً‪ ،‬وفي الحاسوب يطبل نفس المبدأ‪.‬‬

‫شك ‪ :5.1‬طابور من الحياة اليومية‪.‬‬

‫‪167‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 5.2‬ماهو البابور‬
‫الطابور مشابهة للمكدس ماعدا امكانية اضافة البيانرات مرن خلرف الطرابور والحرذف‬
‫من االمام‪ .‬كتابة برنامج الطابور هرو اكثرر صرعوبة مرن كتابرة برنرامج المكردس‪ ,‬فري‬
‫الطابور نحاف علرى اينرين مرن المؤشررات مرن نروع االعرداد الصرحيحة واحرد يحردد‬
‫النهاية االمامية والثاني يحدد النهاية الخلفية للطابور‪.‬‬
‫الطابور هو مثال لهياكل البيانات الخطية‪ ,‬هو نوع خاص لتجميع البيانرات بحيرث ان‬
‫البيانررات فرري التجميررع يررتم المحافظررة عليهررا بترتيررب يتناسررب مررع العمليررات الترري مررن‬
‫الممكررن ان تجرررى علررى هررذا الترتيررب‪ ,‬مررن هررذل العمليررات اضررافة بيانررات الررى نهاي رة‬
‫الطابور وحذف البيانات من بداية الطابور‪ .‬وهذا يجعرل الطرابور هيكرل بيراني يعتمرد‬
‫على مبدأ الداخل اوال يخررج اوال ))‪ (First In First Out (FIFO‬ان هرذا النظرام‬
‫‪ FIFO‬يعني ان العنصرر االول الرذي يضراف الرى الطرابور يخررج اوال‪ ,‬ولرذلك فران‬
‫اضافة عنصر جديد يعني ان جميع العناصر التي اضيفت قبلره يجرب ان تخررج قبرل‬
‫ان يخرج هذا العنصر الجديد‪.‬‬

‫كمثال على الطابور السريارات التري تقرف واحردة خلرف االخررى فري محطرة البنرزين‬
‫لغرض التزود بالوقود‪ ,‬االنتظار بالدور على دفع فاتورة في محرل‪ ,‬االنتظرار بالردور‬
‫لقطع تذكرة‪ ,‬االنتظار في الطابور في نقاط التفتيش االمني‪...‬الا‪.‬‬
‫وفرري مجررال الحاسرربات فرران الطررابور يعتبررر مررن الهياكررل المعروف رة جرردا فرري انظمررة‬
‫التشغيل وشبكات الحاسوب‪.‬‬
‫والطررابور مررن الممكررن ان ينمررو كبرررا ليصرربح طويررل‪ ,‬ولكررن فقررط عنصررر واحررد مررن‬
‫الممكن ان يدخل في الوقت الواحد وكرذلك عنصرر واحرد يخررج او يخردم فري الوقرت‬
‫الواحد‪ ,‬ويتبع الطابور هيكلية الداخل اوال خارج اوال بشكل عام‪ .‬وهنا نروعين مرن‬
‫الطوابير هما الطابور الخطي والطابور الدائري‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 5.3‬ب ض تببيقات البابور‬


‫عندما يكون لدينا مصادر مشتركة مثل طابعة تستلم اوامر طباعة مرن اكثرر‬ ‫‪.1‬‬
‫من حاسوب او تستلم من حاسوب واحد اكثر من امر طباعة‪ ,‬في هذل الحالة‬
‫فرران امررر طباعررة واحررد سرريتم تنفيررذل بينمررا االوامررر االخرررى تنتظررر دورهررا‬
‫للتنفيررذ‪ ,‬ويررتم تنفيررذها حسررب اسرربقية وصررولها (او وفقررا لخوارزميررة محررددة‬
‫بالتنفيذ)‪.‬‬
‫اذا ماعملنررا علررى الحاسرروب وعملنررا ضررغط سررريع بالمرراوس علررى اكثررر مررن‬ ‫‪.2‬‬
‫ملررف بفررارق وقررت قليرل جرردا‪ ,‬وكرران الملررف االول يحترراج الررى بعررض الوقررت‬
‫النجاز عملة‪ ,‬فان الملف الثاني سريبقى باالنتظرار لحرين اكمرال الملرف االول‬
‫وعندها يكون بالطابور‪.‬‬
‫فرري داخررل الحاسرروب فرران االجهررزة المختلفررة لهررا سرررع انجرراز مختلفررة‪ ,‬مررثال‬ ‫‪.3‬‬
‫اجهررزة االدخررال بطي ررة نسرربة الجهررزة المعالجررة لررذلك فرران عمليررة ارسررال‬
‫واستالم البيانات بين هذة االجهزة يؤدي الى توقف بعض االجهزة السرريعة‬
‫النتظار البيانات من االجهرزة البطي رة‪ ,‬فري مثرل هرذة الحالرة فران هنرا عردة‬
‫طرق لمعالجة الفرق بالسرعة احدها استخدام الطابور‪.‬‬
‫انظمرررة مراكرررز اتصررراالت الهررراتف تتطلرررب ان تسرررتخدم الطرررابور لتجعرررل‬ ‫‪.4‬‬
‫االشخاص ينتظرون تلبية طلباتهم وتوفير الخدمة لهم وخصوصا المجانية‪.‬‬
‫الطلبررات المختلفررة علررى شرربكة االنترنيررت ممكررن ان تكررون ضررمن طررابور‪,‬‬ ‫‪.5‬‬
‫وخصوصا في اجهزة التوجيه ‪.Router‬‬
‫طلبات المقاطعة للبرامج داخل الحاسوب تحتاج الى استخدام الطوابير لتلبية‬ ‫‪.6‬‬
‫اوامر المقاطعة المختلفة والتي تصل بوقت واحد او اوقات متقاربة‪.‬‬
‫انظمررة التشررغيل بشرركل عررام تسررتخدم الطرروابير فرري مراحررل مختلفررة لتلبيررة‬ ‫‪.7‬‬
‫الطلبات الكثيرة للمستخدم‪.‬‬

‫‪ 5.4‬البوابير الالبية‬
‫‪169‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫من الممكن تمثيل الطوابير ماديا في الذاكرة كمصفوفة وتدعى حينها هياكل البيانرات‬
‫المستقرة ‪ static data structure‬وعندها سترث جميع صفات المصرفوفات‪ ,‬او‬
‫مررن الممكرررن ان تمثرررل كقائمرررة موصرررولة وبهررذا تررردعى هياكرررل البيانرررات الديناميكيرررة‬
‫‪ dynamic data structure‬وستمتلك جميع خواص وصفات القروائم الموصرولة‪,‬‬
‫وبغررض النظررر عررن طريقررة تمثيررل الطررابور فرران عمليررات االضررافة تحرردث فرري ذيررل‬
‫الطابور بينما الحذف يحدث في راس الطابور‪.‬‬
‫ويحتوي الطابور على مؤشرين احدهما مؤشر البداية واالخر مؤشر النهاية‪.‬‬

‫شك ‪ :5.2‬تمثي افتراضي للبابور المستالد في هياك البيانات‪.‬‬

‫تنفيذ قوائم االنتظار (البابور)‬ ‫‪5.5‬‬

‫يتطلب تنفيذ قوائم االنتظار على الحاسوب حجز حيز في الرذاكرة يسرتوعب البيانرات‬
‫المراد وضعها في الطابور ووفقا لحجم الطابور‪ ,‬مع وجود مؤشرين يترولى المؤشرر‬
‫األول ا شارة لى رأس او بدايرة موقرع االنتظرار (مؤشرر الرراس) ‪Head Pointer‬‬
‫بينما يشير ابخرر لرى نهايرة موقرع االنتظرار (مؤشرر الرذيل) ‪ Tail Pointer‬ويشرير‬
‫مؤشر رأس القائمة لى عنوان أول موقع مشغول بينما يشير مؤشر ذيل القائمرة لرى‬
‫عنوان اخرر موقرع مشرغول فري كتلرة المواقرع المعنونرة المخصصرة للقائمرة‪ .‬يوضرح‬
‫الشكل ‪ 5.3‬طريقة التعامل مع قوائم االنتظار‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :5.3‬شك توضيحي لبريقة االضافة والحذذ من البابور‪.‬‬

‫مميزات استالدا المصفوفة بالبابور‬ ‫‪5.5.1‬‬


‫تنفيذها بسيط‪.‬‬ ‫‪‬‬
‫يجب ان يحدد حجم الطابور عند االعالن‪.‬‬ ‫‪‬‬
‫فضرراء الررذاكرة المخصررص للطررابور مررن الممكررن ان اليسررتخدم بشرركل جيررد‬ ‫‪‬‬
‫ويكون هنا فقدان بمواقع الذاكرة عند استخدام عدد قليرل مرن العناصرر مرع‬
‫االعالن عن حجم كبير للطابور‪.‬‬
‫اليم كن اضافة عناصر اضافية اكثر من عردد العناصرر التري حردد بهرا حجرم‬ ‫‪‬‬
‫الطابور (حجم المصفوفة)‪.‬‬

‫‪ 5.5.2‬مميزات تنفيذ البابور باستالدا القوائم الموصولة‬


‫‪ ‬تخصيص ذاكرة بشكل ألي لكل عنصر جديد‪.‬‬
‫‪ ‬ربط عناصر الطابور مع بعضها بواسطة المؤشرات‪.‬‬

‫‪171‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ ‬استخدام مؤشرين واحد يؤشر على العنصرر االول بالطرابور والثراني يؤشرر‬
‫على العنصر االخير بالطابور‪.‬‬
‫‪ ‬تعتبر طريقة جيدة لترشيد استهال الذاكرة‪.‬‬

‫‪ 5.6‬وزل البابور في هياك بيانات مستقرة‬


‫هي طريقة خزن الطابور على شكل مصفوفة يحدد حجمها مسبقا‪.‬‬
‫ويكون هنا مؤشران او دليالن للمصرفوفة (متغيررين مرن نروع االعرداد الصرحيحة)‬
‫يمثالن رأس وذيرل الطرابور‪ ,‬ويجرب ان يحراف علريهم لتحديرد وضرع الطرابور‪ .‬رأس‬
‫الطررابور وذيررل الطررابور بدايررة يكررون بررالموقع صررفر (او )‪ (-1‬وهررو االفضرل لتجنررب‬
‫الموقررع صررفر فرري المصررفوفة وخصوصررا عنررد كتابررة برنررامج) وتتغيررر قرريمهم عنررد‬
‫االضافة والحذف‪.‬‬
‫لنفرض لدينا طابور بحجم ‪ 5‬عناصر لنرى كيفية االضافة والحذف للطابور‪ ,‬وكيفية‬
‫تغير قيم المؤشرات‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :5.4‬عمليات االضافة والحذذ في طابور وبي‪.‬‬

‫وزل البابور في هياك بيانات يناميكية‬ ‫‪5.7‬‬


‫كما هو الحال في المكدس‪ ,‬فان كل عقدة في هياكل البيانات الديناميكية تحتروي علرى‬
‫بيانات مع مؤشر يشير الى عنوان العقدة الالحقة‪.‬‬
‫الطابور ايضا يحتاج الى مؤشررين احردهما يؤشرر الرى العقردة الراسرية ومؤشرر اخرر‬
‫يؤشر الى عقدة الذنب‪ .‬الشكل ‪ 5.5‬يوضح خزن الطابورباستخدام القوائم الموصرولة‬
‫لطررابور اسررمه ‪ Queue‬كررل عقرردة تتكررون مررن بيانررات )‪ (DataItem‬ومؤشررر (‬
‫)‪ NextNode‬العقدة الالحقة‪.‬‬

‫شك ‪ :5.5‬تمثي البابور علل شك قوائم موصولة‪.‬‬

‫‪173‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫عمليررة الوصررول الررى هررذل العقررد تررتم مررن خررالل اسررتخدام المؤشرررات‪ ,‬والترري سرريتم‬
‫تخصيص فصل لشرح كيفية عمل القوائم‪.‬‬

‫ووارزمية اضافة عنصر الل البابور‬ ‫‪5.8‬‬


‫‪ .1‬يتم اوال فحص مؤشر النهايرة للطرابور‪ ,‬اذا كران يؤشرر علرى الموقرع االخيرر‬
‫للطابور ( وفقرا لحجرم الطرابور المحردد ابترداءا) (تمثيرل الطرابور علرى شركل‬
‫مصفوفة)‪ ,‬فيتم ارسال رسالة بان الطابور اليوجد به فرا ‪.‬‬
‫‪ .2‬اذا لررم يكررن مؤشررر النهايررة يؤشررر علررى الموقررع االخيررر للطررابور‪ ,‬عنرردل يررتم‬
‫مايلي‪:‬‬
‫‪ .A‬يتم تغيير موقع المؤشر (مؤشر النهاية) باضافة واحد له ( اي ينتقل‬
‫المؤشر الى الموقع الجديد)‪.‬‬
‫‪ .B‬يضاف العنصر الجديد‪.‬‬
‫‪ .3‬اذا كان مؤشر النهاية يساوي )‪ (-1‬عندها يرتم زيرادة مؤشرر النهايرة ومؤشرر‬
‫البداية بمقدار واحد (الن ذلك يعني ان مؤشر البداية يسراوي )‪ (-1‬ايضرا اي‬
‫ان الطابور فار واليحتوي على اي عنصر)‪ .‬من الممكن اذا كان الطرابور‬
‫فار وضع المؤشرات على الموقع )‪ (-1‬او )‪.(0‬‬

‫‪ ‬دالة اضافة عنصر الى الطابور الخطي‪ ,‬باستخدام المصفوفات‪.‬‬

‫; ‪int q[25], n , front= -1 , rear= -1 , item‬‬


‫) (‪void insertion‬‬
‫{‬

‫))‪if((rear = =n) && (front = = (rear+1)) || (front = = rear+1‬‬


‫{‬
‫; ”‪cout<< ”Queue Overflow\n‬‬
‫}‬

‫)‪else if (rear = = 0‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪front = rear = 1‬‬

‫‪else‬‬ ‫)‪if (rear = = n‬‬


‫;‪rear = 1‬‬

‫‪else‬‬
‫;‪rear = rear+1‬‬

‫; “ ‪cout<< “Enter the item :‬‬


‫; ‪cin>> item‬‬
‫;‪q[rear] = item‬‬
‫; ‪cout << “ is inserted\n\n” << item‬‬

‫}‬

‫‪ 5.9‬حذذ عنصر من البابور‬


‫‪ .1‬يتم فحص مؤشر البداية للطابور‪ ,‬اذا كان يؤشر على الفرا ( قيمة المؤشرر‬
‫تساوي )‪ ,) (-1‬يتم استصدار رسالة على ان الطابور خالي من العناصر‪.‬‬
‫‪ .2‬اذا كان يؤشر على احد العناصر يتم حذف العنصر الذي يؤشر علية مؤشرر‬
‫البداية‪ ,‬ويتم ذلك كمايلي‪:‬‬
‫‪ .A‬يغيررر موقررع المؤشررر بزيادتررة بمقرردار واحررد‪( ,‬ان مجرررد تغييررر قيمررة‬
‫المؤشر بزيادتة بواحد يعني ان العنصر تم حذفة)‪.‬‬
‫‪ .3‬اذا كان مؤشر البداية يساوي مؤشر النهاية (هذا يعنري وجرود عنصرر واحرد‬
‫في الطابور فقرط) يصرفر المؤشرران (تسرند لهمرا القيمرة )‪ ,) (-1‬والرذي يردل‬
‫على ان الطابور اصبح فارغا‪.‬‬

‫‪ ‬دالة حذف عنصر من طابور خطي‪ ,‬باستخدام المصفوفات‪.‬‬

‫‪175‬‬
C++ ‫هياكل البيانات باستخدام‬

void deletion()
{
if (front = = 0 )
{
cout<< “\n Queue Underflow\n\n” ;

item=q[front];

if ( front = = rear )
{
front = 0 ;
rear = 0 ;
}

else if ( front = n )
front=1;
else
front = front + 1 ;
cout<< “\n%d is deleted\n\n” << item ;

}
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 5.10‬البابور الدائري‬
‫دعنررا نسررتخدم نفررس خطرروات خوارزميررة االضررافة والحررذف الترري اسررتخدمت فرري‬
‫الطابور الخطي خالل هذا الفصل‪ .‬بداية نبتدأ كال النهرايتين بالقيمرة (‪ )-1‬للداللرة‬
‫على ان الطابور فار ‪ .‬فعندما يتم اضافة بيانات الى الطابور فران كرال النهرايتين‬
‫ستحصل على قيم جديدة‪ .‬وعندما تضاف بيانات جديدة‪ ,‬فان النهاية الخلفية ترزاد‬
‫بمقدار واحد‪ ,‬وعندما تحذف بيانات فان النهاية االمامية تنقص بمقدار واحد‪ .‬هذا‬
‫العمل جيد ولكن يملرك عيرب اساسري‪ .‬االن مراذا لرو كانرت القيمرة العظمرى لطاقرة‬
‫الطابور هي ‪ 5‬عناصر‪ .‬ونفرض ان المستخدم اضاف اربع عناصرر ابترداءا‪ ,‬يرم‬
‫حذف يالث عناصر واضاف اينان اخران مرة اخررى‪ .‬الطرابور سروف اليسرمح‬
‫له باكمال االضافة‪ ,‬حيث سيضيف عنصر واحد فقط ويقرر ان الطابور اليوجرد‬
‫بره فرررا ‪ .‬السرربب اننررا نزيرد ونقلررل مررن نهررايتين مختلفترين اعتمررادا علررى االضررافة‬
‫والحذف بشكل اعمى‪ ,‬والندر ان كال النهايتين متعلقتان ببعض‪ .‬هنرا سرنخلص‬
‫الى سؤال مهم هو لماذا تظهر رسالة بامتالء الطابور في الوقت الذي يكرون فيره‬
‫الطابور في الحقيقة شبه فار ‪ .‬هذل المشركلة تقودنرا الرى ان نفكربطريقرة جديردة‬
‫تركز على البيانات اكثر من تركيزها على نهاية االضافة او نهاية الحذف‪.‬‬
‫السةةؤال المهةةم هنةةا‪ :‬المصررفوفة لهررا حجررم محرردد‪ ,‬فرراذا كرران مؤشررر الخلررف فرري نهايررة‬
‫المصفوفة وكان هنا عنصر جديد يراد اضافته‪ ,‬فما هو الحل؟‬
‫هنا اينان من الحلول‪:‬‬
‫‪ ‬تزحيف كل العناصر الى االمام في المصفوفة ( وهذل مكلفة جدا)‪.‬‬
‫‪ ‬االلتفاف حول المصفوفة وهذا يولد الطابور الدائري‪.‬‬

‫‪177‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :5.6‬توضيح البابور الدائري ومقارنته مع البابور الالبي‪.‬‬

‫يتم تغيير قيم المؤشرات عند االضافة والحذف باضافة واحد لهما‪.‬‬
‫‪rear = (rear + 1) mod n‬‬

‫‪front = (front + 1) mod n‬‬

‫مميزات البابور الدائري‬ ‫‪5.10.1‬‬


‫الطابور الدائري يسمح لكامل المصرفوفة بخرزن العناصرر دون الحاجرة الرى تزحيرف‬
‫البيانات ضمن الطابور‪ .‬المصفوفة بالطرابور الردائري تلترف حرول نفسرها ممرا يجعرل‬
‫امكانية تجاور مؤشر النهاية مع مؤشر البدايرة (فضرال عرن امكانيرة ان يكرون مؤشرر‬
‫البداية اكبر من مؤشر النهاية)‪ ,‬هرذا يسراعد علرى الوصرول الرى اول او اخرر عنصرر‬
‫بشرركل كفرروء‪ .‬بعررد عمليررة الحررذف فرران المكرران الفررار فرري المصررفوفة مررن الممكررن ان‬
‫نستفيد منه لخزن اي عنصر جديد‪.‬‬
‫فرري الطررابور الخطرري فرران العناصررر مررن الممكررن ان تحشررر او تضرراف وذلررك بزيررادة‬
‫مؤشر النهاية‪ ,‬وعندما يصل مؤشر النهاية الى الحجم االكبر (نهاية المصفوفة) حتى‬
‫وان تررم حررذف عناصررر مررن مقدمررة الطررابور فرران الطررابور يعتبررر مملرروء‪ .‬لررذلك فرري‬
‫الطابور الخطي اليمكن االسرتفادة مرن المصرفوفة بشركل كامرل‪ .‬مرن جانرب اخرر‪ ,‬فري‬
‫الطابور الدائري فران مؤشرر البدايرة يتجراور مرع مؤشرر النهايرة وعليره فران الطرابور‬
‫الدائري يسمح لكامل المصفوفة لخزن العناصرر‪ .‬الفائردة االساسريه للطرابور الردائري‬
‫علررى الطررابور الخطرري هررو امكانيررة اسررتخدام فضرراء المصررفوفة بشرركل اكفررأ والتوجررد‬
‫ضياعات بالذاكرة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫ووارزمية اضافة عنصر الل البابور الدائري‬ ‫‪5.10.2‬‬

‫‪ .1‬فحررص مؤشررر النهايررة فيمررا اذا كرران فرري موقررع (‪ ,)-1‬اي ان الطررابور فررار ‪,‬‬
‫عندها سيكون االجراء هو‪:‬‬
‫‪ .A‬تغير قيمة المؤشرين وذلك باضافة واحد اليهما‪.‬‬
‫‪front = rear = 0‬‬

‫‪ .B‬اضافة البيانات في الموقع الجديد لمؤشر النهاية‬


‫‪Q[rear] = element‬‬
‫‪ .2‬اذا لم تتحقل الفقرة ‪ ,1‬ابردأ بفحرص مؤشرر البدايرة والنهايرة لمعرفرة وضرعية‬
‫الطابور‪ ,‬فاذا كانت قيمة مؤشر البداية يساوي مؤشرر النهايرة ‪ ,1 +‬فران هرذا‬
‫يعني ان الطابور الدائري مملوء‪ ,‬واليوجد فرا لالضافة‪ ,‬االجراء سيكون‪:‬‬
‫‪front = (rear + 1) % max‬‬
‫‪ .A‬يتم طباعة رسالة خطأ تشير الى امتالء الطابور‪.‬‬
‫‪ .B‬الخروج من دالة االضافة‪.‬‬
‫‪ .3‬اذا لررم يكررن الطررابور مملرروء‪ ,‬ففرري هررذة الحالررة يررتم اضررافة واحررد الررى مؤشررر‬
‫النهاية لتغيير موقعه‪.‬‬
‫‪rear = (rear+1) % max‬‬
‫‪ .4‬اضافة العنصر الجديد في الموقع الذي يؤشر عليه مؤشر النهاية‪.‬‬
‫‪Q[rear] = element‬‬

‫‪ ‬دالة اضافة عنصر الى الطابور الدائري باستخدام المصفوفة‬

‫{ )‪void insert (int data‬‬

‫‪if (rear = = -1) { //‬‬ ‫الطابور فارغ‬

‫;‪front = rear = 0‬‬

‫‪179‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫اضافة العنصر في بداية الطابور (اول عنصر في الطابور) ‪arr [front] = data; //‬‬

‫}‬

‫‪else‬‬ ‫{‬

‫;‪int pos = (rear + 1) % SIZE‬‬

‫‪if (pos = = front) { //‬‬ ‫الطابور مملوء‬

‫;‪cout << "No space in queue ..." << endl‬‬

‫;‪return‬‬
‫}‬

‫{ ‪else‬‬

‫تحديث مؤشر النهاية ‪rear = pos; //‬‬

‫اضافة العنصر في الموقع المحدد ‪arr[pos] = data; //‬‬

‫}‬

‫}‬ ‫}‬

‫ووارزمية حذذ عنصر من البابور الدائري‬ ‫‪5.10.3‬‬


‫‪ .1‬بداية يتم فحص مؤشري البداية والنهاية فراذا كانرت قيمرة المؤشرران تسراوي‬
‫)‪ (-1‬فان ذلرك يعنري ان الطرابور فرار وبالترالي اليمكرن حرذف عنصرر مرن‬
‫طابور فار ‪ ,‬في هذل الحالة‪:‬‬
‫يتم طباعة رسالة خطأ للداللة على ان الطابور فار ‪.‬‬ ‫‪.A‬‬
‫الخروج من دالة الحذف‪.‬‬ ‫‪.B‬‬
‫‪ .2‬في خالف ذلك‪ ,‬اي اذا كران الطرابور لريس فرار بمعنرى ان العبرارة فري (‪)1‬‬
‫خاط ة‪ ..‬عندها يتم حذف العنصر باجراء ما يلي‪:‬‬
‫مررن الممكررن حف ر القيمررة الترري يررتم حررذفها اذا كرران هنررا ضرررورة‬ ‫‪.A‬‬
‫لالحتفاظ بها‪ .‬عادة الحاجة لحف العنصر المحذوف‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫]‪element = Q[front‬‬
‫يتم تغيير قيمة المؤشر وذلك بانقاصها بواحد‪ ..‬الح هنا حالتين‬ ‫‪.B‬‬
‫‪ )a‬امررا ان يكررون مؤشررري البدايررة والنهايررة متسرراويين (هررذا يعنرري ان‬
‫الطابور يحتوي على عنصر واحد فقط) عندها يتم مساواتهم للصفر‬
‫او )‪.(-1‬‬
‫‪front = rear = -1‬‬
‫‪ )b‬اما اذا كان مؤشري البداية والنهاية غير متساويين ) اي ان الطابور‬
‫يحت روي علررى اكثررر مررن عنصررر واحررد)‪ ,‬عنرردها يضرراف واحررد الررى‬
‫مؤشر البداية كما في ادنال‬
‫‪front = (front + 1) % max‬‬

‫م حظةةة‪ :‬فرري الخطرروة (‪ )2‬تررم حجررز العنصررر المررراد حذفررة بمتغيررر وذلررك لغرررض‬
‫طباعته الحقا او اجراء اي عملية عليه‪ ,‬ويمكن اهمال هرذل الخطروة اذا لرم تكرن قيمرة‬
‫العنصر المحذوف مهمة‪.‬‬
‫م حظة‪ :‬ربما يسأل القاريء لماذا استخدام باقي القسرمة فري الخطروات التري تتطلرب‬
‫االضافة الى المؤشرات كما ورد في خروارزميتي االضرافة والحرذف‪ .‬والجرواب هنرا‬
‫ان )‪ (max‬تعنرري حجررم الطررابور الرردائري وبمررا اننررا نسررتخدم طررابور دائررري فهنررا‬
‫احتمررال امررتالء الطررابور وحررذف عناصررر منرره وبالتررالي يتغيررر موقررع مؤشررر النهايررة‬
‫والبداية‪ ,‬فاذا امتأل الطابور يكون مؤشر النهاية على اخر موقع في الطابور (لنتخيل‬
‫الطابور ممتأل ولكن عدد من العناصر تم حذفها هنا سيكون فرا في بداية الطابور)‬
‫فاذا اردنا اضافة جديدة فان المؤشر ستزاد قيمته بواحد وبالترالي سرتكون قيمتره اكبرر‬
‫من القيمة العليا لحجم الطابور لذلك نعمل باقي القسمة لتكون قيمة مؤشر النهاية (‪)1‬‬
‫او اي قيمررة اخرررى ضررمن مرردى حجررم الطررابور‪ ,‬ونفررس الشرريء ينطبررل علررى مؤشررر‬
‫البداية‪.‬‬
‫م حظة‪ :‬مؤشر البداية يستخدم للحذف ومؤشر النهاية يستخدم لالضافة‪.‬‬

‫‪181‬‬
C++ ‫هياكل البيانات باستخدام‬

‫ دالة حذف عنصر من الطابور الدائري باستخدام المصفوفة‬


void delete ( ) {

if (front = = -1) { // ‫الطابور فار‬

cout << "Queue is empty ... " << endl;

return;

else {
if (front == rear) { // ‫فقط عنصر واحد موجود في الطابور‬

front = rear = -1;

else {

front = (front + 1) % SIZE; // ‫حدث مؤشر البداية بتزحيفه موقع واحد‬

} }

.‫ دالة برمجية لعرض محتويات الطابور الدائري‬


void display )( {

int i;

cout << "front : " << front << " rear : " << rear << endl;

cout << "Current circular Queue Elements ( front to rear ) : " <<
endl;

if (front = = -1) {
‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪cout << "Queue is empty ... " << endl‬‬

‫;‪return‬‬

‫}‬

‫{ ‪else‬‬

‫;‪i = front‬‬

‫{ ‪do‬‬

‫; ” ” << ]‪cout << arr [i‬‬

‫; ‪i = (i + 1) % SIZE‬‬

‫; )‪} while (i != rear‬‬

‫; ]‪cout << arr[rear‬‬

‫}‬

‫;‪cout << endl‬‬

‫}‬

‫تنفيذ عمليات االضافة والحذذ في البابور الدائري‬ ‫‪5.10.4‬‬


‫لنفرررض ان لرردينا طررابور دائررري فررار كمررا فرري الشرركل ‪ ,5.7‬حجمرره هررو ‪5‬‬
‫ولنرى كيفية االضافة والحذف عليه‪.‬‬
‫برردءا فرران الطررابور خررالي (اي ان مؤشررر البدايررة والنهايررة يسرراوي )‪.)(-1‬‬
‫االيعاز االول سيكون باضافة العناصر التالية ‪ .60 ,40 ,20‬سنتابع عمليرة االضرافة‬
‫والحرررذف مرررن خرررالل االشررركال الرسرررومية فررري الشررركل ‪ 5.7‬والتررري سنوضرررح فيهرررا‬
‫المؤشرات ومواقعها‪:‬‬

‫‪183‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :5.7‬يوضح البابور الفارغب ثم وضع البابور ب د اضافة ث ث قيم بالت اقب‪.‬‬

‫االيعاز الثاني هو اضافة القريم )‪ (50, 10‬بالتعاقرب الرى الطرابور‪ ,‬هرذا سريتم‬
‫وحسب ماموضح في الشكل ‪.5.8‬‬

‫شك ‪ :5.8‬وضع البابور ب د اضافة عنصرين‬

‫االن لو جاء ايعاز باضافة العنصر ‪ 30‬الى الطابور الدائري‪.‬‬


‫الح هنا بالرجوع لخوارزمية االضافة فاننا نفحص اذا كران الطرابور مملروء ام ال‪,‬‬
‫وذلك اذا تحققت العالقة التالية‬
‫‪front= 0 = (Rear + 1) % size‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪front = (4+1) % 5 = 0‬‬

‫ونظرا لتحقل العالقة‪ ,‬لذلك اليمكن االضافة الن الطابور ممتليء‪.‬‬


‫االن لو جاء االيعاز لنحذف عنصرر‪ .‬اوال نتاكرد مرن وجرود عناصرر (اي ان الطرابور‬
‫ليس خاليا) ويكون الطابور فارغا اذا تسراوى مؤشرر البدايرة والنهايرة وكانرت قيمرتهم‬
‫)‪ .(-1‬عند الفحص نجد ان المؤشرين كل واحد يؤشر الى قيمة مختلفة‪.‬‬
‫‪front = 0‬‬ ‫‪and rear = 4‬‬

‫هنا الطابور ليس فار لذلك باالمكان الحذف وذلك بتغيير قيمة مؤشر البداية‪.‬‬
‫‪front = (front + 1) % size = (0 + 1) % 5 = 1 % 5 = 1‬‬

‫الح الشكل ‪.5.9‬‬

‫شك ‪ :5.9‬البابور ب د حذذ القيمة ‪.20‬‬

‫لنحذف عنصر اخر‪ ,‬نتبع نفس الطريقرة اعرالل ونتاكرد مرن ان الطرابور لريس‬
‫فررار ‪ ,‬بعررد ان تاكرردنا مررن ان الطررابور لرريس فررار نقرروم بعمليررة الحررذف بتغييررر قيمررة‬
‫مؤشر البداية‪.‬‬
‫‪front = (front + 1) % size = (1 +1 ) % 5 = 2 % 5 = 2‬‬

‫الح الشكل ‪.5.10‬‬

‫‪185‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :5.10‬البابور ب د ا راء الحذذ ل نصر ثال‪.‬‬

‫الفص السا س‬
‫القوائم الموصولة ‪LINKED LISTS‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 6.1‬المقدمة‬
‫اذا قمت بخلل قائمة (مجموعة من القيم التي لها نفس النروع مثرل قائمرة او مجموعرة‬
‫مررن القرريم مررن نرروع االعررداد الصررحيحة لغرررض تمثيررل ارقررام هواتررف مررثال‪ ,‬قائمررة او‬
‫مجموعررة مررن نرروع السالسررل الحرفيررة لحف ر اسررماء الطلبررة وهكررذا ) اعتمررادا علررى‬
‫المصررفوفات فانررك مررن الممكررن ان تبرردأ االعررالن عررن المتغيرررات اعضرراء المصررفوفة‬
‫والتي ستحمل العناصر (البيانات)‪ ,‬وكل عنصر من الممكرن الوصرول اليرة بواسرطة‬
‫رقم الفهرس المقابل له‪ .‬عندما تعمل ذلك‪ ,‬وغالبا اينراء العمرل مرع المصرفوفات فانرك‬
‫يجب ان تحدد عدد العناصر االكبر التي تتوقع انها ستمثل بواسرطة هرذل المصرفوفة‪.‬‬
‫بدون تخطيط جيد فان البعد او االبعاد المحددة للمصفوفة من الممكن ان تكون كبيرة‬
‫جدا او صغيرة جدا وهذا مرن الممكرن ان يرؤدي امرا الرى ضرياع مسراحة مرن الرذاكرة‬
‫تحجز للمصفوفة دون االستفادة منها او ان يكون هنا حاجة الرى مزيرد مرن مسراحة‬
‫الذاكرة لم يتم حجزها مسبقا وبالتالي فران كلترا الحرالتين سرتؤديان الرى قلرة فري كفراءة‬
‫البرامج التي تستخدم المصفوفات‪ ,‬علما بان ‪ C++‬ال تسمح با عالن عن مصفوفة‬
‫دون تحديد االبعاد قبل ان تبدا المصفوفة‪ .‬هذا يعني‪ ,‬عنرد خلرل مصرفوفة فانرك غالبرا‬
‫يجررب عليررك ان تحرردد العرردد االكبررر للعناصررر الترري ستتضررمنها المصررفوفة‪ .‬مالحظررة‬
‫اخرى بهذا الشأن هرو ان المصرفوفة تخرزن بمواقرع متجراورة وعنردما يكرون حجمهرا‬
‫كبير احيانا تبرز مشكلة عدم توفر المساحة الخزنية الكافية للمصفوفة‪.‬‬

‫القوائم الموصولة هي قوائم من الممكن ان تتوسع او تتقلص حسب رغبة المستخدم‪.‬‬


‫هذا يعني عند خلل قائمة‪ ,‬فانك ال تحتاج الى ان تخمن او تحدد العدد االكبر لعناصر‬
‫القائمة والتي من الممكن اضافتها ايناء العمل (التنفيرذ)‪ .‬السرتخدام هرذل المرونرة فران‬
‫العناصر يجب ان تدار بواسطة طريقة اخرى تختلف عن طريقة ادارة المصرفوفات‬
‫وذلك باالستعانة بما يسمى بالمؤشررات‪ .‬مرع القروائم الموصرولة مرن السرهولة اضرافة‬
‫وحذف عناصر في أي مكان من القائمة‪.‬‬
‫القرروائم الموصررولة والمصررفوفات متشررابهة‪ ,‬حيررث ان كالهمررا تخررزن مجموعررة مررن‬
‫البيانررات‪ .‬كالهمررا المصررفوفات والقرروائم الموصررولة تخررزن عناصررر لمصررلحة شررفرة‬

‫‪187‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫(برنامج) المستخدم‪ .‬نوع البيانرات لريس مهرم وذلرك الن نفرس التركيرب يعمرل لخرزن‬
‫عناصرررر ألي نررروع مرررن انرررواع البيانرررات‪ .‬واحررردة مرررن طررررق التفكيرررر حرررول القررروائم‬
‫الموصولة هو النظر الى كيفية عمل المصفوفات والتفكير بطرق مختلفة‪.‬‬

‫ان الفرق الرئيس بين استخدام المصفوفات والقوائم الموصرولة يتمثرل بميرزة القروائم‬
‫الموصولة على اضافة عناصر جديدة وحذف عناصرر مرن القائمرة بسرهولة وسررعة‬
‫وهذل الميزة تعتبر صعبة في المصفوفات‪ ,‬كذلك فان القوائم تمتاز بانها مرنه بحجم‬
‫الذاكرة التي تستخدمها حيث يمكن التمدد والتقلص بحجم الذاكرة حسب الحاجة ايناء‬
‫التنفيذ في الوقت الذي ال تتوفر هذل الميزة في المصفوفات التي تمتراز بثبرات الحجرم‬
‫وصررعوبة تغييررررل اينررراء التنفيرررذ‪ ,‬ولكرررن المصرررفوفات تمتررراز بسررررعة الوصرررول الرررى‬
‫عناصرها (وصول مباشر) على عكس القروائم التري ال تصرل الرى عناصررها بشركل‬
‫مباشر‪ ,‬وبالتالي بطأ الوصول الى عناصر القائمة مقارنة بالمصفوفات‪.‬‬

‫‪ 6.2‬ابتداء القوائم الموصولة‬


‫عندما ننشأ قائمة موصولة ستكون فارغة بداية او على االقل يجب ان تفتررض ذلرك‬
‫قبررل ان يررتم اضررافة اي عنصررر اليهررا‪ .‬لتحررديث ذلررك‪ ,‬فرران عليررك االعررالن عررن متغيررر‬
‫يعتبر العنصر االول في القائمة ونواة بناء القائمة‪ .‬بالرغم من انك يمكنرك ان تردعول‬
‫باي اسم‪ ,‬لكن المتعارف علية ان يسمى الراس او البداية ‪ head‬او ‪.start‬‬
‫هذا العنصر من الممكن ان يكون خاص (في حالة استخدام الصنوف ‪ ) classes‬اذا‬
‫لم ترغب ان يتم الوصول الية من خارج الصنف‪ .‬اما اذا اردت ان يتم الوصول الية‬
‫مررن قبررل مسررتخدمي الصررنف فرريمكن ان تجعل ره عررام‪ .‬بررالرغم مررن ان هررذا العنصررر‬
‫(المتغير) يعلن عنه كمؤشر ويؤشر على بداية القائمرة‪ ,‬يجرب ان ال تخصرص ذاكررة‬
‫لرره فرري دالررة االنشرراء ‪ ,constructor‬هررذل الررذاكرة تررنظم عنررد الوصررول لهررا‪ .‬لررذلك‬
‫ببساطة من الممكن ابتدائها على ان تؤشر الى ‪.null‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫كمررا وضررحنا سررابقا فرران كررل عنصررر مررن عناصررر المصررفوفة يمكررن الوصررول لرره‬
‫باستخدام الفهرسة (رقم الموقع) وهذا يضراف الرى اسرم المصرفوفة التري عرادة تحمرل‬
‫عنوان العنصرر االول بالمصرفوفة‪ .‬ونظررا الرى ان عناصرر القائمرة الموصرولة غيرر‬
‫مفهرسة وال تحتوي ارقام مواقرع لرذلك فعلينرا ان نجرد اليرة اخررى لغررض الوصرول‬
‫الى عناصر القائمة الموصولة‪ .‬ان اسهل طريقرة لعمرل ذلرك هرو اوال ايجراد العنصرر‬
‫االول فرري القائمررة وبعرردها يررتم اسررتخراج عنرروان العنصررر الالحررل لرره‪ .‬امررا اذا كانررت‬
‫القائمة فارغة فران هرذل المعلومرات سرتوفر لنرا ‪( null‬وهري تعنري الشريء)‪ .‬اذا كران‬
‫العنصر االول الذي وصلت لره هرو اخرر عنصرر فري القائمرة‪ ,‬فانره ايضرا سريوفر لنرا‬
‫الشرريء ‪ .null‬اي عنصررر اخررر فرري الوسررط مررن الممكررن ان يرروفر لررك وصررول الررى‬
‫العنصررر الالحررل فرري القائمررة‪ .‬لرردعم هررذل النظريررة فعليررك ايجرراد مؤشررر الررى العنصرر‬
‫الالحل في القائمرة كمتغيرر عضرو الرى الصرنف الرذي يحمرل العناصرر‪ .‬هرذا المتغيرر‬
‫العضو يمكن ان يدعى ‪ next‬ولكن يمكن تسميته باي اسم اخر‪.‬‬

‫‪ 6.3‬ماهي القائمة الموصولة‬


‫القائمة الموصرولة هري هيكرل بيراني يسرتخدم لتنظريم البيانرات فري الرذاكرة‪ .‬وكمرا هرو‬
‫واضح من التسرمية فالقائمرة الموصرولة هري قائمرة مرن العناصرر كرل عنصرر يسرمى‬
‫(عقرردة) )‪ (node‬يرررتبط (او يتصررل) مررع العناصررر االخرررى باسررتخدام المؤشرررات‪.‬‬
‫والعقدة هي تركيب ‪ structure‬ضمن القائمة يحتوي على حقلين او اكثرر (الحقرول‬
‫تمثل قيود في التركيب)‪ ,‬غالبا يكون هنا حقل يسمى حقل (البيانات او المعلومات)‬
‫)‪ (data or information‬وهو يحتوي على البيانات او المعلومات المرراد خزنهرا‬
‫والتي يتم االعالن عن نوعها بشكل مسبل‪ ,‬وحقل او حقلرين لرربط او ايصرال العقردة‬
‫بالعقد االخرى تحتوي على عنوان ذاكررة )‪ .(link or address‬عليره فران القائمرة‬
‫الموصولة هي سلسلة من التراكيب )‪.(structures‬‬

‫والقو ائم الموصولة من الممكن ان تكون من اي نوع من االنواع التاليرة وفقرا لعالقرة‬
‫العقد او عناصر القائمة فيما بينها‪:‬‬

‫‪189‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .A‬قوائم موصولة احادية ‪Singly-linked Lists‬‬


‫‪ .B‬قوائم موصولة ينائية او قروائم موصرولة بطرريقين ‪Doubly-Linked or‬‬
‫‪Two Way Linked Lists‬‬
‫‪ .C‬قوائم موصولة دائرية ‪Circularly-Linked Lists‬‬
‫‪ .D‬قوائم موصولة دائرية ينائية ‪Circularly-Doubly Linked Lists‬‬
‫الرجرراء مالحظررة ان هنررا فرروارق تميررز بررين القرروائم الموصررولة االحاديررة والقرروائم‬
‫الموصولة الدائرية والثنائية‪ .‬ووفقا لهذا التعريف فان قيود التركيب ستحمل اي نوع‬
‫من البيانات نحتاج اليه في العمل‪ ,‬فقرط االنتبرال ان كرل قيرد يجرب ان يكرون حالرة مرن‬
‫التركيب )‪ .(structure‬هذا يعني عدم امكانية ان يكون هنا تركيب بياناته حروف‬
‫او رموز يؤشر الى تركيب اخر يحمرل قريم مرن نروع ‪ ,short‬مصرفوفة حرروف‪ ,‬او‬
‫‪ long‬على سبيل المثال‪.‬‬
‫ان جميع الحاالت للعقرد يجرب ان تكرون مرن نفرس التركيرب للقائمرة الواحردة‪ .‬مفهروم‬
‫اخررر لطيررف هررو ان كررل تركيررب او عقرردة مررن الممكررن ان يتواجررد فرري اي مكرران فرري‬
‫الرررذاكرة‪ ,‬والعقرررد عرررادة ال تكرررون خطيرررة بالرررذاكرة ( اي ال تكرررون بمواقرررع متسلسرررلة‬
‫بالذاكرة) وانما تكون في مواقع مبعثرة داخل الذاكرة‪.‬‬

‫‪ 6.4‬ال قدة ‪Node‬‬


‫العقدة هي بحد ذاتها موقع او مجموعة مواقع متجراورة فري الرذاكرة لهرا عنروان هرو‬
‫عنوان موقعها في الذاكرة (عنوان اول بايت (كلمرة) فري الرذاكرة)‪ .‬ومرن الممكرن ان‬
‫نخزن بهرا (العقردة) بيانرات وممكرن ان نخرزن بهرا عنروان ذاكررة لموقرع اخرر‪ .‬ولكري‬
‫نضيف قي م الى هذا الموقع‪/‬المواقع سواء كانت هذل القيم بيانات او عناوين فال بد ان‬
‫نعلن عن نوع البيانرات التري سريتم اضرافتها لحقرول العقردة (هرذل العمليرة تفيرد بتحديرد‬
‫حجم الذاكرة للعقدة)‪ .‬ان االعالن عن نوع البيانات يتم من خالل اسرتخدام التراكيرب‬
‫)‪ (structure‬والتي يعرفها ويحددها المستخدم‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.1‬عقدة احا ية‬

‫شك ‪ :6.2‬عقدة ثنائية‬

‫‪ 6.5‬لماكا القوائم الموصولة‬


‫من فوائد استخدام القوائم هو عردم القلرل حرول فقردان مسراحة مرن الرذاكرة مرن خرالل‬
‫تخصيص ذاكرة اكثر مرن المطلروب‪ .‬كلمرا زاد الطلرب علرى البيانرات يرتم تخصريص‬
‫ذاكررة اضررافية وفقررا لرذلك‪ .‬لكررن الجانررب الصرعب هررو عنررد الرغبرة للوصررول الررى اي‬
‫عقرردة يجررب علينررا المرررور علررى كررل عقرردة سررابقة لهررا لحررين الوصررول الررى العقرردة‬

‫‪191‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫المطلوبرة‪ .‬هرذا هررو السربب الن تكررون القروائم الموصررولة لهرا اشرركال مختلفرة لتسررهيل‬
‫الوصول‪ ,‬مثل القوائم الموصولة الثنائية والدائرية‪.‬‬
‫القوائم الدائرية هي القوائم التي تكون فيها اخر عقدة دائما تؤشر الى العقردة االولرى‪.‬‬
‫بينمرا الثنائيررة تحترروي علررى مؤشررين احرردهما يشررير الررى العقردة الالحقررة بينمررا الثرراني‬
‫يؤشر الى العقدة السابقة‪.‬‬

‫‪ 6.6‬المؤشرات‬
‫سررنتطرق بمراجعررة سررريعة لرربعض المصررطلحات والقواعررد للمؤشرررات ‪pointers‬‬
‫والتي تعتبر االساس في كتابة وتنفيرذ بررامج القروائم الموصرولة‪ .‬ان فهرم المؤشررات‬
‫يساعد بدرجة كبيرة على فهم القوائم الموصولة والعمليات التي تجرى عليها‪.‬‬
‫المؤشر هو متغير يخزن عنوان موقع ذاكرة وبالتالي فان هذا المتغير الرذي هرو مرن‬
‫نوع مؤشر سيتعامل مرع عنراوين الرذاكرة بردل ان يتعامرل مرع القريم او البيانرات التري‬
‫تحتويها مواقع الذاكرة كما في المتغيرات االعتيادية‪ .‬الموقرع او العنروان الرذي يشرير‬
‫له المتغير من نروع المؤشرر بعرض االحيران يعررف باسرم المؤشرر عليره‪ .‬احيانرا فران‬
‫المؤشررات ربمرا تكرون مجموعرة مرن القريم الخاليرة ‪ null‬والتري تفسرر علرى انهرا ال‬
‫تؤشرر حاليررا الررى مؤشرر عليرره (فرري لغرة ‪ C++‬فرران القيمررة الخاليرة يمكررن ان تسررتخدم‬
‫القيمة المطلقة ‪.( false‬‬
‫لقد تعلمنا من خالل البررامج التري نكتبهرا بران المتغيررات ينظرر لهرا علرى انهرا خاليرا‬
‫متجاورة في الذاكرة والتي من الممكن الوصول اليها من خالل المعررف الرذي يمثرل‬
‫المتغير‪ ,‬وفي هذل الطريقة فان المستخدم ال يكترث او ال يهرتم حرول المواقرع الماديرة‬
‫للبيانات في الذاكرة‪ ,‬وببساطة فانه يسرتخدم هرذل المعرفرات فري أي وقرت يرغرب فيره‬
‫االشارة الى متغيراته والعمل عليها‪.‬‬
‫ان ذاكررة الحاسربة مرن الممكرن ان نتخيلهرا كمجموعرة متعاقبرة مرن خاليرا الرذاكرة او‬
‫مواقع الخرزن المتجراورة‪ ,‬وحجرم كرل خليرة تخصرص للمتغيرر هرو بقردر حجرم النروع‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫المعلن عنه لهذا المتغير‪ ,‬وترقم خاليا الرذاكرة بشركل تسلسرلي واضرح‪ .‬هرذل الطريقرة‬
‫تسررراعد علرررى الوصرررول الرررى أي موقرررع فررري الرررذاكرة وذلرررك باسرررتخدام هرررذل االرقرررام‬
‫التسلسلية‪ ,‬وهي ارقام وحيدة لكل خلية في الذاكرة‪ ,‬بمعنى انها ال تتكرر (تسمى هذل‬
‫االرقام عناوين )‪ .) (addresses‬في كل مرة يتم االعالن عرن متغيرر مرا فران حجرم‬
‫الذاكرة التي يحتاجها هذا المتغير ستسند او تخصص له في موقع محدد مرن الرذاكرة‬
‫(هذا الموقع لره رقرم يمثرل عنوانره فري الرذاكرة) وبشركل عرام فران المسرتخدم ال يحردد‬
‫الموقع للمتغير ضمن مستوى خاليا الذاكرة‪ .‬ولحسن الح فان هذل العملية تنجز اليا‬
‫بواسطة نظام التشغيل وخرالل وقرت التشرغيل‪ ,‬وعلرى كرل حرال ففري بعرض الحراالت‬
‫ربما يكون المستخدم راغبا بمعرفرة العنروان الرذي ترم خرزن المتغيرر بره خرالل وقرت‬
‫التشررغيل وذلررك لكرري يعمررل علررى‪ /‬او ينفررذ اوامررر نسرربة لموقعهررا فرري الررذاكرة ولكررن ال‬
‫يكون ذلك متاحا عادة‪.‬‬
‫بعد ان يرتم االعرالن عرن المؤشرر المحلري وقبرل ان يرتم اسرناد قيمرة لره‪ ,‬فران المؤشرر‬
‫يحتوي على قيمة غير معروفرة‪ .‬المؤشررات العامرة تبردأ اليرا بالقيمرة )‪( (null‬والتري‬
‫تعنرري الفرررا او ال شرريء او ربمررا تفسررر علررى انهررا صررفر)‪ .‬اتفاقيررة مهمررة هرري‪ :‬ان‬
‫المؤشر الذي ال يؤشر حاليا الى موقرع ذاكررة محردد فيجرب اسرناد القيمرة )‪ (null‬لره‪,‬‬
‫حيث ان أي مؤشر يحتوي على القيمة )‪ (null‬فهذا يعني ان المؤشرر يؤشرر علرى ال‬
‫شيء‪ .‬وعلى كل حرال‪ ,‬وبسربب ان المؤشرر لره القيمرة )‪ (null‬فران ذلرك كرافي لجعلره‬
‫غيررر امررن‪ .‬ان لغررة ‪ C++‬ال ترررغم المؤشررر الن تكررون لرره القيمررة ‪ .null‬المؤشرررات‬
‫الخالية من الممكن استخدامها لتحديد نهاية القائمة الموصولة او العقدة التي ليس لهرا‬
‫عقدة الحقة‪.‬‬
‫‪ 6.6.1‬عوام المؤشرات‬
‫اكثر معاملين مهمين يستخدمان مع المؤشرات هما‪:‬‬
‫عامررل العنرروان )&( (اذا وضررع امررام متغيررر فانرره سرريعيد عنرروان هررذا المتغيررر فرري‬
‫الذاكرة)‪.‬‬

‫‪193‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫عامل التأشرير )*( (اذا وضرع امرام متغيرر فران هرذا المتغيرر سيشرير الرى موقرع فري‬
‫الذاكرة يخزن به عنوان ذاكرة)‪.‬‬
‫يجب مالحظة ان متغيرات المؤشرر يجرب االعرالن عرن نوعهرا مسربقا فري البرنرامج‬
‫ونقصد با عالن هو تحديد عدد المواقع التي تؤشر عليها هذل المتغيرات وهري ذات‬
‫الطريقة التي كنا نتعامل بها مع المتغيررات االعتياديرة‪ ,‬وسربب ان نحردد نروع متغيرر‬
‫المؤشر هو لكي يتم تحديد حجم خاليا الذاكرة التي سيتم تحديردها لعمرل هرذا المتغيرر‬
‫وبالتالي سهولة اسناد واسترجاع القيم منها وفقا لنوعها‪.‬‬
‫مثال‬
‫اذا كان لدينا االعالن التالي‬
‫;‪int i, *pi‬‬
‫في هذا االعالن‪ ,‬فان ‪ i‬هو متغير من نوع االعداد الصحيحة ( اي انه يشير‬
‫الى بيانات في الذاكرة يحتوي على بيانات من نوع االعداد الصحيحة)‪.‬‬
‫بينما ‪ pi‬هرو مؤشرر الرى موقرع يحتروي علرى االعرداد الصرحيحة (اي ان ‪pi‬‬
‫يشير الى موقع في الذاكرة (عنوان في الذاكرة) هذا العنوان اذا وصلنا له من خرالل‬
‫البرنامج سنجدل يحتوي على بيانات من نوع االعداد الصحيحة)‪ .‬اما اذا قلنا‬
‫;‪pi = &i‬‬
‫هنا ان ‪ &i‬تعيد عنوان المتغير ‪ i‬وتسند قيمته الى المتغير ‪ . pi‬اما اذا اردنرا‬
‫ان نسند قيمة الى المتغير ‪ i‬فيمكننا القول‪:‬‬
‫;‪i = 10‬‬ ‫‪or‬‬ ‫;‪*pi = 10‬‬

‫من ذلك نستنتج ان العالمة )&( اذا وضعت امام اي متغير ايناء تنفيذ البرنامج فانها‬
‫ستعيد عنوان هذا المتغير في الذاكرة وليس قيمته‪ .‬اما المتغير من نوع المؤشر الذي‬
‫يعلن عنره كمؤشرر بوضرع العالمرة )*( امرام المتغيرر فانره سريحمل دائمرا عنروان فري‬
‫ال ذاكرة وال يمكن ان يحمل بيانات‪ .‬بينما المتغيرات االعتيادية التي ال يوضع امامها‬
‫اي من العالمتين اعالل فأنها ستشير الى قيم او بيانات فري موقرع محردد فري الرذاكرة‪.‬‬
‫الح عندما نضع )*( امام متغير من نوع مؤشر فان التعامرل معره سريكون مشرابه‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫للتعامل مع المتغيرات االعتيادية اي با مكان ان نسند قيمة له وتوضع بذلك الموقرع‬


‫كما في المثال اعالل‪.‬‬
‫دعنا نتخيل الذاكرة على انهرا مصرفوفة كبيررة وكرل موقرع فري المصرفوفة لره عنروان‬
‫ذاكرة مختلف‪ .‬فاذا ترم االعرالن عرن متغيرر فران اسرم المتغيرر سيشرير الرى موقرع فري‬
‫الذاكرة يحتوي القيمة المسندة لهذا المتغير كما في الشكل ‪.6.3‬‬
‫; ‪int a = 50‬‬

‫شك ‪ :6.3‬مواقع الذاكرة‬

‫وللتوضيح‪ ,‬نفرض ان اي موقع فري الرذاكرة مرن الممكرن تمثيلره مثرل الردار الرذي لره‬
‫عنوان ضمن المنطقة او الحي‪ ,‬وهذا الدار يحتوي على غرفرة او اكثرر (وهري تمثرل‬
‫النوع (افتراضا)‪ ,‬لنفرض الغرفة هي بايت واحد وبالتالي غرفة واحردة يعنري بايرت‬
‫واحد وهي من نوع ‪ ,character‬وغرفتين كما لو نقول من نوع االعداد الصرحيحة‬
‫وهكذا)‪ .‬لذلك فان الوصول الى عنوان الدار يكون من خالل اسم الدار مثال )‪ ,(a‬اما‬
‫الشررخص او االشررخاص الررذين يسرركنون هررذا الرردار فهررو‪/‬هم يمثررل (محترروى الرردار او‬
‫محترروى موقررع الررذاكرة)‪ ,‬فرري الشرركل (‪ )6.3‬القيمررة هرري )‪ (50‬ورقررم الرردار (حسررب‬
‫تسلسله في المنطقة) هو موقع الذاكرة )‪ .(4010‬اذا اردنا تغيير قيمة المتغيرر ( اسرم‬
‫الشخص) في هذا الدار‪ ,‬فان الطريقة المناسبة هو ان نغير الشخص الذي يسركن هرذا‬
‫الدار وبالتالي نقول ان الدار يحتوي الشخص الرذي سركن حرديثا فري الردار‪ ..‬هرذا مرن‬
‫الممكن برمجيا باستخدام االيعاز التالي‪:‬‬
‫; ‪a = 100‬‬

‫‪195‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫وهررذا يعنرري اننررا اخرجنررا ‪ 50‬مررن الرردار ووضررعنا برردال عنرره ‪ ,100‬دائمررا ان عمليررة‬
‫المساواة تنسا القيمة القديمة وتبدلها بالقيمة الجديدة‪.‬‬
‫لكررن الح ر ان اسررتخدام المؤشررر يسرراعد علررى الررذهاب مباشرررة الررى موقررع الررذاكرة‬
‫للعنصرررر )‪( (a‬اي الرررى رقرررم الررردار او حسرررب المصرررطلحات البرمجيرررة موقعررره فررري‬
‫الررذاكرة)‪ ,‬ومررن الممكررن تغييررر قيمررة المتغيررر فرري ذلررك الموقررع مررن دون الحاجررة الررى‬
‫العنصر )‪ . (a‬مثال‬
‫; ‪int * b‬‬
‫هنا تم االعالن عن مؤشر باسم ‪ b‬من نوع االعداد الصحيحة‬
‫;‪b = & a‬‬

‫بهذا فاننا مررنا عنوان العنصر )‪ (a‬الى المتغير ‪b‬‬

‫شك ‪ :6.4‬شك يوضح وزل ال نوال في المؤشر‬

‫االن من الممكن تغييرر قيمرة ‪ a‬دون الوصرول الرى ‪( a‬الحر هنرا ان المتغيرر ‪ b‬هرو‬
‫موقع في الذاكرة لكنه بدل ان يخزن بيانات فانره يخرزن عنروان ذاكررة‪ ,‬وهرو عنروان‬
‫المتغير ‪.) a‬‬
‫; ‪*b = 100‬‬

‫; ‪cout << a‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫عندما تصدر ايعاز الى الحاسوب للوصول الى ‪ * b‬فانره يقررا المحتويرات داخرل ‪b‬‬
‫والتي هي بالحقيقة عنوان ‪ a‬وبعدها يتم اتباع العنوان للوصرول الرى (‪ ) a‬او عنروان‬
‫‪ a‬وتتم تغيير محتويات ‪ a‬لتكون القيمة ‪.100‬‬
‫السررؤال االن هررل مررن الممكررن قررراءة وتغييررر محتويررات ‪ a‬دون الوصررول الررى ‪ b‬؟‬
‫الجواب نعم ممكن اذا عملنا مؤشر الى مؤشر‪ .‬الح المثال التالي‪:‬‬

‫) (‪int main‬‬

‫{‬

‫;‪int a = 50‬‬ ‫ابتداء قيمة المتغير ‪// a‬‬

‫;‪cout<<"The value of 'a': "<<a<<endl‬‬

‫;‪int * b‬‬ ‫االعالن عن مؤشر ‪// b‬‬

‫;‪b = &a‬‬ ‫نقل عنوان '‪ 'a‬الى المؤشر ‪//‬‬

‫;‪*b = 100‬‬

‫;‪cout<<"The value of 'a' using *b: "<<a<<endl‬‬

‫;‪int **c‬‬ ‫االعالن عن مؤشر الى المؤشر '‪// 'c‬‬

‫;‪c = &b‬‬

‫;‪**c = 200‬‬ ‫تغيير قيمة '‪ 'a‬باستخدام مؤشر الى مؤشر ‪//‬‬

‫;‪cout<<"The value of 'a' using **c: "<<a<<endl‬‬

‫;‪return 0‬‬

‫}‬

‫م حظةةة‪ :‬فرري كثيررر مررن البرررامج نرررى االيعرراز ‪ q=q->link‬داخ رل البرنررامج‪ .‬هررذل‬
‫العبارة فقط تزحف المؤشر من عقدة الى عقدة اخرى (أي من موقع في الذاكرة الرى‬
‫موقع اخر)‪.‬‬

‫‪197‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 6.7‬هيكلية القائمة الموصولة‬


‫كما سبل واشرنا بان القائمة الموصولة هي عبارة عن مجموعرة مرن العقرد وبالترالي‬
‫فرران العقرردة هرري الوحرردة االساسررية لبنرراء القائمررة الموصررولة‪ ,‬والعقرردة الواحرردة تمثررل‬
‫مجموعة من خاليا الذاكرة المتجاورة‪ .‬ولذلك فان بداية العمرل سريكون االعرالن عرن‬
‫م حتويات العقدة‪ .‬ان العقدة ألغراض القوائم الموصولة يعلن عنها من نوع التركيرب‬
‫)‪ (structure‬ولذلك ستكون نقطة البداية هري ان يرتم خلرل تركيرب باسرم ‪( node‬او‬
‫اي اسم اخر) وهذا التركيب له على االقل اينان من االعضاء او الحقول‪ ,‬واحد يمثل‬
‫البيانات )‪ (data‬وهو من نوع االعداد الصحيحة في هذا المثال (كل انواع البيانات‬
‫من الممكن اسرتخدامها) والرذي سريتم خرزن المعلومرات فيره‪ ,‬بينمرا الثراني هرو مؤشرر‬
‫باسررم )‪( (next‬او اي اسررم اخررر) عررادة يؤشررر الررى العقرردة الالحقررة )‪(node *next‬‬
‫(سيحمل عنوان العقدة الالحقة)‪ .‬بعد ان يتم االعالن عن التركيب للعقدة فسيكون من‬
‫الممكن ان تضاف المعلومات والبيانات الى حقول هذا التركيب‪.‬‬
‫‪struct‬‬ ‫‪node‬‬

‫{‬

‫‪int‬‬ ‫;‪data‬‬

‫;‪node * next‬‬

‫;}‬

‫‪ ‬الح هنا ان المؤشر اعلن عنه من نوع ‪ node‬اي من نروع التركيرب وهرذا‬
‫يعني بانه سيؤشر الى التركيب وليس الى حقل محدد من التركيب‪.‬‬
‫م حظة‪ :‬عند العمل على انشاء قوائم موصرولة فأننرا سرنحتاج الرى خلرل عقرد جديردة‬
‫باستمرار وكلما دعت الحاجة‪ ,‬هذا من الممكن ان يتم من خالل االيعاز )‪.(new‬‬
‫مثال‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫; ‪node *Q‬‬

‫;‪Q = new node‬‬


‫م حظةةة‪ :‬عنررد االنتهرراء مررن اسررتخدام عقرردة معينررة فانرره يفضررل حررذفها واعادتهررا الررى‬
‫الذاكرة الحرة لكري يرتم االسرتفادة منهرا الحقرا‪ ,‬هرذا يرتم باسرتخدام االيعراز )‪.(delete‬‬
‫مثال‬
‫; ‪delete Q‬‬
‫‪ ‬عملية اضافة بيانات الى حقل البيانرات فري العقردة التري يرتم خلقهرا ترتم باسرتخدام‬
‫االيعاز التالي‬
‫; ‪Q - > data = 100‬‬

‫هنا تمت اضافة بيانات وهي القيمة ‪ 100‬الى حقل البيانات في العقدة )‪(Q‬‬
‫‪ ‬اضافة عنوان الى حقل العنوان في العقدة التي يتم خلقها‪ ,‬يتم مرن خرالل االيعراز‬
‫التالي مع مالحظة ان الجانب االيمن من المساواة اما يكون عنوان عقدة اخررى‬
‫او يكون )‪ (null‬في حالة كرون هرذل العقردة التري خلقرت هري العقردة االخيررة فري‬
‫القائمة‪.‬‬
‫; ‪Q -> next = null‬‬

‫‪199‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.5‬الشك يوضح ولر عقدة ديدة واضافة بيانات لها‪.‬‬

‫‪ 6.8‬المرور علل عناصر القائمة الموصولة‬


‫لغرض المرور على كامل عناصر القائمة الموصولة لعرض محتوياتها مثال‪.‬‬
‫نبدأ بخلل متغير من نوع مؤشر باسم معين مثال )‪ (temp‬وهرذا المؤشرر سيسرند لره‬
‫عنرروان عقرردة الررراس (العقرردة االولررى)‪ ,‬عررادة عنرروان العقرردة االولررى يكررون مترروفر‬
‫للمسررتخدم لكرري يسررتخدم للوصررول الررى القائمررة (مررن الممكررن ان يكررون عنرروان العقرردة‬
‫االخيرة ايضا متوفر ويعتمد ذلك على طريقة العمل والمعالجة)‪ .‬يمررر المؤشرر الرى‬
‫العقدة الالحقة وهكذا لحين الوصول الى العقدة النهائية‪.‬‬
‫لتوضيح كيفية الوصول الى العقدة الالحقة‪ ,‬نفرض لدينا القائمة التالية والمكونة مرن‬
‫اربع عقد كما في الشكل ‪.6.6‬‬

‫شك ‪ :6.6‬قائمة موصولة موضح بها القيم وعناوين ال قد في الذاكرة‬

‫الح عنوان العقدة الثاني موجرود فري حقرل العنروان للعقردة االولرى‪ ,‬وعنروان العقردة‬
‫الثالثة موجود في حقل العنوان للعقدة الثانية‪ ..‬وهكذا لبقية العقرد حيرث يكرون عنروان‬
‫كل عقدة موجود في حقل عنوان العقدة السابقة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الوصررول الررى العقرردة الالحقررة يكررون مررن خررالل قررراءة عنوانهررا الموجررود فرري حقررل‬
‫العنوان للعقدة التي تسبقها‪.‬‬
‫فمثال للوصول الى العقدة الثانيرة‪ ,‬يجرب اوال الوصرول الرى العقردة االولرى مرن خرالل‬
‫عنوانها المحفوظ بالمتغير ‪ start‬يم قرراءة عنروان العقردة الثانيرة المحفروظ فري حقرل‬
‫العنوان للعقدة االولى باستخدام االيعاز التالي‪:‬‬
‫; ‪start - > next‬‬

‫لو اردنا ان نصل الى العقدة الثالثرة مرثال نضرع مؤشرر علرى العقردة االولرى )‪(temp‬‬
‫ونحركرره للثالثررة‪ .‬ايضررا مررن الممكررن الوصررول للعقرردة الثالثررة باسررتخدام العنرراوين فرري‬
‫العقدة االولى والثانية‪ ,‬وذلك الن عنوان العقدة الثانية موجود باألولى وعنوان الثالثة‬
‫بالثانية فيكون االيعاز التالي مفيد‬
‫; ‪Start -> next -> next‬‬

‫الح هنا اوال سنصل من خالل االيعاز ) ‪ (start -> next‬الى عنوان العقدة الثانية‬
‫وهذا االيعاز يكاف العنوان ‪(1684‬ألن حقل عنوان العقدة الثانيرة موجرود فري حقرل‬
‫العنروان ‪ next‬للعقردة االولرى ‪ ) start‬ولرذلك فران االيعراز >‪(start -> next -‬‬
‫)‪ next‬من الممكرن ان نتخيلره ليصربح )‪ (1684-> next‬وهرذا يعنري انره يشرير الرى‬
‫عنوان العقدة الالحقة في العقدة ‪( 1684‬سيتم قراءة العنروان ‪ 1688‬وبهرذا نكرون قرد‬
‫وصلنا الى العقدة الثالثة)‪ .‬االن حاول تفسير االيعاز >‪(start -> next -> next -‬‬
‫) ‪.next‬‬
‫لغررض قررراءة جميررع بيانرات القائمررة الموصررولة (وهرري نفرس فكرررة الوصررول لجميررع‬
‫العقد في القائمة) نالح الكود التالي‪:‬‬
‫; ‪temp = start‬‬

‫) ‪while ( temp!=null‬‬

‫{‬

‫; " "<< ‪cout << temp -> data‬‬ ‫عرض بيانات العقدة المؤشر عليها بالمؤشر ‪// temp‬‬

‫‪201‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫نقل المؤشر )‪ (temp‬الى العقدة الالحقة ‪temp = temp-> next ; //‬‬

‫}‬

‫‪ 6.9‬القوائم الموصولة االحا ية ‪Singly Linked Lists‬‬


‫القوائم الموصولة االحادية هري قروائم تكرون فيهرا العقردة الواحردة متكونرة مرن حقلرين‬
‫احدهم للبيانات والثاني حقل عنوان لمؤشر يؤشرر علرى العقردة الالحقرة‪ ,‬واخرر عقردة‬
‫في القائمة تؤشر الى الفرا )‪ .(null‬عادة فان عنروان العقردة االولرى يكرون محفروظ‬
‫لرردينا ويررتم الوصررول للقائمررة عررن طريقرره‪ ,‬ومررن الممكررن ان يررتم حف ر عنرروان العقرردة‬
‫االخيرة ايضا ( الشائع استخدام عنوان العقدة االولى فقط‪ ,‬وهذا سنتبعه هنا)‪.‬‬

‫شك ‪ :6.7‬قائمة موصولة احا ية‬

‫بعض العمليات االساسية التي من الممكن انجازها على القروائم الموصرولة االحاديرة‬
‫هي‪:‬‬

‫‪ .A‬اضافة عقدة في نهاية القائمة الموصولة‪.‬‬


‫‪ .B‬اضافة عقدة الى بداية القائمة الموصولة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫حشر عقدة في موقع ما داخل القائمة الموصولة‪.‬‬ ‫‪.C‬‬


‫حذف عقدة من القائمة الموصولة‪.‬‬ ‫‪.D‬‬
‫ترتيب عناصر القائمة الموصولة‪.‬‬ ‫‪.E‬‬
‫تحديث بيانات عقدة ضمن القائمة الموصولة‪.‬‬ ‫‪.F‬‬

‫اضافة عقدة ديدة الل نهاية القائمة الموصولة‬ ‫‪.A‬‬

‫بعض االحيان تبررز الحاجرة الرى اضرافة عقردة جديردة فري نهايرة القائمرة الموصرولة‪.‬‬
‫ولغرض االضافة في نهاية القائمة فالبد من الوصول الى العقدة االخيرة فري القائمرة‬
‫ومن يم االضافة بعدها (العقدة االخيرة فري القروائم االحاديرة يرتم معرفتهرا وذلرك بران‬
‫يكون حقل العنوان في العقدة يحمرل القيمرة )‪ .((null‬وحيرث اننرا ال نملرك معلومرات‬
‫عن القائمة سوى معلومات عن راس القائمة او عنوان العقدة االولى‪ ,‬لذلك علينا ان‬
‫نبرردأ مررن العقرردة االولررى ويررتم المرررور علررى جميررع العقررد واحرردة تلررو االخرررى لحررين‬
‫الوصررول الررى العقرردة االخيرررة ومررن بعررد ذلررك تررتم االضررافة بعررد هررذل العقرردة (العقرردة‬
‫االخيرة)‪ .‬في هذل الحالة فان من المهم ان نتبع الخطوات التالية‪:‬‬

‫‪203‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.8‬شك توضيحي إلضافة عقدة في نهاية القائمة االحا ية‪.‬‬

‫دائمررا يررتم فحررص القائمررة للتأكررد مررن انهررا ليسررت فارغررة‪ .‬نخلررل عقرردة جديرردة‬ ‫‪.1‬‬
‫(لنسررميها ‪ ) temp‬يررم نضرريف المعلومررات المطلوبررة الررى هررذل العقرردة‪ ,‬وهرري قسررمين‬
‫االول قسم البيانات اي نضيف بيانات الرى حقرل البيانرات‪ ,‬ويانيرا حقرل العنروان وهنرا‬
‫يضاف عنوان العقدة الالحقة في حقرل العنروان‪ ,‬وبمرا اننرا سنضريف هرذل العقردة الرى‬
‫نهاية القائمة الموصولة‪ ,‬وهذا يعني ان هذل العقدة ستكون اخر عقدة فري القائمرة‪ ,‬اي‬
‫ان العنوان الذي سيوضع في حقل العنوان هو ال شيء )‪.(null‬‬

‫يتم خلل او االعالن عن متغير من نوع المؤشر ويوضع عنوان عقدة البداية‬ ‫‪.2‬‬
‫في هذا المؤشر (نفرض مؤشر باسم ‪ )q‬هذا المؤشر سيتم تحريكه من عقدة الخرى‬
‫لحين الوصول الى العقدة االخيرة‪ .‬ان السبب باستخدام مؤشر يان يؤشر على العقردة‬
‫االولى الن العقدة االولرى دائمرا يؤشرر عليهرا مؤشرر يسرمى مؤشرر البدايرة او مؤشرر‬
‫الراس )‪ )head or start‬ويجرب ان نحراف عليره لكري نرتمكن مرن الوصرول الرى‬
‫القائمة متى ما رغبنا اما اذا تم استخدام مؤشر البداية وتم تحريكه الرى العقردة الثانيرة‬
‫فأننا سنفقد عنوان العقدة االولى والقائمة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.9‬كيفية ربط ال قدة الجديدة في نهاية القائمة‬


‫عنررد تحريررك المؤشررر ووصرروله الررى العقرردة االخيرررة فأننررا ببسرراطة سنضرريف‬ ‫‪.3‬‬
‫عنوان العقدة الجديدة التي يراد اضافتها الى حقل العنوان فري العقردة االخيررة‪ ,‬حيرث‬
‫فرري هررذل الحالررة فرران المؤشررر ‪ q‬سرريكون هررو مررن يؤشررر علررى العقرردة االخيرررة اي ان‬
‫عنوان العقدة االخيرة يكون في هذا المؤشرر‪ .‬ترتم عمليرة االضرافة باسرتخدام االيعراز‬
‫التالي‪:‬‬

‫;‪q->next = temp‬‬

‫شك ‪ :6.10‬توضيح كيفية وصول المؤشر الثاني الل ال قدة االويرة مع الحفاظ علل مؤشر‬
‫البداية‬
‫بهذا نكون قد ربطنا عقدة جديدة بنهاية القائمة الموصولة‪.‬‬ ‫‪.4‬‬

‫‪205‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.11‬القائمة االحا ية ب د االضافة‬

‫اضافة عقدة الل بداية القائمة الموصولة‬ ‫‪.B‬‬

‫دعنا نحاول اضافة عقدة جديدة الى بداية القائمة او بكالم اخر وضع عقدة جديدة في‬
‫بدايرة القائمررة‪ .‬ان ربررط عقردة جديرردة فرري بدايرة القائمررة هررو عمرل بسرريط وذلررك ألنره ال‬
‫يتطلب المرور على عناصر القائمة وايجاد الموقع المطلوب لحشر العقدة به‪ .‬عملية‬
‫االضافة تتم بربط العقردة الجديردة بالعقردة االولرى يرم تغييرر اسرم العقردة الجديردة لرتكن‬
‫عقدة البداية‪.‬‬

‫شك ‪ :6.12‬توضيح إلضافة عقدة في بداية القائمة الموصولة االحا ية‬

‫اذا لرم تكررن القائمررة فارغررة‪ ,‬يررتم خلرل عقرردة جديرردة )‪ (temp‬يررم نبرردأ بإضررافة‬ ‫‪)a‬‬
‫البيانات الى حقل البيانات للعقدة الجديدة المراد اضافتها‪.‬‬
‫اضافة عنوان العقدة االولى الى حقل العنوان في العقدة المراد اضرافتها الرى‬ ‫‪)b‬‬
‫القائمة‪ .‬وحسب االيعاز التالي‪:‬‬

‫; ‪temp -> next = start‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫وضررع عنررروان العقررردة المضرررافة فررري متغيررر عنررروان العقررردة االولرررى للقائمرررة‬ ‫‪)c‬‬
‫)‪ (start‬اي ان المتغير الذي يحمل اسم العقدة الجديردة ‪ temp‬سريتم تغييرر تسرميته‬
‫بحيث يكون اسمه ‪ start‬لكي يدل على انه العقدة االولى او عقدة البداية‪.‬‬

‫شك ‪ :6.13‬كيفية ربط ال قدة الجديدة بالقائمة‪.‬‬

‫بهذا تكون العقدة الجديدة قد تمت اضافتها‪.‬‬ ‫‪)d‬‬

‫شك ‪ :6.14‬القائمة ب د االضافة‬


‫حشر عقدة ديدة في اي مكال في القائمة‬ ‫‪.C‬‬

‫نفرررض وجررود الحاجررة الررى حشررر عقرردة جديرردة فرري القائمررة (فرري أي موقررع محرردد‬
‫بالقائمة)‪ .‬هنا سيكون من المهم المرور على عناصر القائمة يجاد الموقع المطلوب‬
‫لحشر العقدة فيه‪ .‬في عمليرة المررور‪ ,‬يجرب ان نحراف علرى مؤشررين احردهما يشرير‬
‫الررى العقرردة السررابقة واالخررر يشررير الررى العقرردة الالحقررة فرري القائمررة (بمعنررى ان يكررون‬
‫المؤشررران علررى عقرردتين متجرراورتين)‪ .‬وذلررك الن العقرردة عنرردما يررراد حشرررها بررين‬

‫‪207‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫عقدتين‪ ,‬فالبد ان تكون هنا عقدة سابقة لها واخرى الحقة لهرا (أي اننرا نحتراج الرى‬
‫عناوين عقدتين لنربط العقدة الجديدة بهما)‪.‬‬

‫شك ‪ :6.15‬شك توضيحي لقائمة تضاذ لها عقدة ديدة في موقع محد ‪.‬‬

‫دائما نفحرص ان تكرون القائمرة غيرر فارغرة‪ .‬فران كانرت غيرر فارغرة نسرتمر‬ ‫‪)a‬‬
‫بعملنا‪.‬‬
‫يتم خلل عقدة جديدة‪ ,‬ومن يم نضيف البيانات الى العقدة المراد اضافتها‪.‬‬ ‫‪)b‬‬
‫في هذل المسالة توجد حالتين وهما‪ ..‬االولى اضرافة العقردة قبرل عقردة محرددة‬ ‫‪)c‬‬
‫في القائمة‪ ,‬والثانية اضافة العقدة بعرد عقردة محرددة فري القائمرة ‪ ..‬ان هراتين الحرالتين‬
‫تختلفان بشكل بسيط في طريقة المعالجة‪.‬‬
‫في كلتا الحالتين سنبحث عرن العقردة المحرددة المرراد الوصرول لهرا‪ ,‬اي كرأن‬ ‫‪)d‬‬
‫تكون عقدة تحتوي على بيانات معينة‪ ,‬او بموقع معين مثال العقردة الثالثرة او الرابعرة‬
‫وهكذا‪ ,‬في هذل الحالة نتبع الخطوات التالية‪:‬‬
‫‪ ‬اذا كان المطلوب اضافة العقدة قبل عقدة محددة (مرثال قبرل العقردة الثالثرة‪ ,‬او‬
‫قبل العقدة التي تحتوي القيمة ‪ ,)40‬عندها سنعمل ما يلي‪:‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫استحداث اينان مرن المتغيررات مرن نروع مؤشرر يسرند عنروان العقردة االولرى‬ ‫‪.I‬‬
‫الحرردهم‪ ,‬بينمررا يسررند لألخررر عنرروان العقرردة الثانيررة (يكررون المؤشررران علررى‬
‫عقدتين متجاورتين)‪.‬‬

‫;‪q = start‬‬

‫; ‪S = start -> next‬‬

‫شك ‪ :6.16‬بيال كيفية وضع المؤشرات علل القائمة‪.‬‬


‫يحر المؤشران الى العقدة الالحقة (من خالل حلقة تكرار) بمعنرى انره فري‬ ‫‪.II‬‬
‫كل مرة يحر المؤشرين عقردة واحردة وبرذلك نضرمن انهمرا سريكونان علرى‬
‫عقدتين متجاورتين دائما‪.‬‬
‫يتم فحص محتويات العقدة (او تسلسل العقدة اذا كان المطلروب عقردة بموقرع‬ ‫‪.III‬‬
‫معين في القائمة) التي يؤشر عليها المؤشر االول (المؤشرر ‪ ) S‬لمعرفرة اذا‬
‫كانت العقدة المطلوبة ام ال‪.‬‬
‫ان لم تكن العقدة المطلوبرة يرتم تحريرك المؤشررين االول والثراني كرل منهمرا‬ ‫‪.IV‬‬
‫لعقدة واحدة (نكرر‪ ,‬هنرا سنضرمن دائمرا ان يكرون المؤشرران االول والثراني‬

‫‪209‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫على عقدتين متجاورتين‪ ,‬بحيرث المؤشرر الثراني يؤشرر علرى العقردة السرابقة‬
‫للمؤشر االول)‪.‬‬
‫التأكد بشكل مسرتمر ان المؤشرر االول )‪ (S‬لرم يصرل الرى نهايرة القائمرة قبرل‬ ‫‪.V‬‬
‫تحريكه‪ .‬فان وصل الى نهاية القائمة هذا يعني عدم وجود العقدة التي نبحث‬
‫عنها لغرض ان نضيف العقدة بجوارها‪.‬‬
‫في حالة الوصرول الرى العقردة المطلوبرة سريكون المؤشرر االول )‪ (S‬يؤشرر‬ ‫‪.VI‬‬
‫عليها بينما المؤشر الثاني )‪ (q‬يؤشر على العقدة السابقة لها‪.‬‬

‫شك ‪ :6.17‬وضع المؤشرات ب د وصولها الل ال قدة المبلوبة‪.‬‬

‫اضافة عنوان العقدة المحددة (المرراد االضرافة قبلهرا) الرى حقرل العنروان فري‬ ‫‪.VII‬‬
‫العقدة الجديدة المراد اضافتها (هذا العنوان موجود فري حقرل العنروان للعقردة‬
‫التي يؤشر عليها المؤشر االول ‪)S‬‬
‫اضرافة عنرروان العقرردة المرراد اضررافتها الررى حقررل العنروان للعقرردة الترري يؤشررر‬ ‫‪.VIII‬‬
‫عليها المؤشر الثاني ‪.q‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.18‬يوضح كيفية ربط ال قدة الجديدة بالقائمة وطريقة وضع ال ناوين‪.‬‬

‫; ‪temp -> next = S‬‬

‫; ‪q -> next = temp‬‬


‫‪ .IX‬بهذا تكون العقدة قد تمت اضافتها‪.‬‬
‫اما اذا كان المطلوب اضافة العقردة بعرد عقردة محرددة (نفررض االضرافة بعرد‬ ‫‪)e‬‬
‫العقدة الثانية التي تحتوي القيمة ‪ )10‬فيكون كما يلي‪:‬‬
‫‪ .I‬هنا ال نحتاج الى مؤشرين فمؤشر واحرد يكفري وهرو المؤشرر االول ‪ S‬الرذي‬
‫سيصل الى العقدة المحددة‪.‬‬

‫شك ‪ :6.19‬اضافة عقدة ب د عقدة محد ة‪.‬‬

‫‪211‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫يضاف عنوان العقردة الالحقرة (الالحقرة للعقردة المرراد االضرافة بعردها وهري‬ ‫‪.II‬‬
‫الترري يؤشررر عليهررا المؤشررر‪ ,S‬هررذا العنرروان موجررود فرري حقررل عنرروان العقرردة‬
‫المراد االضافة بعدها) الى حقل العنوان في العقدة المرراد اضرافتها‪( .‬ارجرو‬
‫االنتبال الى ان عنوان العقدة الالحقة للعقدة التي يؤشر عليها المؤشرر ‪ S‬هرو‬
‫موجود في الحقل ‪ next‬في الشكل ‪.)6.20‬‬
‫يضاف عنوان العقدة المراد اضافتها الى حقل عنوان العقدة المراد االضرافة‬ ‫‪.III‬‬
‫بعدها‪.‬‬

‫شك ‪ :6.20‬توضيح كيفية اضافة ال قدة ب د عقدة محد ة وطريقة اضافة ال ناوين‪.‬‬

‫; ‪temp -> next = S -> next‬‬

‫; ‪S -> next = temp‬‬


‫تم هنا اضافة العقدة‪.‬‬ ‫‪.IV‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.21‬القائمة الموصولة ب د اضافة عقدة ديدة‪.‬‬

‫‪ .D‬حذذ عقدة من القائمة الموصولة‬

‫عملية حذف عقدة من قائمة موصولة تتضمن اكثر من حالة وهي‪:‬‬


‫‪ ‬حذذ عقدة من بداية القائمة الموصولة‬

‫شك ‪ :6.22‬قائمة موصولة مبلوب حذذ ال قدة االولل منها‪.‬‬

‫ان حذف عقدة من بداية القائمة عملية التحتاج الى جهد كبير‪ ,‬وهري تتمركرز بتغييرر‬
‫موقع مؤشر العقدة االولى ليوضع على العقردة الثانيرة (بحيرث تكرون هرذل العقردة هري‬
‫العقدة االولى)‪ ,‬هذل العملية من الممكن انجازها وذلك بان نضع عنوان العقدة الثانية‬
‫في المتغير ‪.start‬‬

‫يتم تحرير مساحة العقدة االولى (هذا يتم بوضرع مؤشرر علرى العقردة االولرى قبرل ان‬
‫يتم تسمية العقدة الثانية باسم العقدة االولى)‪.‬‬

‫‪213‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.23‬توضيح طريقة الحذذ وموقع المؤشر‪.‬‬

‫; ‪Q = start‬‬

‫;‪start = start->next‬‬

‫; )‪free (Q‬‬

‫شك ‪ :6.24‬القائمة ب د الحذذ‪.‬‬

‫‪ ‬حذذ عقدة من نهاية القائمة الموصولة‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.25‬قائمة موصولة محد فيها ال قدة المرا حذفها‪.‬‬

‫حذف عقدة من نهاية القائمة الموصولة يتطلب الوصول الى العقردة النهائيرة لغررض‬
‫حذفها‪ ,‬الح هنا اذا وصلنا الى العقدة النهائية وتم حذفها فان العقدة السابقة لهرا هري‬
‫التي ستكون العقدة النهائية وهذا يعني من المفروض اضافة ‪ null‬الى حقرل عنروان‬
‫العقدة التي تسبل العقدة النهائية الحالية‪.‬‬
‫من هذا فأننا نحتاج الى مؤشر يصل الى العقدة النهائيرة‪ ,‬وكرذلك مؤشرر اخرر يؤشرر‬
‫على العقدة السابقة للعقدة النهائية لكي نحاف عليها عند حذف العقدة النهائية‪.‬‬
‫اذن سنخلل مؤشرين احدهم يوضع على العقدة االولى )‪ (S‬والثاني )‪ (q‬يوضع على‬
‫العقدة الثانية‪ ,‬ويتم تحريك المؤشرين بمقدار عقدة واحدة في كل مررة لحرين وصرول‬
‫المؤشر االول )‪ (S‬الذي وضع ابتداءا على العقدة الثانية الى العقدة النهائية‪.‬‬

‫شك ‪ :6.26‬القائمة الموصولة ب د وصول المؤشرات الل اماكنها المحد ة‪.‬‬

‫عنرد الوصرول الرى العقرردة النهائيرة يرتم وضرع ‪ null‬فرري حقرل العنروان للعقردة السررابقة‬
‫للعقدة النهائية والمؤشر عليها بالمؤشر ‪ q‬وبالتالي فان العقدة النهائية سرتكون خرارج‬
‫القائمة‪.‬‬

‫يتم تحرير مساحة العقدة االخيرة والمؤشر عليها بواسطة المؤشر ‪.S‬‬

‫; ‪q->next = null‬‬

‫‪215‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫; )‪free (S‬‬

‫‪ ‬الحالةةة الثالثةةة هةةي حةةذذ عقةةدة مةةن او ة القائمةةة اي ال هةةذ ال قةةدة تو ةةد بةةين‬
‫عقدتين‪.‬‬

‫شك ‪ :6.27‬قائمة موصولة محد بها ال قدة المرا حذفها‪.‬‬

‫في هذل الحالة ايضا سنحتاج الى مؤشررين مؤشرر سيصرل الرى العقردة المرراد حرذفها‬
‫واالخر يكون على العقدة السابقة لهرا‪ ,‬ألننرا بالنتيجرة نحتراج ان نرربط العقردة السرابقة‬
‫للعقدة المراد حذفها بالعقدة التي تلي العقدة المرراد حرذفها بحيرث تكرون العقردة المرراد‬
‫حذفها خارج القائمة‪.‬‬

‫نخلل متغيرين من نوع مؤشر ونضعهما على العقدة االولى والثانية‪ ,‬ونبردأ بتحريرك‬
‫المؤشرين بمقدار عقدة واحدة في كل مرة لحين وصول المؤشر االول ‪ S‬الى العقردة‬
‫المطلرروب حررذفها (دائمررا عنررد تحريررك المؤشرررات يجررب ان يكررون المؤشرررين علررى‬
‫عقدتين متجاورتين)‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.28‬قائمة موصولة مع المؤشرات التي وصلت الل ال قدة المرا حذفها‪.‬‬

‫تررتم عمليررة الحررذف وذل رك بوضررع عنرروان العقرردة الالحقررة للعقرردة الترري يؤشررر عليهررا‬
‫المؤشرر االول ‪( S‬وهرري العقرردة المررراد حررذفها) فرري حقررل عنرروان العقرردة الترري يؤشررر‬
‫عليها المؤشر الثاني ‪( q‬الح هنا ان عنروان العقردة الالحقرة دائمرا موجرود فري حقرل‬
‫العنوان للعقدة التي يؤشر عليها المؤشر)‪ .‬يتم تحرير مساحة العقدة المحذوفة‪.‬‬

‫شك ‪ :6.29‬كيفية انتقال ال ناوين عند حذذ عقدة بين عقدتين في قائمة موصولة احا ية‪.‬‬

‫; ‪q-> next = S-> next‬‬

‫‪free (S) .‬‬

‫وبهذا فان العقدة المطلوب حذفها تم حذفها‪.‬‬

‫‪217‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.30‬القائمة ب د اتما عملية الحذذ‪.‬‬

‫‪ .E‬ترتيب عناصر قائمة موصولة‬

‫ترتيب القائمة الموصولة سهل جدا الى حد ما‪ .‬بدايرة نخلرل مؤشررين يوضرع احردهم‬
‫علررى العقرردة االولررى والثرراني يوضررع علررى العقرردة الثانيررة‪ .‬هنررا يجررب ان نأخررذ بيانررات‬
‫العقدة االولى ونقارنها مع بيانات جميع العقرد الالحقرة ومترى مرا وجردنا بيانرات اكبرر‬
‫يتم اسرتبدالها (فري حالرة الترتيرب التنرازلي)‪ .‬بعردها ننتقرل الرى العقردة الثانيرة ونقرارن‬
‫بياناتهررا مررع جميررع بيانررات العقررد الالحقررة لهررا ويررتم ابرردال القرريم الكبيرررة مررع الصررغيرة‬
‫وهكذا لحين اكمال جميع العقد‪.‬‬

‫‪ ‬الدالة البرمجية للترتيب هي‪:‬‬

‫{ ) ( ‪void ListSort‬‬

‫; ‪node *temp1, *temp2‬‬

‫; ‪int x = 0‬‬

‫{ ) ‪for (temp1 = start ; temp1 - > next != null ; temp1 = temp1 - > next‬‬

‫) ‪for (temp2 = temp1 - > next; temp2 != null ; temp2 = temp2 - > next‬‬

‫{ ))‪if ( (temp1 - > data) < (temp2 - > data‬‬

‫; ‪x = temp1 - > data‬‬

‫; ‪temp1 - > data = temp2 - > data‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫} } } ; ‪temp2 - > data = x‬‬

‫‪ .F‬تحديث بيانات عقدة ضمن القائمة الموصولة‬


‫ان تحديث بيانات أي عقدة في القائمرة الموصرولة هري مرن االعمرال السرهلة وهري ال‬
‫تحتاج اال لمؤشرر واحرد يوضرع علرى اول عقردة فري القائمرة‪ ,‬يرم يحرر هرذا المؤشرر‬
‫لحين الوصول الى العقدة المطلوبة ( سواء كانت العقدة نبحث عنها بداللة محتوياتها‬
‫او موقعها في القائمة)‪ ,‬بعد الوصول الى العقدة المطلوبة يتم تحديث بياناتها‪.‬‬

‫‪ ‬البرنامج الكامل لجميع العمليات التي تجرى على القوائم الموصولة االحادية‬

‫*‪/‬‬

‫‪* C++ Program to Implement Singly Linked List‬‬

‫‪*/‬‬

‫>‪#include<iostream‬‬

‫>‪#include<cstdio‬‬

‫>‪#include<cstdlib‬‬

‫;‪using namespace std‬‬

‫*‪/‬‬

‫االعالن عن العقدة تكون‪ ..‬على شكل تركيب *‬

‫‪*/‬‬

‫‪struct node‬‬

‫{‬

‫;‪int info‬‬

‫;‪struct node *next‬‬

‫‪219‬‬
C++ ‫هياكل البيانات باستخدام‬

} *start ;

/*

* ‫االعالن عن الصنف‬

*/

class single_llist

public:
node* create_node(int);

void insert_begin();

void insert_pos();

void insert_last();

void delete_pos();

void sort();

void search();

void update();

void reverse();

void display();

single_llist()

start = NULL;

};
C++ ‫هياكل البيانات باستخدام‬

main()

int choice, nodes, element, position, i;

single_llist sl ;

start = NULL;

while (1)

cout<<endl<<"---------------------------------"<<endl;

cout<<endl<<"Operations on singly linked list"<<endl;

cout<<endl<<"---------------------------------"<<endl;

cout<<"1.Insert Node at beginning"<<endl;

cout<<"2.Insert node at last"<<endl;

cout<<"3.Insert node at position"<<endl;

cout<<"4.Sort Link List"<<endl;

cout<<"5.Delete a Particular Node"<<endl;

cout<<"6.Update Node Value"<<endl;

cout<<"7.Search Element"<<endl;

cout<<"8.Display Linked List"<<endl;

cout<<"9.Reverse Linked List "<<endl;

cout<<"10.Exit "<<endl;

cout<<"Enter your choice : ";

cin>>choice;

221
C++ ‫هياكل البيانات باستخدام‬

switch(choice)

case 1:

cout<<"Inserting Node at Beginning: "<<endl;

sl.insert_begin();

cout<<endl;

break;
case 2:

cout<<"Inserting Node at Last: "<<endl;

sl.insert_last();

cout<<endl;

break;

case 3:

cout<<"Inserting Node at a given position:"<<endl;

sl.insert_pos();

cout<<endl;

break;

case 4:

cout<<"Sort Link List: "<<endl;

sl.sort();

cout<<endl;

break;
C++ ‫هياكل البيانات باستخدام‬

case 5:

cout<<"Delete a particular node: "<<endl;

sl.delete_pos();

break;

case 6:

cout<<"Update Node Value:"<<endl;

sl.update();

cout<<endl;

break;

case 7:

cout<<"Search element in Link List: "<<endl;

sl.search();

cout<<endl;

break;

case 8:

cout<<"Display elements of link list"<<endl;

sl.display();

cout<<endl;

break;

case 9:

cout<<"Reverse elements of Link List"<<endl;

sl.reverse();

cout<<endl;

223
C++ ‫هياكل البيانات باستخدام‬

break;

case 10:

cout<<"Exiting..."<<endl;

exit(1);

break;

default:

cout<<"Wrong choice"<<endl;
}

/*

* ‫خلق عقدة‬

*/

node *single_llist::create_node(int value)

struct node *temp, *s;

temp = new(struct node);

if (temp == NULL)

cout<<"Memory not allocated "<<endl;

return 0;
C++ ‫هياكل البيانات باستخدام‬

else

temp->info = value;

temp->next = NULL;

return temp;

/*

* ‫اضافة عقدة في البداية‬

*/

void single_llist::insert_begin()

int value;

cout<<"Enter the value to be inserted: ";

cin>>value;

struct node *temp, *p;

temp = create_node(value);

if (start == NULL)

start = temp;

start->next = NULL;

225
C++ ‫هياكل البيانات باستخدام‬

else

p = start;

start = temp;

start->next = p;

}
cout<<"Element Inserted at beginning"<<endl;

/*

* ‫اضافة عقدة في نهاية القائمة‬

*/

void single_llist::insert_last()

int value;

cout<<"Enter the value to be inserted: ";

cin>>value;

struct node *temp, *s;

temp = create_node(value);

s = start;

while (s->next != NULL)


C++ ‫هياكل البيانات باستخدام‬

s = s->next;

temp->next = NULL;

s->next = temp;

cout<<"Element Inserted at last"<<endl;

/*

* ‫اضافة عقدة في أي موقع في القائمة‬

*/

void single_llist::insert_pos()

int value, pos, counter = 0;

cout<<"Enter the value to be inserted: ";

cin>>value;

struct node *temp, *s, *ptr;

temp = create_node(value);

cout<<"Enter the postion at which node to be inserted: ";

cin>>pos;

int i;

s = start;

while (s != NULL)

227
C++ ‫هياكل البيانات باستخدام‬

s = s->next;

counter++;

if (pos == 1)

if (start == NULL)

{
start = temp;

start->next = NULL;

else

ptr = start;

start = temp;

start->next = ptr;

else if (pos > 1 && pos <= counter)

s = start;

for (i = 1; i < pos; i++)

{
C++ ‫هياكل البيانات باستخدام‬

ptr = s;

s = s->next;

ptr->next = temp;

temp->next = s;

else

cout<<"Positon out of range"<<endl;

/*

* ‫ترتيب القائمة الموصولة‬

*/

void single_llist::sort()

struct node *ptr, *s;

int value;

if (start == NULL)

cout<<"The List is empty"<<endl;

return;

229
C++ ‫هياكل البيانات باستخدام‬

ptr = start;

while (ptr != NULL)

for (s = ptr->next;s !=NULL;s = s->next)

if (ptr->info > s->info)

{
value = ptr->info;

ptr->info = s->info;

s->info = value;

ptr = ptr->next;

/*

* ‫حذف عنصر في موقع ما في القائمة‬

*/

void single_llist::delete_pos()

int pos, i, counter = 0;

if (start == NULL)
C++ ‫هياكل البيانات باستخدام‬

cout<<"List is empty"<<endl;

return;

cout<<"Enter the position of value to be deleted: ";

cin>>pos;

struct node *s, *ptr;

s = start;

if (pos == 1)

start = s->next;

else

while (s != NULL)

s = s->next;

counter++;

if (pos > 0 && pos <= counter)

s = start;

for (i = 1;i < pos;i++)

231
C++ ‫هياكل البيانات باستخدام‬

ptr = s;

s = s->next;

ptr->next = s->next;

else
{

cout<<"Position out of range"<<endl;

free(s);

cout<<"Element Deleted"<<endl;

/*

* ‫تحديث بيانات عقدة‬

*/

void single_llist::update()

int value, pos, i;

if (start == NULL)

{
C++ ‫هياكل البيانات باستخدام‬

cout<<"List is empty"<<endl;

return;

cout<<"Enter the node postion to be updated: ";

cin>>pos;

cout<<"Enter the new value: ";

cin>>value;

struct node *s, *ptr;

s = start;

if (pos == 1)

start->info = value;

else

for (i = 0;i < pos - 1;i++)

if (s == NULL)

cout<<"There are less than "<<pos<<" elements";

return;

s = s->next;

233
C++ ‫هياكل البيانات باستخدام‬

s->info = value;

cout<<"Node Updated"<<endl;

/*
* ‫البحث عن عنصر‬

*/

void single_llist::search()

int value, pos = 0;

bool flag = false;

if (start == NULL)

cout<<"List is empty"<<endl;

return;

cout<<"Enter the value to be searched: ";

cin>>value;

struct node *s;

s = start;
C++ ‫هياكل البيانات باستخدام‬

while (s != NULL)

pos++;

if (s->info == value)

flag = true;

cout<<"Element "<<value<<" is found at position "<<pos<<endl;

s = s->next;

if (!flag)

cout<<"Element "<<value<<" not found in the list"<<endl;

/*

* ‫عكس القائمة الموصولة‬

*/

void single_llist::reverse()

struct node *ptr1, *ptr2, *ptr3;

if (start == NULL)

cout<<"List is empty"<<endl;

235
C++ ‫هياكل البيانات باستخدام‬

return;

if (start->next == NULL)

return;

ptr1 = start;
ptr2 = ptr1->next;

ptr3 = ptr2->next;

ptr1->next = NULL;

ptr2->next = ptr1;

while (ptr3 != NULL)

ptr1 = ptr2;

ptr2 = ptr3;

ptr3 = ptr3->next;

ptr2->next = ptr1;

start = ptr2;

/*
C++ ‫هياكل البيانات باستخدام‬

* ‫عرض عناصر القائمة الموصولة‬

*/

void single_llist::display()

struct node *temp;

if (start == NULL)

cout<<"The List is Empty"<<endl;

return;

temp = start;

cout<<"Elements of list are: "<<endl;

while (temp != NULL)

cout<<temp->info<<"->";

temp = temp->next;

cout<<"NULL"<<endl;

Doubly Linked Lists ‫ القوائم الموصولة الثنائية‬6.10

237
‫هياكل البيانات باستخدام ‪C++‬‬

‫القوائم الموصولة الثنائية هي مجموعة من العقرد (كمرا فري القروائم االحاديرة) تررتبط‬
‫فيما بينها بواسطة مؤشرات مع مالحظة ان كل عقدة في القوائم الثنائية تحتوي على‬
‫يالث حقرول وهري حقرل البيانرات وحقلرين اخررين احردهما يشرير الرى العقردة الالحقرة‬
‫ويسمى المؤشر االيمن‪ ,‬ومؤشر اخر يشير الى العقدة السابقة وهرو المؤشرر االيسرر‪.‬‬
‫ان الفرق بين القوائم الموصولة االحادية والقروائم الموصرولة الثنائيرة هرو ان القروائم‬
‫الموصولة الثنائية تحتوي على مؤشر اضافي في كل عقدة يؤشر الى العقدة السابقة‪.‬‬

‫الح عندما ال توجد عقدة يؤشر عليها المؤشر فانه سيؤشرر الرى ‪ null‬وهرذل الحالرة‬
‫سررتحدث فرري العقرردة االخيرررة حيررث ال توجررد عقرردة الحقررة لهررا وبالتررالي فرران المؤش رر‬
‫االيمن سيؤشر الى ‪ null‬وكذلك العقدة االولى فان المؤشر االيسرر ال يؤشرر الرى اي‬
‫عقدة سابقة للعقدة االولى وبالتالي سيؤشر المؤشر االيسر للعقدة االولى الى ‪.null‬‬

‫شك ‪ :6.31‬قائمة موصولة ثنائية‬

‫ال مليات التي تجرى علل القوائم الموصولة الثنائية‬ ‫‪6.10.1‬‬


‫هنررا عرردد مررن العمليررات الرئيسررة واالساسررية الترري تجرررى علررى القرروائم الموصررولة‬
‫الثنائية‪ ,‬وفي كل العمليات ودائما يجب ان يتم التأكد ان القائمة غير فارغة‪ ,‬العمليات‬
‫التي تجرى على القوائم الموصولة الثنائية هي‪:‬‬

‫‪ .A‬خلل قائمة ينائية‪.‬‬


‫‪ .B‬اضافة عقدة في نهاية القائمة الثنائية‪.‬‬
‫‪ .C‬اضافة عقدة في بداية القائمة الثنائية‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .D‬اضافة عقدة في موقع محدد في القائمة‪.‬‬


‫‪ .E‬حذف عقدة من القائمة‪.‬‬
‫‪ .F‬عرض محتويات القائمة‪.‬‬

‫ولر قائمة‬ ‫‪.A‬‬


‫ان عمليررة خلررل قائمررة تعنرري اضررافة عقررد جديرردة عنرردما ال تكررون هنررا اي عقرردة فرري‬
‫القائمة (اي ال توجد قائمة محددة)‪ ,‬و بالتأكيد فان الخطوة االولى في انشاء اي قائمة‬
‫هو اضافة العقدة االولى او خلل العقدة االولى في القائمة‪.‬‬
‫بعد ان تتم اضافة العقدة االولى يصبح با مكان اضافة عقد اخرى وحسرب الحاجرة‪,‬‬
‫وهذا سيتم من خالل اضافة عقدة جديدة في نهاية القائمة التي ترم خلقهرا سرواء كانرت‬
‫هذل القائمة تحتوي على عقدة واحدة او اكثر ففي كل الحاالت ترتم االضرافة فري ذيرل‬
‫القائمة‪.‬‬
‫ان عمليرة خلرل عقردة ترتم مرن خرالل االيعرراز الخراص بخلرل عقردة جديردة بعرد ان يررتم‬
‫تعريف هيكل العقدة ‪.structure‬‬
‫‪struc node‬‬

‫{‬

‫; ‪int data‬‬

‫; ‪node *next‬‬

‫; ‪node *prev‬‬

‫}‬

‫بعد ان تتم عملية خلل العقدة (والتي سنسميها ‪ ) temp‬تتم اضافة البيانات الى حقل‬
‫البيانات‪ ,‬يم نقوم بإضافة العناوين الى حقول العناوين االيمن وااليسر‪ .‬الح هنا بما‬
‫اننررا نخلررل عقرردة جديرردة لقائمررة غيررر موجررودة اصررال (اي ان هررذل العقرردة هرري العقرردة‬
‫االولى او النواة لخلرل قائمرة جديردة) فران حقرول العنراوين االيمرن وااليسرر سروف ال‬

‫‪239‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫تؤشر الى اي عقدة سابقة او الحقة لعدم وجود عقد اخرى وبالتالي فسنضع فري هرذل‬
‫الحقول ‪.null‬‬
‫; ‪new temp‬‬

‫; ‪temp - > data = value‬‬

‫; ‪temp -> next = null‬‬

‫)‪if (start == null‬‬

‫{‬
‫; ‪temp -> prev = null‬‬

‫; ‪start = temp‬‬

‫}‬

‫الح هنا اننا فحصنا عنوان العقدة االولى ‪ start‬لنتأكد من انها تساوي ‪ null‬للداللة‬
‫على عدم وجود قائمة‪ ,‬حيث انه اذا كانت هنا قائمة فان العنوان ‪ start‬سيكون فيره‬
‫قيمة عنوان وليس ‪.null‬‬

‫‪ .B‬اضافة عقدة الل نهاية القائمة‬


‫خلل عقدة جديدة (نسميها ‪ .)temp‬اضافة بيانرات فري حقرل البيانرات للعقردة الجديردة‪,‬‬
‫ولما كانت هذل العقدة ستكون العقدة االخيرة فعليه سيكون حقل العنروان االيمرن لهرذل‬
‫العقدة يؤشر على ‪ ,null‬اذن نضيف ‪ null‬الى حقل العنوان االيمن للعقدة الجديدة‪.‬‬
‫للوصول الى العقدة االخيرة في القائمة‪ ,‬نضع مؤشر على العقردة االولرى لريكن تحرت‬
‫مسمى )‪.(S‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫نعمل حلقة تكرار تبدا من العقدة االولى وتنتهي عنردما يكرون عنروان العقردة الالحقرة‬
‫(العنرروان االيمررن) يسرراوي ‪ ,null‬بحيررث فرري كررل دورة يررتم نقررل المؤشررر الررى العقرردة‬
‫الالحقة طالما مؤشر العنوان االيمن اليساوي ‪.null‬‬

‫شك ‪ :6.32‬اضافة عقدة الل نهاية القائمة‪.‬‬

‫عندما يصل المؤشر الى العقدة االخيرة نقوم بإضافة العقدة الجديدة بعدها وكما يلي‪:‬‬
‫يوضع عنروان العقردة الجديردة فري حقرل العنروان االيمرن للعقردة االخيررة‪ ,‬وبرذلك فران‬
‫العقدة االخيرة في القائمة ستؤشر على العقدة الجديدة بحيث تكون العقدة الجديدة هي‬
‫االخيرة)‪ .‬يوضع عنوان العقدة االخيرة في حقل العنوان االيسر للعقدة الجديردة‪ ,‬كمرا‬
‫في الشكل ‪.6.32‬‬
‫; ‪s = start‬‬

‫)‪while (s -> next != null‬‬

‫{‬ ‫} ; ‪s = s -> next‬‬

‫; ‪s -> next = temp‬‬

‫; ‪temp -> prev = s‬‬

‫‪241‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫اضافة عقدة في بداية القائمة‬ ‫‪.C‬‬


‫يتم خلل عقدة جديدة باسم )‪ .(temp‬اضافة البيانات الى حقل البيانات‪.‬‬
‫لمرا كانررت هررذل العقرردة ستضرراف فرري بدايرة القائمررة‪ ,‬عليرره فهرري سررتكون العقرردة االولررى‬
‫ولررذلك سرروف يكررون عنرروان العقرردة السررابقة ‪ ,null‬اي يررتم اضررافة ‪ null‬فرري حقررل‬
‫العنوان االيسر‪.‬‬
‫اما مؤشر حقل العنوان االيمن للعقدة الجديدة فيجب ان يؤشرر علرى العقردة التري هري‬
‫االولى قبل االضافة حيث ستصبح العقدة الثانية بعد االضافة (يوضرع عنروان العقردة‬
‫االولى فيه)‪.‬‬
‫ولكي ننجز ربط العقدة الجديدة بالعقدة التي كانت هري االولرى فرالمفروض ان تكرون‬
‫العقدة الجديدة قبلها عند االضافة كمرا اسرلفنا‪ ,‬لرذلك فران حقرل العنروان االيسرر للعقردة‬
‫التي كانت االولى سيوضع به عنوان العقدة الجديدة )‪.(temp‬‬
‫اخيرا يتم تسمية العقدة الجديدة باسم عقدة البداية ‪ ,start‬الح الشكل ‪.6.33‬‬

‫شك ‪ :6.33‬كيفية ربط ال قدة الجديدة في بداية القائمة الثنائية‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫; ‪temp -> prev = null‬‬

‫; ‪temp -> data = value‬‬

‫; ‪temp -> next = start‬‬

‫; ‪start -> prev = temp‬‬

‫; ‪start = temp‬‬

‫شك ‪ :6.34‬القائمة الثنائية ب د االضافة‪.‬‬

‫اضافة عقدة في موقع محد في القائمة‬ ‫‪.D‬‬


‫يتم خلل عقدة جديدة وتضاف البيانات الى حقل البيانات في العقدة الجديدة‪.‬‬
‫في هذل الحالة يتم تحديد الموقع المراد االضافة بعدل او قبله‪.‬‬
‫يوضع مؤشر على عقدة البداية او العقدة االولى‪.‬‬
‫يتم عمل حلقة تكرار من العقدة االولى الى الموقع المراد االضافة بعردل او قبلره (فري‬
‫القوائم الثنائية نحتاج مؤشر واحد يوضع على عقردة البدايرة فري كرل االحروال ولريس‬
‫كما في القوائم االحادية التي احيانا نحتاج مؤشرين)‪.‬‬
‫في كل دورة يتم نقل المؤشرر الرى العقردة الالحقرة‪ .‬مرع مالحظرة ضررورة التأكرد مرن‬
‫عدم الوصول الى العقدة االخيرة (اذا تم الوصول الرى العقردة االخيررة قبرل الوصرول‬
‫الى الموقع المطلوب يتم اظهار رسالة تفيد بان الموقع خارج حجم القائمة)‪.‬‬

‫‪243‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫عند الوصل الى العقدة المراد االضافة بعدها او قبلها‪ ,‬نتبع الخطوات التاليرة لغررض‬
‫اتمام عملية االضافة‪ ,‬في هذل الحالة لدينا احتماالن‪..‬‬
‫‪ )a‬االول ان تكون االضافة بعد العقدة المحددة وهنا لدينا احتماالن‪:‬‬
‫‪ ‬االحتمال االول‪ ..‬ان تكون العقدة المراد االضافة بعردها هري العقردة االخيررة‬
‫عندها تتم االضافة كما سبل وان وضحنا عند االضافة في نهاية القائمة‪.‬‬

‫شك ‪ :6.35‬اضافة عقدة بين عقدتينب االضافة ب د عقدة محد ة‪.‬‬

‫‪ ‬االحتمال االخر ان تكون االضرافة فري وسرط القائمرة عنردها نتبرع الخطروات‬
‫التالية (الشكل ‪:)6.35‬‬
‫نضع عنوان العقدة الالحقة للعقدة المراد االضافة بعردها (عنوانهرا موجرود فري حقرل‬
‫العنوان االيمن للعقدة ‪ )q‬في حقل العنوان االيمن للعقدة الجديدة‪.‬‬
‫نضع عنوان العقدة التي سنضيف بعدها في حقل العنوان االيسر للعقدة المضافة‪.‬‬
‫نضع عنوان العقدة الجديدة فري حقرل العنروان االيسرر للعقردة التري تلري العقردة المرراد‬
‫االضافة بعدها‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫كذلك نضع عنوان العقدة الجديدة في حقل العنوان االيمن للعقدة التي سنضيف بعدها‬
‫; ‪temp -> next = q -> next‬‬

‫; ‪temp -> prev = q‬‬

‫; ‪q -> next -> prev = temp‬‬

‫; ‪q - > next = temp‬‬

‫‪ )b‬االحتمال الثاني هو ان تكون االضافة قبل العقدة المحددة فري القائمرة‪ ..‬وهنرا‬
‫لدينا احتماالن ايضا‪:‬‬
‫‪ ‬االحتمررال االول ان تكررون االضررافة قبررل العقرردة االولررى وبهررذا سررنتبع ذات‬
‫الخطوات ل ضافة قبل العقدة االولى‪.‬‬
‫‪ ‬االحتمال الثاني تكون االضافة وسرط القائمرة‪ ,‬وسروف ال يختلرف كثيررا عرن‬
‫االضررافة بعررد عقرردة محررددة‪ ,‬بدايررة نحررر مؤشررر ليصررل الررى العقرردة المررراد‬
‫االضافة قبلها‪ ..‬يم تتم اضافة عنوان العقدة الجديدة في حقل العنروان االيسرر‬
‫للعقدة المحددة المراد االضافة قبلها‪ ,‬وفي حقل العنوان االيمن للعقدة السابقة‬
‫للعقردة المحررددة (وعنوانهررا موجررود فرري حقررل العنرروان االيسررر للعقرردة المحردد‬
‫االضافة قبلها)‪.‬‬
‫يررتم اضررافة عنرروان العقرردة المحرردد االضررافة قبلهررا فرري حقررل العنرروان االيم رن‬
‫للعقدة الجديدة‪ ,‬ويضاف حقل عنروان العقردة السرابقة للعقردة المحردد االضرافة‬
‫قبلها في حقل العنوان االيسر للعقدة الجديدة‪ ,‬الشكل ‪.6.36‬‬

‫‪245‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.36‬اضافة عقدة بين عقدتينب االضافة قب عقدة محد ة‪.‬‬

‫; ‪temp -> next = q‬‬

‫; ‪temp -> prev = q -> prev‬‬

‫; ‪q -> prev = temp‬‬


‫; ‪q -> prev -> next = temp‬‬

‫شك ‪ :6.37‬القائمة ب د عملية االضافة في الوسط‬

‫حذذ عنصر‬ ‫‪.E‬‬


‫عملية الحرذف هنرا تعتمرد علرى ايجراد العقردة التري تحتروي قيمرة معينرة او محرددة فري‬
‫موقع معرين ليرتم حرذفها‪ ,‬و نجراز عمليرة الحرذف علينرا ان نالحر االحتمراالت التري‬
‫تكون عليها العقدة المطلوبة وكما يلي‪:‬‬
‫‪ )a‬االحتمال االول ان تكرون العقردة المطلروب حرذفها هري العقردة االولرى عنردها‬
‫نتبع الخطوات التالية ألجراء عملية حذف العقدة االولى‪ ,‬الشكل ‪.6.38‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.38‬حذذ عقدة من بداية القائمة الموصولة الثنائية‪.‬‬

‫بداية نحف عنوان العقدة االولى بمتغير نسميه مثال ‪( temp‬نستفيد منه لحف عنوان‬
‫العقدة المحذوفة وامكانية تحرير مساحتها الحقا باستخدام هذا االسم)‪.‬‬
‫نسمي العقدة الثانية باسم عقدة البداية اي نسميها ‪.start‬‬
‫نضع ‪ null‬في حقل العنوان االيسر للعقدة الثانية ( مرن الخطروة السرابقة فران العقردة‬
‫الثانيرة اصرربحت هرري عقردة البدايررة)‪ .‬عنرروان العقردة الثانيررة موجررود فري حقررل العنرروان‬
‫االيمن للعقدة االولى‪.‬‬
‫يتم تحرير مساحة العقدة المحذوفة‪.‬‬
‫; ‪temp = start‬‬

‫; ‪start = start -> next‬‬

‫; ‪start -> prev = null‬‬

‫; )‪free (temp‬‬

‫شك ‪ :6.39‬القائمة ب د ا راء الحذذ‪.‬‬


‫‪ )b‬االحتمال الثاني هو ان تكون العقدة المطلوب حذفها هي بين عقدتين عندها نتبع‬
‫الخطوات التالية للحذف‬

‫‪247‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.40‬حذذ عقدة بين عقدتين في قائمة موصولة ثنائية‪.‬‬

‫نضع مؤشر على عقدة البداية لنسميه ‪.q‬‬


‫نعمررل حلقررة تكرررار مررن اول عقرردة فرري القائمررة لحررين الوصررول الررى العقرردة المطلرروب‬
‫حذفها‪ ,‬شكل ‪.6.40‬‬
‫االن نبرردأ عمليررة الحررذف‪ ,‬وهرري ببسرراطة تتضررمن ربررط العقرردة السررابقة للعقرردة الم رراد‬
‫حذفها مع العقدة الالحقة للع قدة المرراد حرذفها وبهرذا تكرون هرذل العقردة المرراد حرذفها‬
‫خارج القائمة‪.‬‬
‫هذا يتم بوضع عنوان العقردة الالحقرة للعقردة المرراد حرذفها فري حقرل العنروان االيمرن‬
‫للعقدة السابقة للعقدة المراد حذفها (عنوان العقدة السرابقة للعقردة التري نرغرب بحرذفها‬
‫يكون موجود في حقل العنوان االيسر للعقدة المرراد حرذفها‪ ,‬وعنروان العقردة الالحقرة‬
‫للعقدة المطلوب حذفها يكون في حقرل العنروان االيمرن لعقردة المطلروب حرذفها)‪ ,‬كمرا‬
‫هو واضح في الشكل ‪.6.40‬‬
‫نضررع عنرروان العقرردة السررابقة للعقرردة المررراد حررذفها فرري حقررل العنرروان االيسررر للعقرردة‬
‫الالحقة للعقدة المراد حذفها‪.‬‬
‫يتم تحرير مساحة العقدة المحذوفة‪ .‬نفرض المطلوب حذف عقردة تحمرل قيمرة معينرة‬
‫عندها نتبع االيعازات التالية‪:‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫; ‪q = start‬‬

‫) ‪while (q -> next != null‬‬

‫{‬

‫; ) ‪if (q -> data == value‬‬ ‫{‬


‫; ‪q -> next -> prev = q -> prev‬‬

‫; ‪q -> prev -> next = q -> next‬‬

‫; ”‪cout << “Elemrnt Deleted \n‬‬

‫; )‪free (q‬‬

‫} } ; ‪break‬‬

‫شك ‪ :6.41‬القائمة ب د حذذ ال قدة‪.‬‬


‫‪ )c‬االحتمال االخير هو ان تكون العقدة المرراد حرذفها هري العقردة االخيررة عنرد‬
‫ذا نتبع الخطوات التالية‪:‬‬

‫الشك ‪ :6.42‬حذذ ال قدة النهائية من القائمة الموصولة الثنائية‪.‬‬

‫‪249‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫كما سبل ووضحنا ان المؤشر الذي وضعنال على العقدة االولى وتم تحريكه سيصل‬
‫الررى العقرردة المطلرروب حررذفها‪ ,‬وفرري هررذل الحالررة سررتكون العقرردة المطلرروب حررذفها هري‬
‫العقدة االخيرة (العقردة االخيررة يرتم التعررف عليهرا مرن فحرص حقرل العنروان االيمرن‬
‫حيث سنجد به ‪ ,)null‬شكل ‪.6.43‬‬

‫شك ‪ :6.43‬وصول المؤشر الل ال قدة االويرة‪.‬‬

‫لكرري نحررذف هررذل العقرردة فرران العقرردة السررابقة لهررا سررتكون هرري االخيرررة لررذلك مررن‬
‫المفروض ان يكون حقل العنوان االيمن للعقدة السابقة للعقدة االخيررة المرراد حرذفها‬
‫يحمل القيمة ‪.null‬‬
‫عليه ضع ‪ null‬في حقل العنوان االيمن للعقدة السابقة للعقدة االخيرة (الح هنا ان‬
‫عنوان العقدة السابقة للعقردة االخيررة يكرون موجرود فري حقرل العنروان االيسرر للعقردة‬
‫االخيرة)‪.‬‬
‫تحرير مساحة العقدة االخيرة المحذوفة‪.‬‬
‫; ‪q -> prev -> next = null‬‬

‫; )‪free (q‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.44‬القائمة ب د حذذ ال قدة االويرة‪.‬‬

‫القائمة‬ ‫عر‬ ‫‪.F‬‬


‫نضع مؤشر على عقدة البداية‪.‬‬
‫نعمل حلقة تكرار من العقدة االولى الى العقدة االخيرة‪.‬‬
‫فرري كررل دورة يررتم عرررض بيانررات العقرردة الترري يؤشررر عليه را المؤشررر ومررن يررم ننقررل‬
‫المؤشر الى العقدة الالحقة‪.‬‬
‫; ‪q = start‬‬

‫)‪while ( q != null‬‬

‫{‬

‫; ‪q = q -> next‬‬

‫}‬

‫حساب عد ال قد‬ ‫‪.G‬‬


‫نضع مؤشر على العقدة االولى‪.‬‬
‫نحدد عداد وله قيمة ابتدائية مقدارها صفر‪.‬‬
‫نعمل حلقة تكرار تبدا من العقدة االولى وتنتهي بالعقدة االخيرة‪.‬‬
‫في كل دورة عندما ينتقل المؤشر الى العقدة الالحقة يتم زيادة العداد بمقدار واحد‪.‬‬
‫بعد انتهاء حلقة التكرار سيكون العداد يحمل قيمة تمثل عدد العقد في القائمة‪.‬‬
‫; ‪int count = 0‬‬

‫; ‪q = start‬‬

‫)‪while (q != null‬‬

‫‪251‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫{‬

‫; ‪q = q -> next‬‬

‫; ‪count ++‬‬

‫}‬
‫; ‪cout<< “ Number of nodes in linked list =” << count‬‬

‫عكس القائمة‬ ‫‪.H‬‬

‫عمليررة عكررس القائمررة الموصررولة الثنائيررة (اي ان تكررون العقرردة االولررى هرري االخيرررة‬
‫والعقدة االخيرة هي االولى) ال تعتبرر عمليرة صرعبة او معقردة وانمرا هري عمليرة فري‬
‫غايررة السررهولة‪ ,‬كررل مرراهو مطلرروب ان تكررون العقرردة االولررى هرري االخيرررة والعقرردة‬
‫االخيرررة هرري االولررى‪ ,‬وجميررع العقررد يررتم عكسررها بعمليررة ابرردال العنرراوين فرري حقررول‬
‫العناوين االيمن وااليسر للعقدة (بمعنى ان يكون حقل العنوان االيمرن‪ ..‬ايسرر وحقرل‬
‫العنوان االيسر‪ ..‬ايمن)‪ .‬الح هنا ان العقدة الثانيرة سرتكون العقردة قبرل االخيررة الن‬
‫العقدة االولى اصبحت االخيرة وهكذا‪.‬‬
‫نخلل مؤشرين ونضع احدهما على العقدة االولى )‪ (p1‬والمؤشر الثاني على العقردة‬
‫الثانية )‪.(p2‬‬
‫االن نجعل في حقل العنوان االيمن للمؤشر االول القيمة ‪.null‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.45‬شك توضيحي لبريقة عكس القائمة الموصولة الثنائية‪.‬‬

‫يوضررع فرري حقررل العنرروان االيسررر للعقرردة الترري يؤشررر عليهررا المؤشررر االول (العقرردة‬
‫االولى في هذل الحالة) عنوان العقدة التي يؤشر عليها المؤشر الثاني (اي هذل العقدة‬
‫ستؤشر على المؤشر الثاني ‪.) p2‬‬
‫خلل حلقة تكرار يكون فيها شرط التوقف هو ان المؤشر الثاني ‪ p2‬يساوي ‪.null‬‬
‫داخل حلقة التكرار سيكون ما يلي‬
‫سننقل العقد الى مواقع سرابقة للعقردة االولرى وحسرب ترتيبهرا كمرا فري الشركل ‪,6.45‬‬
‫هذا يتم من خالل تغيير قيم العناوين في حقول العناوين للعقد‪ ,‬كما يلي‪:‬‬
‫في العقردة التري يؤشرر عليهرا المؤشرر الثراني ‪ ,p2‬وضرع العنروان الموجرود فري حقرل‬
‫العنوان االيمن في حقل العنوان االيسر‪.‬‬
‫وضررع عنرروان العقرردة الترري يؤشررر عليهررا المؤشررر ‪ p1‬فرري حقررل العنرروان االيمررن (اي‬
‫وضع ‪ p1‬في حقل العنوان االيمن)‪.‬‬
‫نقل المؤشرين عقدة واحدة (دائما يبقى المؤشران متجاوران)‪ .‬الح هنا ان المؤشر‬
‫االول تم نقله الى العقدة التي يؤشرر عليهرا المؤشرر الثراني وال مشركلة برذلك = ‪(p1‬‬
‫)‪ , p2‬بينمررا المؤشررر الثرراني فرري الخطرروة الثانيررة يررتم نقلرره الررى العقرردة الالحقررة لهررا‬
‫باستخدام ايعاز يبدو ظاهريا انه ينقله الى العقدة السابقة وليس الالحقة حسب االيعاز‬
‫)‪ (p2 = p2 -> prev‬وسربب ذلرك ألننرا اساسرا فري خطروة سرابقة غيرنرا قيمرة هرذا‬
‫الحقررل (حقررل عنرروان العقرردة السررابقة) بحررث وضررعنا فيرره عنرروان العقرردة الالحقررة لررذل‬
‫اقتضى التنويه)‪.‬‬
‫بعد انتهاء او توقف التكرار يتم وضع عنوان المؤشر االول ‪ p1‬في المتغير ‪.start‬‬

‫‪253‬‬
C++ ‫هياكل البيانات باستخدام‬

p1 = start ;

p2 = p1 -> next ;

p1 ->next = null ;

p1 -> prev = p2 ;

while (p2 != null )

p2 -> prev = p2 ->next ;


p2 -> next = p1 ;

p1 = p2 ;

p2 = p2 ->prev ;

‫ البرنامج الكامل لجميع العمليات التي تجرى على القوائم الموصولة الثنائية‬

/*

* C++ Program to Implement Doubly Linked List


*/

#include<iostream>

#include<cstdio>

#include<cstdlib>

/*

* ‫االعالن عن العقدة‬
C++ ‫هياكل البيانات باستخدام‬

*/

using namespace std;

struct node

int info;

struct node *next;

struct node *prev;

}* start;

/*

‫االعالن عن الصنف‬

*/

class double_llist

public:

void create_list(int value);

void add_begin(int value);

void add_after(int value, int position);

void delete_element(int value);

void search_element(int value);

void display_dlist( );

void count( );

void reverse( );

255
C++ ‫هياكل البيانات باستخدام‬

double_llist( ) ;

start = NULL ;

};

int main( )
{

int choice, element, position;

double_llist dl;

while (1)

cout<<endl<<"----------------------------"<<endl;

cout<<endl<<"Operations on Doubly linked list"<<endl;

cout<<endl<<"----------------------------"<<endl ;

cout<<"1.Create Node"<<endl;

cout<<"2.Add at begining"<<endl;

cout<<"3.Add after position"<<endl;

cout<<"4.Delete"<<endl;

cout<<"5.Display"<<endl;

cout<<"6.Count"<<endl;

cout<<"7.Reverse"<<endl;
C++ ‫هياكل البيانات باستخدام‬

cout<<"8.Quit"<<endl;

cout<<"Enter your choice : " ;

cin>>choice;

switch ( choice )

case 1:

cout<<"Enter the element :" ;

cin>>element;

dl.create_list(element);

cout<<endl;

break;

case 2:

cout<<"Enter the element :" ;

cin>>element;

dl.add_begin(element);

cout<<endl;

break;

case 3:

cout<<"Enter the element :" ;

cin>>element;

cout<<"Insert Element after postion :" ;

cin>>position ;

dl.add_after(element, position) ;

257
C++ ‫هياكل البيانات باستخدام‬

cout<<endl ;

break;

case 4:

if (start == NULL)

cout<<"List empty,nothing to delete"<<endl ;

break;
}

cout<<"Enter the element for deletion : " ;

cin>>element;

dl.delete_element(element) ;

cout<<endl;

break;

case 5:

dl.display_dlist( ) ;

cout<<endl;

break;

case 6:

dl.count( ) ;

break ;

case 7:

if (start == NULL)
C++ ‫هياكل البيانات باستخدام‬

cout<<"List empty, nothing to reverse"<<endl;

break;

dl.reverse( ) ;

cout<<endl;

break;

case 8:

exit(1) ;

default:

cout<<"Wrong choice"<<endl;

return 0;

/*

* ‫خلق قائمة موصولة ثنائية‬


*/

void double_llist::create_list (int value)

struct node *s, *temp;

temp = new(struct node) ;

259
C++ ‫هياكل البيانات باستخدام‬

temp->info = value;

temp->next = NULL;

if (start == NULL)

temp->prev = NULL;

start = temp;

}
else

s = start;

while (s->next != NULL)

s = s->next;

s->next = temp;

temp->prev = s;

/*

* ‫االضافة في بداية القائمة‬


*/

void double_llist::add_begin(int value)

{
C++ ‫هياكل البيانات باستخدام‬

if (start == NULL)

cout<<"First Create the list."<<endl;

return;

struct node *temp;

temp = new(struct node) ;

temp->prev = NULL;

temp->info = value;

temp->next = start;

start->prev = temp;

start = temp;

cout<<"Element Inserted"<<endl;

/*

* ‫اضافة عنصر في موقع محدد في القائمة‬


*/

void double_llist::add_after(int value, int pos)

if (start == NULL)

cout<<"First Create the list."<<endl;

261
C++ ‫هياكل البيانات باستخدام‬

return;

struct node *tmp, *q ;

int i;

q = start;

for (i = 0;i < pos - 1; i+)+

{
q = q->next;

if (q == NULL)

cout<<"There are less than " ;

cout<<pos<<" elements."<<endl;

return;

tmp = new(struct node) ;

tmp->info = value;

if (q->next == NULL)

q->next = tmp;

tmp->next = NULL;

tmp->prev = q ;
C++ ‫هياكل البيانات باستخدام‬

else

tmp->next = q->next;

tmp->next->prev = tmp;

q->next = tmp;

tmp->prev = q;

cout<<"Element Inserted"<<endl;

/*

* ‫حذف عنصر من القائمة‬


*/

void double_llist::delete_element (int value)

struct node *tmp, *q ;

*/ first element deletion/*

if (start->info == value)

tmp = start;

start = start->next ;

start->prev = NULL;

cout<<"Element Deleted"<<endl;

263
C++ ‫هياكل البيانات باستخدام‬

free(tmp) ;

return;

q = start;

while (q->next->next != NULL)

/ * ‫ * حذف عنصر بين عقدتين‬/


if (q->next->info == value)

tmp = q->next;

q->next = tmp->next;

tmp->next->prev = q;

cout<<"Element Deleted"<<endl;

free(tmp) ;

return;

q = q->next;

/ * ‫حذف العنصر االخير‬ */

if (q->next->info == value)

tmp = q->next;
C++ ‫هياكل البيانات باستخدام‬

free (tmp) ;

q->next = NULL;

cout<<"Element Deleted"<<endl;

return;

cout<<"Element "<<value<<" not found"<<endl;

/*

* ‫عرض عناصر القائمة الموصولة الثنائية‬


*/

void double_llist::display_dlist ( )

struct node *q;

if (start == NULL)

cout<<"List empty,nothing to display"<<endl;

return;

q = start;

cout<<"The Doubly Link List is :"<<endl;

while (q != NULL)

265
C++ ‫هياكل البيانات باستخدام‬

cout<<q->info<<" >-< " ;

q = q->next;

cout<<"NULL"<<endl;

/*
* ‫حساب عدد العناصر في القائمة الموصولة الثنائية‬
*/

void double_llist::count ( )

struct node *q = start;

int cnt = 0;

while (q != NULL)

q = q->next;

cnt++ ;

cout<<"Number of elements are: "<<cnt<<endl;

/*

* ‫عكس القائمة الموصولة الثنائية‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪*/‬‬

‫) (‪void double_llist::reverse‬‬

‫{‬

‫;‪struct node *p1, *p2‬‬

‫;‪p1 = start‬‬

‫;‪p2 = p1->next‬‬

‫;‪p1->next = NULL‬‬

‫;‪p1->prev = p2‬‬

‫)‪while (p2 != NULL‬‬

‫{‬

‫;‪p2->prev = p2->next‬‬

‫;‪p2->next = p1‬‬

‫;‪p1 = p2‬‬

‫; ‪p2 = p2->prev‬‬

‫}‬

‫;‪start = p1‬‬

‫; ‪cout<<"List Reversed"<<endl‬‬

‫}‬

‫مالحظ ة ‪ :‬عمليررة تحرردث بيانررات عقرردة فرري القرروائم الموصررولة الثنائيررة التختلررف ع رن‬
‫عملية تحدث بيانات عقدة في القوائم الموصولة االحادية‪.‬‬

‫‪ 6.11‬القوائم الموصولة الدائرية ‪Circular Linked Lists‬‬

‫‪267‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫القوائم الموصولة الدائرية هي مشابهة للقوائم الموصولة االعتياديرة االحاديرة ماعردا‬


‫ان مؤشر العقردة االخيررة او العنصرر االخيرر يؤشرر الرى العنصرر االول فري القائمرة‬
‫(في القوائم االحادية كان يؤشر الى ‪.)null‬‬

‫يجب عليك ان تتسائل‪ ..‬لمراذا يريرد اي شرخص لعمرل شريء مثرل هرذا ؟ حسرنا ‪..‬هرل‬
‫تعلم ان القوائم الموصولة الدائريرة تسرتخدم غالبرا فري حراالت متعرددة ولهرا تطبيقرات‬
‫عديدة‪ ,‬على سبيل المثال هي من الممكن ان تستخدم في االعالنات االلكترونية حيث‬
‫ان كل اعالن يضاف الى القائمرة ويرتم عرضره بعرد اخرر اعرالن ترم عرضره‪ ,‬وبرذلك‬
‫فان القائمة ستعرض بشكل الي اول اعالن في القائمة‪ .‬في العقد الدائرية من الممكرن‬
‫ان يكررون هنررا مؤشرررين يررتم حفظهمررا وهمررا مؤشررر العقرردة االولررى ومؤشررر العقرردة‬
‫االخيرة‪.‬‬

‫شك ‪ :6.46‬قائمة موصولة ثنائية‬

‫هنا عدد من العمليرات التري مرن الممكرن اجرائهرا علرى القروائم الموصرولة الدائريرة‬
‫كما في حالة القوائم الموصولة االحادية (في كل العمليات التري نرروم انجازهرا علرى‬
‫القرروائم الموصررولة الثنائيررة علينررا اوال ان نتأكررد ان القائمررة ليسررت فارغررة وهررذا ينجررز‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫بفحص المؤشر ‪ last‬فاذا كان يؤشرر الرى ‪ null‬فران القائمرة فارغرة وبخالفرة القائمرة‬
‫ليست فارغة)‪.‬‬
‫ال مليات التي تنجز علل القوائم الدائرية‬ ‫‪6.11.1‬‬
‫التختلف القوائم الدائرية عن باقي انواع القوائم الموصولة مرن حيرث العمليرات التري‬
‫تنجز على القائمة‪ ,‬فقط هنا اختالف بسريط بعمليرة التنفيرذ وشرفرة البرنرامج‪ ,‬بشركل‬
‫عام فان العمليات التي تنفذ على القوائم الدائرية هي‪:‬‬
‫‪ .A‬خلل عقدة‪.‬‬
‫‪ .B‬اضافة عقدة في نهاية القائمة‪.‬‬
‫‪ .C‬اضافة عقدة في بداية القائمة‪.‬‬
‫‪ .D‬اضافة عقدة بين عقدتين‪.‬‬
‫‪ .E‬حذف عقدة‪.‬‬
‫‪ .F‬عرض القائمة‪.‬‬
‫‪ .G‬تحديث القائمة‪.‬‬
‫‪ .H‬ترتيب عناصر القائمة‪.‬‬

‫‪ .A‬ولر عقدة‬
‫يتم ابتداء خلل عقدة جديدة ويوضع لهرا اسرم او مؤشرر باسرم معرين يؤشرر علرى هرذل‬
‫العقدة وهو يمثل اسم هذل العقدة (نفرض ان اسم المؤشر هو ‪.) temp‬‬
‫تضاف البيانات المحددة لهذل العقدة‪ ,‬تضاف الى حقل البيانات‪.‬‬
‫يتم فحص المؤشر ‪( last‬الذي يمثل عنوان العقدة االخيررة المسرماة ‪ ) last‬فراذا كران‬
‫يؤشر على ‪( null‬هذا يعني عدم وجود عقد في القائمة اي ان القائمة فارغة) عنردها‬
‫نجعل اسم العقدة التي تم خلقها في حقل عنروان العقردة الالحقرة للعقردة التري ترم خلقهرا‬
‫(اي انها ستؤشر على نفسها)‪ ,‬ويعاد تسمية ‪ last‬برنفس اسرم العقردة االولرى (اي ان‬
‫‪ start & last‬سيشيران الى نفس العنوان)‪.‬‬

‫‪269‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .B‬اضافة عقدة الل نهاية القائمة الموصولة الدائرية‬

‫في هذل الحالرة يرتم خلرل عقردة جديردة كمرا اسرلفنا وتسرند البيانرات فري حقرل البيانرات‬
‫للعقدة الجديدة‪.‬‬
‫بعد وضع البيانات يتم تغيير عنوان العقدة الالحقة للعقدة التي ترم خلقهرا بحيرث يسرند‬
‫له ذات العنوان الموجود في حقل عنوان العقدة االخيرة في القائمة (طالما هذل العقدة‬
‫الجديرردة سررتكون االخيرررة لررذلك البررد ان تؤشررر علررى العقرردة االولررى كمررا كانررت العقرردة‬
‫االخيرة في القائمة تؤشر)‪.‬‬
‫الخطوة التالية ان يتم ربط العقدة التي هي االن اخيرة مع العقردة الجديردة لكري تكرون‬
‫الجديدة هي االخيرة‪.‬‬

‫شك ‪ :6.47‬اضافة عقدة في نهاية القائمة مع توضيح لكيفية وضع ال ناوين وربط ال قدة‪.‬‬

‫;‪temp->next = last->next‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫االن سررنجعل حقررل العنرروان فرري العقرردة الترري هرري االخيرررة قبررل االضررافة يؤشررر علررى‬
‫العقدة التي تم خلقها وهي العقدة ‪temp‬‬
‫; ‪last -> next = temp‬‬

‫اخيرا يتم تغير اسم العقدة التي تم خلقها لتكون باسم ‪ last‬بدال من ‪temp‬‬
‫;‪last = temp‬‬

‫م حظة‪ :‬من الممكن عدم استخدام المؤشر ‪ ,last‬في هرذل الحالرة نضرع مؤشرر علرى‬
‫العقدة االولى ونحركه ليصل العقدة االخيرة (العقردة االخيررة هري العقردة التري يكرون‬
‫فيها مؤشر العقردة الالحقرة يسراوي عنروان العقردة االولرى ولريس ‪ null‬كمرا سربل فري‬
‫االنواع االخرى)‪.‬‬

‫شك ‪ :6.48‬القائمة ب د اضافة ال قدة‪.‬‬

‫اضافة عقدة في البداية‬ ‫‪.C‬‬

‫‪271‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫يتم خلل عقدة جديدة‪ ,‬واسناد قيمة الى حقل البيانرات فري العقردة الجديردة‪ .‬ربرط العقردة‬
‫التي تم خلقها الى بداية القائمة‪.‬‬
‫تتم عملية الربط بوضع عنوان العقدة االولى في حقل العنروان للعقردة التري ترم خلقهرا‬
‫(الن العقدة االولى فري القائمرة سرتكون العقردة الثانيرة بعرد االضرافة)‪ ,‬وبرذلك سرتكون‬
‫هررذل العقرردة الترري تررم خلقهررا سررابقة للعقرردة االولررى فرري القائمررة اي سررتكون هرري العقرردة‬
‫االولى وكما يلي‬
‫; ‪temp->next = last->next‬‬
‫‪OR‬‬

‫; ‪temp -> next = start‬‬

‫شك ‪ :6.49‬طريقة ربط ال قدة في بداية القائمة وتغيير ال ناوين‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫الح هنا (شكل ‪ )6.49‬ان عنوان العقدة االولى هو موجود في حقل العنروان للعقردة‬
‫االخيرة ‪ ,last‬لذلك من الممكن الحصول عليه من هنا واسنادل الى العقردة التري ترم‬
‫خلقهررا كمررا وضررحنا اعررالل واعررادة تسررمية العقرردة المضررافة بحيررث تكررون ه ري العقرردة‬
‫االولررى )‪ ,(start‬ومررن الممكررن ايضررا اسررتخدامه بشرركل مباشررر مررن العقرردة االولررى‬
‫)‪.(start‬‬
‫الخطوة االخيرة هي جعل مؤشر العقردة االخيررة يؤشرر علرى العقردة التري وضرعناها‬
‫في البداية‪ ,‬واعادة تسمية العقدة الجديدة باسم عقدة البداية‪ ,‬وكما يلي‬
‫; ‪last->next = temp‬‬

‫; ‪start = temp‬‬

‫شك ‪ :6.50‬القائمة ب د االضافة‪.‬‬


‫اضافة عقدة في موقع م ين‬ ‫‪.D‬‬

‫وهي ال تختلف عن طريقة االضافة في القوائم االحادية‪ ,‬لرذلك سروف ال نتطررق لهرا‬
‫ومن الممكن الرجوع الى اضافة عقدة بين عقدتين في القوائم االحادية‪.‬‬

‫حذذ عقدة تحتوي علل عنصر م ين‬ ‫‪.E‬‬

‫اذا لم تكن القائمة فارغة فران هنرا اكثرر مرن احتمرال‪ .‬طبعرا البرد مرن وضرع مؤشرر‬
‫على العقدة االولى‪ ,‬ليكن اسمه مثال )‪ (S‬لكل الحاالت‪:‬‬

‫‪273‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ )a‬الحالة االولل‪ :‬هو ان تكون القائمة متكونة مرن عقردة واحردة فقرط وهرذا مرن‬
‫الممكن فحصة وذلك بان يكون عنوان العقدة الالحقة هو ذاته عنروان العقردة‬
‫ولها قيمة في حقل القيمة مساوي للقيمة المطلوبة اذا تحقرل هرذين الشررطين‬
‫فهذا يعني وجود عقدة واحدة وسيتم حذفها لنحصل على قائمة فارغة‪.‬‬
‫حررذف هرررذل العقررردة يكررون بحفررر عنررروان العقررردة بمتغيررر‪ ,‬يرررم حرررذف العقررردة‬
‫بمساواتها الى ‪ null‬ومن بعدها تحريرر (المسراحة) التري كانرت تشرغلها هرذل‬
‫العقدة وكما يلي‬
‫;‪temp = last‬‬

‫;‪last = null‬‬

‫; )‪free (temp‬‬
‫‪ )b‬الحالةةة الثانيةةة‪ :‬هررو ان القيمررة المطلوبررة موجررودة فرري العقرردة االولررى لقائمررة‬
‫تحتوي على اكثر من عقدة‪ ,‬عملية الحذف تتم كما يلي‪:‬‬

‫شك ‪ :6.51‬حذذ عقدة من قائمة موصولة ائرية‪.‬‬

‫بداية البد من حف عنوان العقدة االولى بمتغير من نوع مؤشر‪.temp‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.52‬كيفية تغيير ال ناوين عند حذذ عقدة‪.‬‬

‫يررتم وضررع عنرروان العقرردة الثانيررة وهررو العنرروان الررذي يوجررد فرري حقررل العنرروان للعقردة‬
‫االولى في حقل العنوان للعقدة االخير (شكل ‪.)6.52‬‬
‫تسمية العقدة الثانية باسم عقدة البداية ‪.start‬‬
‫يتم تحرير المساحة الخاصة بالعقدة االولى ‪ temp‬وكما يلي‬

‫;‪last->next = temp -> next‬‬


‫; ‪temp -> next = start‬‬
‫; )‪free (temp‬‬

‫شك ‪ :6.53‬القائمة ب د الحذذ‪.‬‬

‫الحالة الثالثة‪ :‬هو حذف عقدة تكرون وسرط القائمرة وهرذا يرتم برنفس الطريقرة‬ ‫‪)c‬‬
‫التي استخدمت بحذف عقدة في وسط قائمة موصولة احادية‪.‬‬

‫‪275‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الحالةةة الراب ةة‪ :‬هررو ان تكررون العقرردة المطلرروب حررذفها هرري العقرردة االخيرررة‬ ‫‪)d‬‬
‫عندها سيتم وضع مؤشرين االول على العقدة االولى )‪ (S‬والثاني على العقدة الثانية‬
‫)‪ (temp‬ويتم تحريكهم بواقع عقدة واحدة في كرل مررة علرى ان يرتم المحافظرة علرى‬
‫تموضع المؤشرين على عقدتين متجاورتين دائما‪ ,‬يتم التوقف عنرد وصرول المؤشرر‬
‫الثاني )‪ (temp‬الى العقدة النهائية‪.‬‬
‫يررتم تغييررر العنرراوين بمررا يضررمن حررذف العقرردة االخيرررة وذلررك بوضررع عنرروان العقرردة‬
‫االولى في حقرل العنروان للعقردة السرابقة للعقردة االخيررة والتري يؤشرر عليهرا المؤشرر‬
‫االول )‪.(S‬‬
‫يعاد تسمية العقدة التي يؤشر عليها المؤشر االول باسم ‪last‬‬
‫تحرير مساحة العقدة المحذوفة‬
‫;‪s->next = last->next‬‬

‫;‪last = s‬‬

‫;)‪free (temp‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.54‬حذذ ال قدة االويرة وتوضيح كيفية تغيير ال ناوين‪.‬‬

‫القائمة‬ ‫عر‬ ‫‪.F‬‬

‫يوضررع مؤشررر علررى العقرردة االولررى يررم يررتم نقلرره الررى العقرردة المجرراورة وهكررذا لحررين‬
‫الوصول الى نهاية القائمة‪.‬‬
‫هذل العملية تتم باستخدام حلقة تكرار تبدا من اول عقدة وتنتهي باخر عقدة‪.‬‬
‫في كل عقدة يتم المرور عليها يرتم عررض القيمرة الموجرودة فري حقرل البيانرات لتلرك‬
‫العقدة‪.‬‬

‫تحديث القائمة‬ ‫‪.G‬‬

‫عملية التحديث هري عمليرة تغييرر القيمرة التري فري حقرل البيانرات لعقردة مرا فري موقرع‬
‫معين داخل القائمة‪.‬‬
‫نجاز ذلك نضع مؤشر على اول عقدة‪.‬‬
‫نعمل حلقة تكرار من اول عقدة الى الموقع المحدد‪.‬‬
‫ننقل المؤشر في كل مرة الى العقدة الالحقة‪.‬‬
‫عند الوصول الى الموقع المطلوب يتم تغيير القيمة في حقل البيانات لتلك العقدة‪.‬‬
‫اذا وصل المؤشر الى العقدة االخيررة قبرل ان يرتم ايجراد العقردة المطلوبرة‪ ,‬عنردها يرتم‬
‫عرض رسالة توضح ان الموقع المطلوب خارج حجم القائمة‪.‬‬

‫ترتيب القائمة‬ ‫‪.H‬‬

‫نتبع نفس الطريقة في ترتيب القوائم االحادية‪.‬‬

‫‪277‬‬
C++ ‫هياكل البيانات باستخدام‬

‫ برنامج كامل لجميع العمليات التي تجرى على القوائم الموصولة الدائرية‬
/*

* C++ Program to Implement Circular Linked List

*/

#include<iostream>

#include<cstdio>
#include<cstdlib>

using namespace std;

/*

* ‫االعالن عن العقدة‬

*/

struct node

int info;

struct node *next;

}*last;

/*

* ‫االعالن عن الصنف‬

*/

class circular_llist
C++ ‫هياكل البيانات باستخدام‬

public:

void create_node(int value);

void add_begin(int value);

void add_after(int value, int position);

void delete_element(int value);

void search_element(int value);

void display_list( );

void update();

void sort();

circular_llist( )

last = NULL;

};

int main()

int choice, element, position;

circular_llist cl;

while (1)

cout<<endl<<"---------------------------"<<endl;

279
C++ ‫هياكل البيانات باستخدام‬

cout<<endl<<"Circular singly linked list"<<endl;

cout<<endl<<"---------------------------"<<endl;

cout<<"1.Create Node"<<endl;

cout<<"2.Add at beginning"<<endl;

cout<<"3.Add after"<<endl;

cout<<"4.Delete"<<endl;

cout<<"5.Search"<<endl;
cout<<"6.Display"<<endl;

cout<<"7.Update"<<endl;

cout<<"8.Sort"<<endl;

cout<<"9.Quit"<<endl;

cout<<"Enter your choice : ";

cin>>choice;

switch(choice)

case 1:

cout<<"Enter the element: ";

cin>>element;

cl.create_node(element);

cout<<endl;

break;

case 2:
C++ ‫هياكل البيانات باستخدام‬

cout<<"Enter the element: ";

cin>>element;

cl.add_begin(element);

cout<<endl;

break;

case 3:

cout<<"Enter the element: ";

cin>>element;

cout<<"Insert element after position: ";

cin>>position;

cl.add_after(element, position);

cout<<endl;

break;

case 4:

if (last == NULL)

cout<<"List is empty, nothing to delete"<<endl;

break;

cout<<"Enter the element for deletion: ";

cin>>element;

cl.delete_element(element);

cout<<endl;

281
C++ ‫هياكل البيانات باستخدام‬

break;

case 5:

if (last == NULL)

cout<<"List Empty!! Can't search"<<endl;

break;

}
cout<<"Enter the element to be searched: ";

cin>>element;

cl.search_element(element);

cout<<endl;

break;

case 6:

cl.display_list();

break;

case 7:

cl.update();

break;

case 8:

cl.sort();

break;

case 9:
C++ ‫هياكل البيانات باستخدام‬

exit(1);

break;

default:

cout<<"Wrong choice"<<endl;

return 0;

/*

* ‫خلق قائمة موصولة‬

*/

void circular_llist::create_node(int value)

struct node *temp;

temp = new(struct node);

temp->info = value;

if (last == NULL)

last = temp;

temp->next = last;

else

283
C++ ‫هياكل البيانات باستخدام‬

temp->next = last->next;

last->next = temp;

last = temp;

/*

* ‫اضافة عنصر الى بداية القائمة‬

*/

void circular_llist::add_begin(int value)

if (last == NULL)

cout<<"First Create the list."<<endl;

return;

struct node *temp;

temp = new(struct node);

temp->info = value;

temp->next = last->next;

last->next = temp;
C++ ‫هياكل البيانات باستخدام‬

/*

* ‫اضافة عنصر في موقع محدد‬

*/

void circular_llist::add_after(int value, int pos)

if (last == NULL)

cout<<"First Create the list."<<endl;

return;

struct node *temp, *s;

s = last->next;

for (int i = 0;i < pos-1;i++)

s = s->next;

if (s == last->next)

cout<<"There are less than ";

cout<<pos<<" in the list"<<endl;

return;

285
C++ ‫هياكل البيانات باستخدام‬

temp = new(struct node);

temp->next = s->next;

temp->info = value;

s->next = temp;

/*‫*اضافة عنصر الى نهاية القائمة‬/

if (s == last)
{

last=temp;

/*

* ‫حذف عنصر من القائمة‬

*/

void circular_llist::delete_element(int value)

struct node *temp, *s;

s = last->next;

/* ‫*اذا كانت القائمة تحتوي فقط عنصر واحد‬/

if (last->next == last && last->info == value)

{
C++ ‫هياكل البيانات باستخدام‬

temp = last;

last = NULL;

free(temp);

return;

if (s->info == value) /*‫*حذف العنصر االول‬/

temp = s;

last->next = s->next;

free(temp);

return;

while (s->next != last)

/*‫*حذف عنصر بين عنصرين‬/

if (s->next->info == value)

temp = s->next;

s->next = temp->next;

free(temp);

cout<<"Element "<<value;

cout<<" deleted from the list"<<endl;

return;

287
C++ ‫هياكل البيانات باستخدام‬

s = s->next;

/*‫*حذف العنصر االخير‬/

if (s->next->info == value)

temp = s->next;
s->next = last->next;

free(temp);

last = s;

return;

cout<<"Element "<<value<<" not found in the list"<<endl;

/*

* ‫البحث عن عنصر في القائمة‬

*/

void circular_llist::search_element(int value)

struct node *s;

int counter = 0;

s = last->next;
C++ ‫هياكل البيانات باستخدام‬

while (s != last)

counter++;

if (s->info == value)

cout<<"Element "<<value;

cout<<" found at position "<<counter<<endl;

return;

s = s->next;

if (s->info == value)

counter++;

cout<<"Element "<<value;

cout<<" found at position "<<counter<<endl;

return;

cout<<"Element "<<value<<" not found in the list"<<endl;

/*

* ‫عرض محتويات القائمة الموصولة الدائرية‬

289
C++ ‫هياكل البيانات باستخدام‬

*/

void circular_llist::display_list()

struct node *s;

if (last == NULL)

cout<<"List is empty, nothing to display"<<endl;


return;

s = last->next;

cout<<"Circular Link List: "<<endl;

while (s != last)

cout<<s->info<<"->";

s = s->next;

cout<<s->info<<endl;

/*

* ‫تحديث القائمة الموصولة الدائرية‬

*/
C++ ‫هياكل البيانات باستخدام‬

void circular_llist::update()

int value, pos, i;

if (last == NULL)

cout<<"List is empty, nothing to update"<<endl;

return;

cout<<"Enter the node position to be updated: ";

cin>>pos;

cout<<"Enter the new value: ";

cin>>value;

struct node *s;

s = last->next;

for (i = 0;i < pos - 1;i++)

if (s == last)

cout<<"There are less than "<<pos<<" elements.";

cout<<endl;

return;

s = s->next;

291
C++ ‫هياكل البيانات باستخدام‬

s->info = value;

cout<<"Node Updated"<<endl;

/*

* ‫ترتيب القائمة الموصولة الدائرية‬


*/

void circular_llist::sort()

struct node *s, *ptr;

int temp;

if (last == NULL)

cout<<"List is empty, nothing to sort"<<endl;

return;

s = last->next;

while (s != last)

ptr = s->next;

while (ptr != last->next)


C++ ‫هياكل البيانات باستخدام‬

if (ptr != last->next)

if (s->info > ptr->info)

temp = s->info;

s->info = ptr->info;

ptr->info = temp;

else

break;

ptr = ptr->next;

s = s->next;

Circular Doubly ‫ القةةوائم الموصةةولة الدائريةةة الثنائيةةةة‬6.12


Linked List

293
‫هياكل البيانات باستخدام ‪C++‬‬

‫تختلف القروائم الموصرولة الدائريرة الثنائيرة عرن االنرواع االخررى التري سربل وان ترم‬
‫التطرق لها‪ ..‬حيث ان كل عقدة هنا تحتوي على حقلين للعنوان بدل من حقرل واحرد‪,‬‬
‫احدهما يوضع به عنوان العقدة السابقة (وهو حقل العنوان االيسرر)‪ ,‬امرا الثراني فهرو‬
‫حقل عنوان العقدة الالحقة والذي هو (حقل العنوان االيمن)‪ ..‬وبالتالي فان كل عقردة‬
‫من الممكن ان نعرف من خاللها العقدة السابقة لها والعقدة الالحقة لها‪ ,‬مرع مالحظرة‬
‫ان العقدة االولى تشير الى العقدة االخيررة والعقردة االخيررة تشرير الرى العقردة االولرى‬
‫اذا كانت القائمة تحتوي على اكثر من عقدة‪.‬‬

‫شك ‪ :6.55‬قائمة موصولة ائرية ثنائية‪.‬‬

‫ال مليات التي تجرى علل القوائم الموصولة الثنائية الدائرية‬ ‫‪6.12.1‬‬
‫هنا عدد من العمليرات التري مرن الممكرن اجرائهرا علرى القروائم الموصرولة الدائريرة‬
‫الثنائية وهي‪:‬‬
‫‪ .A‬اضافة عقدة في بداية القائمة الموصولة‪.‬‬
‫‪ .B‬اضافة عقدة في نهاية القائمة‪.‬‬
‫‪ .C‬اضافة عقدة في موقع محدد ضمن القائمة‪.‬‬
‫‪ .D‬حذف عقدة من القائمة‪.‬‬
‫‪ .E‬تحديث القائمة‪.‬‬
‫‪ .F‬البحث عن عقدة داخل القائمة‪.‬‬
‫‪ .G‬الترتيب‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .H‬عرض محتويات القائمة‪.‬‬

‫م حظة ‪ :‬في كل العمليات اعالل والتي سيتم توضيحها الحقا سيتم فررض اسرم عقردة‬
‫البداية ‪ start‬واسم عقدة النهاية ‪ last‬والعقدة التي يتم خلقها نسميها ‪.temp‬‬
‫كررذلك فرري كررل العمليررات علينررا ابتررداء ان نفحررص القائمررة فيمررا اذا كانررت فارغررة او ال‬
‫وتكون القائمة فارغة اذا كانت عقدة البداية تساوي عقدة النهاية (اي لهم نفس االسم)‬
‫وعقدة البداية تساوي ‪.null‬‬
‫المتغيرات هنا والتي ندعوها اسماء للعقد )‪ (start, last, temp‬هي في حقيقتها من‬
‫نوع مؤشر اي تحمل عنوان‪.‬‬

‫اضافة عقدة الل القائمة‬ ‫‪.A‬‬


‫لغرض اضافة عقدة في اي مكان من القائمة البد بداية من خلرل عقردة يرم ترتم عمليرة‬
‫االضررافة‪ ,‬اذن نخلررل عقرردة جديرردة كمررا سرربل وان شرررحنا فرري خلررل العقررد الثنائيررة‪,‬‬
‫ونضيف قيمة الى حقل البيانات في العقدة‪.‬‬
‫هنا عدد من الحاالت التي تتم بها االضافة وهي‪:‬‬
‫‪ )a‬اضافة عقدة في بداية القائمة‪.‬‬
‫نضرريف عنرروان العقرردة االولررى فرري القائمررة فرري حقررل العنرروان االيمررن للعقرردة المررراد‬
‫اضافتها (نظرا الى ان العقدة ستضراف قبرل العقردة االولرى فري القائمرة لرذلك سرتكون‬
‫هي االولى)‪.‬‬

‫‪295‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.56‬اضافة عقدة الل قائمة موصولة ثنائية ائرية‪.‬‬

‫في حقل العنوان االيسرر للعقردة االولرى التري فري القائمرة سنضرع عنروان العقردة التري‬
‫سيتم اضافتها )‪( (temp‬الن العقدة المضافة ستضاف قبل العقدة االولرى فري القائمرة‬
‫وستكون الحقا هي العقدة االولى)‪.‬‬
‫االن بعررد ان اصرربحت العقرردة االولررى تؤشررر علررى العقرردة المضررافة والعقرردة المضررافة‬
‫تؤشر على العقدة االولى اصبح واضحا ان العقدة المضافة اصبحت هي قبرل البدايرة‬
‫(العقدة االولى ) لذلك من المناسب ان نسميها العقدة االولى وذلرك بران نضرع عنروان‬
‫العقرردة الترري سنضرريفها فرري المؤشررر ‪( start‬أي ان يررتم تسررمية العقرردة المضررافة باسررم‬
‫‪ ,) start‬شكل ‪.6.57‬‬

‫شك ‪ :6.57‬توضيح لكيفية ربط ال قدة المضافة في بداية القائمة‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫االن بقى لدينا حقل العقدة السابقة في العقدة المضافة (حقل العنوان االيسر) ليس فيه‬
‫عنوان‪ ,‬ولما كانت القائمة دائريرة فسنضرع عنروان العقردة االخيررة فري حقرل العنروان‬
‫االيسر للعقدة المضافة‪.‬‬

‫شك ‪ :6.58‬شك توضيحي لكيفية ربط ال قدة االولل مع االويرة‪.‬‬

‫كررذلك فرران العقرردة االخيرررة كانررت تشررير فرري حقررل عنرروان العقرردة الالحقررة الررى العقرردة‬
‫االولررى الترري اصرربحت االن يانيررة بعررد االضررافة‪ ,‬لررذلك يجررب تحديثرره وذلررك بإضررافة‬
‫عنوان العقدة المضافة التي هي االن اولى وغيرنا اسمها الى العقدة االولى في حقرل‬
‫العنوان االيمن للعقدة االخيرة (الن القائمة دائرية)‪.‬‬
‫;‪temp->next = start‬‬

‫;‪start->prev = temp‬‬

‫;‪start = temp‬‬

‫;‪start->prev = last‬‬

‫;‪last->next = start‬‬

‫‪297‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.59‬القائمة ب د االضافة‪.‬‬

‫‪ )b‬اضافة عقدة في نهاية القائمة‬

‫شك ‪ :6.60‬اضافة عقدة الل نهاية القائمة الموصولة الثنائية الدائرية‪.‬‬

‫ان العمررل االسرراس هررو اضررافة عنرراوين فرري حقررل العنرراوين للعقرردة المضررافة وحقررل‬
‫العنوان االيمن للعقدة االخيرة في القائمة وكذلك حقل العنوان االيسر للعقردة االولرى‪,‬‬
‫مع مالحظة ان العقدة االخيرة ستكون العقدة ما قبل االخيرة عند اضافة عقدة بعردها‬
‫(الن العقرردة المضررافة سررتكون هرري االخيرررة) لررذلك فرران هررذل العقرردة الترري كانررت ه ري‬
‫االخيرة ستشير في حقل العنوان االيمن الى العقدة المضافة وليس الى العقدة االولرى‬
‫كما كانت قبل االضافة‪.‬‬
‫بالنسرربة للعقرردة المضررافة سنضرريف عنرروان العقرردة الالحقررة فرري حقررل العنرروان االيم رن‬
‫والتي هي العقدة االولى نظرا الن هذل العقدة ستصبح اخر عقدة في القائمة الدائرية‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.61‬توضيح كيفية ربط ال قدة المضافة مع ال قدة االولل وال قدة االولل م ها‪.‬‬

‫في حقل العنوان االيسر للعقدة المضافة سنضيف عنوان العقدة التي كانرت هري اخرر‬
‫عقدة النها ستكون سابقة للعقدة المضافة‪.‬‬
‫يتم ابدال اسم العقدة المضرافة الرى العقردة االخيررة )‪ (last‬النهرا اصربحت هري العقردة‬
‫االخيرة‪.‬‬

‫شك ‪ :6.62‬توضيح ربط ال قدة االويرة مع ال قدة المضافة‪.‬‬

‫بالنسبة للعقدة االولى فانها كانت تشير الى عنروان العقردة االخيررة فري حقرل العنروان‬
‫االيسر‪ ,‬ولما كانت العقردة االخيررة قرد ترم تغييرهرا لرذلك يجرب تحرديث حقرل العنروان‬
‫االيسر للعقدة االولى ليشير الى العقدة المضافة التي هي اصبحت العقدة االخيرة‪.‬‬
‫;‪last->next = temp‬‬

‫;‪temp->prev = last‬‬

‫;‪last = temp‬‬

‫;‪start->prev = last‬‬

‫‪299‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪last->next = start‬‬

‫شك ‪ :6.63‬القائمة ب د االضافة‪.‬‬


‫‪ )c‬اضافة عقدة في موقع محد‬
‫نتبع نفس خطوات االضافة لعقدة وسط القائمة الثنائية‪.‬‬

‫حذذ عقدة في موقع محد‬ ‫‪.B‬‬


‫يجرب تحديرد الموقرع المرراد حررذف العقردة منره ونتاكرد مررن ان هرذا الموقرع هرو ضررمن‬
‫حدود او اقل من عدد العقد في القائمة‪.‬‬
‫االن نحذف العقدة حسب االحتماالت التالية‬
‫‪ )a‬اذا كان موقع الحذف هو واحد اي انه العقدة االولى نعمل ما يلي‬

‫شك ‪ :6.64‬حذذ ال قدة االولل في قائمة ثنائية ائرية‪.‬‬

‫بداية يتم حف عنوان العقدة االولى بمتغير من نوع مؤشر ليكن ‪.S‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫نغير عنوان العقدة الالحقة في حقل العنوان االيمن للعقدة االخيررة ليشرير الرى العقردة‬
‫الثانية في القائمة بدال من االولى التي سيتم حذفها (عنوان العقدة الثانيرة موجرود فري‬
‫حقل العنوان االيمن للعقدة االولى)‪.‬‬
‫نضع عنوان العقدة االخيررة فري حقرل العنروان االيسرر للعقردة الثانيرة (وبهرذا سرتكون‬
‫العقدة االولى خارج القائمة)‪ .‬يجب ان نغير تسمية العقدة الثانية لتكون العقدة االولى‬
‫‪.start‬‬
‫نحرر مساحة العقدة االولى التي تم ازالتها والتي تم حف عنوانها بالمتغير‪.S‬‬

‫حذذ ال قدة االولل‬ ‫شك ‪ :6.65‬تغيير ال ناوين لغر‬

‫;‪S = start‬‬

‫;‪last->next = S->next‬‬

‫;‪S->next-> prev = last‬‬

‫;‪start = S->next‬‬

‫;)‪free (S‬‬

‫‪301‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫اذا كانت العقدة المراد حذفها هي ليست العقدة االولى وانمرا عقردة فري موقرع‬ ‫‪)b‬‬
‫معررين داخررل القائمررة نتبررع ذات الخطرروات الترري تررم توضرريحها فرري حررذف عقرردة بررين‬
‫عقدتين في القوائم الثنائية‪.‬‬

‫اذا كانت العقدة المراد حذفها هي العقدة االخيرة عندها نتبع الخطوات التالية‬ ‫‪)c‬‬

‫شك ‪ :6.66‬حذذ ال قدة االويرة في قائمة موصولة ثنائية ائرية‪.‬‬

‫نحر مؤشر واحد من عقدة البداية لحين الوصول الى العقدة االخيرة (نفرض اسمه‬
‫‪.)S‬‬
‫يررتم ربررط العقرردة الترري تسرربل العقرردة االخيرررة بالعقرردة االولررى وبررذلك ستصرربح العقرردة‬
‫االخيرة التي يؤشر عليها المؤشر ‪ S‬خارج القائمة (في القوائم الثنائية عنروان العقردة‬
‫السابقة ألي عقدة يكون موجود في حقل العنوان االيسر)‪.‬‬
‫يعاد تسمية العقدة التي تسبل العقدة االخيرة باسم ‪.last‬‬
‫يتم تحرير المساحة للعقدة المحذوفة‪.‬‬
‫م حظة‪ :‬اذا كنا نعلم مسبقا ان المطلوب هو حذف العقدة االخيرة فمن الممكن انجاز‬
‫ذلك دون الحاجة لتمرير مؤشرين وذلك باالعتماد على عنوان العقدة االخيرة ‪. last‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :6.67‬شك توضيحي لكيفية ربط ال قدة السابقة لل قدة االويرة مع ال قدة االولل لغر‬
‫حذذ ال قدة االويرة‪.‬‬

‫من الممكن وضع عنوان العقدة االولى مباشرة في حقرل العنروان االيسرر للعقردة قبرل‬
‫االخيرة كما واضح من الخط المنقط اعلى الشكل ‪.6.67‬‬
‫; ‪S -> prev -> next = start‬‬

‫ومررن الممكررن ايضررا وضررع العنرروان االيمررن فرري العقرردة االخيرررة (وهررو يحمررل عنرروان‬
‫العقدة االولرى) فري حقرل العنروان االيمرن للعقردة قبرل االخيررة كمرا واضرح مرن الخرط‬
‫المتصل اسفل الشكل ‪.6.67‬‬
‫; ‪S -> prev -> next = S -> next‬‬

‫; ‪S -> prev = last‬‬

‫‪303‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الشك ‪ :6.68‬القائمة ب د الحذذ‪.‬‬

‫التحديث‬ ‫‪.C‬‬
‫نحدد الموقع المراد تحديث بياناته‪.‬‬
‫نحدد قيمة البيانات المراد ادخالها في حقل البيانات للعقدة المطلوب تحديث بياناتها‪.‬‬
‫اذا كان الموقع هو الموقع االول (بمعنى العقدة االولى) يتم تحديثها‪ ,‬بخالف ذلك‬
‫نضع مؤشر على العقدة االولى ونحركه الى نهاية القائمرة وفري كرل مررة مرن البدايرة‬
‫الى الن هاية نفحص البيانات للعقردة التري يؤشرر عليهرا المؤشرر فراذا كانرت هري العقردة‬
‫المطلوبة يتم تحديث بياناتها والخروج من حلقة التكرار‪.‬‬

‫;‪S = start‬‬

‫‪do‬‬

‫{‬

‫)‪if (S -> data == value‬‬

‫; ‪{ S -> data = new_value‬‬

‫;‪cout<<"Node Updated"<<endl‬‬

‫; ‪break‬‬

‫}‬

‫; ‪S = S -> next‬‬

‫; )‪} while (S != start‬‬

‫محتويات القائمة‬ ‫عر‬ ‫‪.D‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫نضرع مؤشررر علررى العقرردة االولررى‪ .‬نعمررل حلقررة تكرررار مررن العقرردة االولررى الررى العقردة‬
‫االخيرة‪.‬‬
‫في كل دورة يتم اظهر او طباعة البيانات في حقل البيانات للعقدة التري يؤشرر عليهرا‬
‫المؤشر‪ .‬وفي كل دورة يتم نقل المؤشر الى العقدة الالحقة‪.‬‬
‫;‪S = start‬‬

‫)‪while ( S != last‬‬

‫{‬

‫;‪S = S -> next‬‬

‫; ">‪cout<< S -> data << "<-‬‬

‫}‬

‫; ‪cout<< S-> data << endl‬‬

‫‪ ‬البرنامج الكامل لجميع العمليات التي تجرى على القوائم الموصولة الثنائية‬

‫*‪/‬‬

‫‪* C++ Program to Implement Circular Doubly Linked List‬‬

‫‪*/‬‬

‫>‪#include<iostream‬‬

‫>‪#include<cstdio‬‬

‫>‪#include<cstdlib‬‬

‫;‪using namespace std‬‬

‫*‪/‬‬

‫‪305‬‬
C++ ‫هياكل البيانات باستخدام‬

* ‫االعالن عن العقدة‬

*/

struct node

int info;

struct node *next;

struct node *prev;


}*start, *last;

int counter = 0;

/*

* ‫االعالن عن الصنف‬

*/

class double_clist

public:

node *create_node (int);

void insert_begin();

void insert_last();

void insert_pos();

void delete_pos();

void search();

void update();
C++ ‫هياكل البيانات باستخدام‬

void display();

void reverse();

void sort();

double_clist( )

start = NULL;

last = NULL;

};

int main()

int choice;

double_clist cdl;

while (1)

cout<<"\n-------------------------------"<<endl;

cout<<"Operations on Doubly Circular linked list"<<endl;

cout<<"\n-------------------------------"<<endl;

cout<<"1.Insert at Beginning"<<endl;

cout<<"2.Insert at Last"<<endl;

cout<<"3.Insert at Position"<<endl;

cout<<"4.Delete at Position"<<endl;

307
C++ ‫هياكل البيانات باستخدام‬

cout<<"5.Update Node"<<endl;

cout<<"6.Search Element"<<endl;

cout<<"7.Sort"<<endl;

cout<<"8.Display List"<<endl;

cout<<"9.Reverse List"<<endl;

cout<<"10.Exit"<<endl;

cout<<"Enter your choice : ";


cin>>choice;

switch(choice)

case 1:

cdl.insert_begin();

break;

case 2:

cdl.insert_last();

break;

case 3:

cdl.insert_pos();

break;

case 4:

cdl.delete_pos();

break;
C++ ‫هياكل البيانات باستخدام‬

case 5:

cdl.update();

break;

case 6:

cdl.search();

break;

case 7:

cdl.sort();

break;

case 8:

cdl.display();

break;

case 9:

cdl.reverse();

break;

case 10:

exit(1);

default:

cout<<"Wrong choice"<<endl;

return 0;

309
C++ ‫هياكل البيانات باستخدام‬

/*

* ‫تخصيص الذاكرة للعقد بشكل الي‬

*/

node* double_clist::create_node(int value)

counter++;
struct node *temp;

temp = new(struct node);

temp->info = value;

temp->next = NULL;

temp->prev = NULL;

return temp;

/*

* ‫اضافة عنصر في البداية‬

*/

void double_clist::insert_begin()

int value;

cout<<endl<<"Enter the element to be inserted: ";

cin>>value;
C++ ‫هياكل البيانات باستخدام‬

struct node *temp;

temp = create_node (value);

if (start == last && start == NULL)

cout<<"Element inserted in empty list"<<endl;

start = last = temp;

start->next = last->next = NULL;

start->prev = last->prev = NULL;

else

temp->next = start;

start->prev = temp;

start = temp;

start->prev = last;

last->next = start;

cout<<"Element inserted"<<endl;

/*

* ‫اضافة عنصر في نهاية القائمة‬

*/

311
C++ ‫هياكل البيانات باستخدام‬

void double_clist::insert_last()

int value;

cout<<endl<<"Enter the element to be inserted: ";

cin>>value;

struct node *temp;

temp = create_node(value);
if (start == last && start == NULL)

cout<<"Element inserted in empty list"<<endl;

start = last = temp;

start->next = last->next = NULL;

start->prev = last->prev = NULL;

else

last->next = temp;

temp->prev = last;

last = temp;

start->prev = last;

last->next = start;

}
C++ ‫هياكل البيانات باستخدام‬

/*

* ‫اضافة عنصر في موقع داخل القائمة‬

*/

void double_clist::insert_pos()

int value, pos, i;

cout<<endl<<"Enter the element to be inserted: ";

cin>>value;

cout<<endl<<"Enter the postion of element inserted: ";

cin>>pos;

struct node *temp, *s, *ptr;

temp = create_node(value);

if (start == last && start == NULL)

if (pos == 1)

start = last = temp;

start->next = last->next = NULL;

start->prev = last->prev = NULL;

else

313
C++ ‫هياكل البيانات باستخدام‬

cout<<"Position out of range"<<endl;

counter--;

return;

else

{
if (counter < pos)

cout<<"Position out of range"<<endl;

counter--;

return;

s = start;

for (i = 1;i <= counter;i++)

ptr = s;

s = s->next;

if (i == pos - 1)

ptr->next = temp;

temp->prev = ptr;
C++ ‫هياكل البيانات باستخدام‬

temp->next = s;

s->prev = temp;

cout<<"Element inserted"<<endl;

break;

/*

* ‫حذف عقدة من موقع محدد في القائمة‬

*/

void double_clist::delete_pos()

int pos, i;

node *ptr, *s;

if (start == last && start == NULL)

cout<<"List is empty, nothing to delete"<<endl;

return;

cout<<endl<<"Enter the postion of element to be deleted: ";

cin>>pos;

if (counter < pos)

315
C++ ‫هياكل البيانات باستخدام‬

cout<<"Position out of range"<<endl;

return;

s = start;

if(pos == 1)

{
counter--;

last->next = s->next;

s->next->prev = last;

start = s->next;

free(s);

cout<<"Element Deleted"<<endl;

return;

for (i = 0;i < pos - 1;i++ )

s = s->next;

ptr = s->prev;

ptr->next = s->next;

s->next->prev = ptr;
C++ ‫هياكل البيانات باستخدام‬

if (pos == counter)

last = ptr;

counter--;

free(s);

cout<<"Element Deleted"<<endl;

/*

* ‫تحديث قيمة او بيانات عقدة محددة‬

*/

void double_clist::update()

int value, i, pos;

if (start == last && start == NULL)

cout<<"The List is empty, nothing to update"<<endl;

return;

cout<<endl<<"Enter the postion of node to be updated: ";

cin>>pos;

cout<<"Enter the new value: ";

cin>>value;

317
C++ ‫هياكل البيانات باستخدام‬

struct node *s;

if (counter < pos)

cout<<"Position out of range"<<endl;

return;

s = start;
if (pos == 1)

s->info = value;

cout<<"Node Updated"<<endl;

return;

for (i=0;i < pos - 1;i++)

s = s->next;

s->info = value;

cout<<"Node Updated"<<endl;

/*

* ‫البحث عن عنصر في القائمة‬


C++ ‫هياكل البيانات باستخدام‬

*/

void double_clist::search()

int pos = 0, value, i;

bool flag = false;

struct node *s;

if (start == last && start == NULL)

cout<<"The List is empty, nothing to search"<<endl;

return;

cout<<endl<<"Enter the value to be searched: ";

cin>>value;

s = start;

for (i = 0;i < counter;i++)

pos++;

if (s->info == value)

cout<<"Element "<<value<<" found at position: "<<pos<<endl;

flag = true;

s = s->next;

319
C++ ‫هياكل البيانات باستخدام‬

if (!flag)

cout<<"Element not found in the list"<<endl;

/*

* ‫ترتيب القائمة الموصولة الثنائية الدائرية‬

*/
void double_clist::sort()

struct node *temp, *s;

int value, i;

if (start == last && start == NULL)

cout<<"The List is empty, nothing to sort"<<endl;

return;

s = start;

for (i = 0;i < counter;i++)

temp = s->next;

while (temp != start)

{
C++ ‫هياكل البيانات باستخدام‬

if (s->info > temp->info)

value = s->info;

s->info = temp->info;

temp->info = value;

temp = temp->next;

s = s->next;

/*

* ‫عرض محتويات القائمة‬

*/

void double_clist::display()

int i;

struct node *s;

if (start == last && start == NULL)

cout<<"The List is empty, nothing to display"<<endl;

return;

321
C++ ‫هياكل البيانات باستخدام‬

s = start;

for (i = 0;i < counter-1;i++)

cout<<s->info<<"<->";

s = s->next;

cout<<s->info<<endl;
}

/*

* ‫عكس ترتيب القائمة الموصولة الثنائية الدائرية‬

*/

void double_clist::reverse()

if (start == last && start == NULL)

cout<<"The List is empty, nothing to reverse"<<endl;

return;

struct node *p1, *p2;

p1 = start;

p2 = p1->next;

p1->next = NULL;
C++ ‫هياكل البيانات باستخدام‬

p1->prev = p2;

while (p2 != start)

p2->prev = p2->next;

p2->next = p1;

p1 = p2;

p2 = p2->prev;

last = start;

start = p1;

cout<<"List Reversed"<<endl;

323
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص السابع‬
‫االستدعاء الذاتي ‪RECURSION‬‬

‫‪ 7.1‬المقدمة‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫فكرة االعادة )‪ (recursive‬ليست معروفة بشكل عام في العالم الحقيقي‪ ,‬ولذلك فهي‬
‫ربما تبدو مربكة للمبرمج المبتديء‪ .‬عليه‪ ,‬فراني اتوقرع بامكانيرة اسرتخدامهم مبراديء‬
‫االعادة بشكل تدريجي‪.‬‬
‫احيانا تكون المشكلة صعبة جدا او معقدة جدا لكي يمكن حلها وذلك النها كبيرة جدا‪.‬‬
‫فاذا كان من الممكن تجزأة المشكلة الى نسا صغيرة مشابه لالصل‪ ,‬فربما يكون من‬
‫الممكن ايجاد طريقة لحل واحدة من هذل النسا الصغيرة وبهذا سنكون قرادرين علرى‬
‫بناء حل لكامل المشكلة‪ .‬هذل هي الفكرة ما وراء االعرادة )‪ ,(recursive‬خوارزميرة‬
‫االعادة تجزأ المشكلة الى اجزاء صغيرة والتي ربمرا تكرون اجابتهرا معروفرة مسربقا‪,‬‬
‫او من الممكن حلها بتطبيل نفس الخوارزمية على كل جزء صغير‪ ,‬وبعدها يتم دمج‬
‫الحلول‪.‬‬
‫االسررتدعاء الررذاتي هرري عمليررة اعررادة العناصررر نفسررها وبررنفس الطريقررة‪ .‬فرري لغررات‬
‫البرمجررة‪ ,‬اذا البرنررامج سررمح لررك السررتدعاء الدالررة مررن داخررل نفررس الدالررة‪ ,‬فعنررد ذلررك‬
‫تدعى االستدعاء الذاتي للدالة‪.‬‬
‫لغة ‪ C++‬تدعم االستدعاء الذاتي‪ ,‬بمعنرى دالرة تسرتدعي نفسرها‪ .‬ولكرن عنرد اسرتخدام‬
‫االستدعاء الذاتي‪ ,‬المبرمجين بحاجة الن يكونوا حذرين بتعريف شرط الخروج مرن‬
‫الدالة‪ ,‬في خالف ذلك فانها ستذهب (الدالة) بحلقة تكرار ال نهائية‪.‬‬

‫‪ 7.2‬االعا ة ‪Recursion‬‬
‫االعادة في علم الحاسروب هري طريقرة تسرتند الرى مفهروم حرل المشركلة اعتمرادا علرى‬
‫حلرول الحرراالت الصررغيرة لررنفس المشرركلة (عكرس التكرررار)‪ .‬الطريقررة مررن الممكررن ان‬
‫تطبررل علررى العديررد مررن المشرراكل‪ ,‬واالعررادة هرري واحررد مررن االفكررار الرئيسررية لعلرروم‬
‫الحاسوب‪.‬‬

‫‪325‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫دوال االستدعاء الذاتي مفيدة جردا لحرل العديرد مرن مشراكل الرياضريات‪ ,‬مثرل حسراب‬
‫مضروب رقم معين‪ ,‬توليد متوالية ‪ Fibonacci‬وغيرها‪.‬‬
‫ان قوة االستدعاء الذاتي يكمن في امكانية تعريف مجموعة غير محددة من الكيانات‬
‫بواسطة عبارات محددة‪ .‬بنفس الطريقة‪ ,‬عدد غير محردد مرن الحسرابات مرن الممكرن‬
‫وصفها بواسطة برنامج استدعاء ذاتي‪ ,‬حتى وان كان هذا البرنرامج ال يحتروي علرى‬
‫تكرارات خارجية‪ .‬خوارزميات االسرتدعاء الرذاتي‪ ,‬هري مناسربة مبردئيا عنردما تكرون‬
‫المشرركلة قابلررة للحررل‪ ,‬او الدالررة الترري نبرمجهررا او هيكررل البيانررات الترري تعررالج هرري‬
‫باالساس معرفة بداللة االستدعاء الذاتي‪.‬‬
‫ولكرري نبسررط الموضرروع سررنتطرق الررى الرردمى الروسررية‪ ,‬فهررل سرربل لررك أن رأيررت‬
‫مجموعة من الدمى الروسية؟ في البداية‪ ،‬ترى مجرد تمثال واحد من الخشب ويرسم‬
‫عليه نقوش لتبدو كما في الشكل ‪.7.1‬‬

‫شك ‪ :7.1‬الدمل الروسية تبدو مية واحدة‪.‬‬

‫االن لو رفعت النصف العلوي من الدمية االولى‪ ,‬فماذا سترى في داخلها؟ سترى ان‬
‫هنا دمية روسية اصغر منها قليال‪ .‬كما في الشكل ‪.7.2‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :7.2‬الدمية الروسية ب د رفع النصف االعلل من الدمية االولل‪.‬‬

‫من الممكن ان تزيل هذل الدمية االصرغر وتفصرل النصرف العلروي والنصرف السرفلي‬
‫للدمية الثانية‪ .‬سترى دمية اخرى اصغر منها قليال شكل ‪.7.3‬‬

‫شك ‪ :7.3‬الدمل الروسية ب د فتح الدمية الثانية‪.‬‬

‫ان االسررتمرار بهررذا العمررل (فررتح كررل دميررة اليجرراد دميررة اخرررى داخلهررا) سرريؤدي الررى‬
‫الحصول على مجموعة من الدمى وكل واحردة هري اصرغر مرن سرابقتها قلريال (علمرا‬
‫بانها جميعا كانت ضمن دمية واحدة رئيسية) وكما في الشكل ‪.7.4‬‬

‫‪327‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الشك ‪ :7.4‬الدمل الروسية ب د فتح ميع الدمل‪.‬‬

‫الح هنا اننا بدأنا بدمية كبيرة وتم التجزئة الى مجموعة من الردمى اصرغر فاصرغر‬
‫لحين الوصول الى دمية صغير جدا بحيث التحتوي على دمية اصغر منها‪.‬‬
‫ما عملنال للدمى الروسية سنعمله للخوارزميات‪ ,‬فان المشكلة الكبيرة مرن الممكرن ان‬
‫تجزأ الى مشاكل اصرغر واصرغر مشرابهة للمشركلة الكبيررة االصرلية لحرين الوصرول‬
‫الى جزء صغير اليمكن تجزأته ومن الممكن حلها بشركل مباشرر‪ .‬هرذل التقنيرة تردعى‬
‫االعادة (او االستدعاء الذاتي)‪.‬‬

‫‪ 7.3‬كيف يستالد االستدعاء الذاتي‬


‫مرن االفضرل ان يسرتخدم االسرتدعاء الرذاتي عنردما تكرون لردينا مهمرة كبيررة )‪,(task‬‬
‫ومررن الممكررن تجزئتهررا الررى مهمررات جزئيررة فرعيررة مكررررة‪ .‬والن دالررة االسررتدعاء‬
‫تستدعي نفسها نجاز المهمة الجزئية‪ ,‬لذا فري النهايرة فران الدالرة سرتاتي علرى مهمرة‬
‫جزئية بدون ان تستدعي نفسها‪ .‬وهرذل تعررف الحالرة االسراس )‪ ,(base case‬ونحتراج‬
‫لها لمنع الدالة من استدعاء نفسها مرة بعد مرة بدون توقف‪ .‬لذلك مرن الممكرن القرول‬
‫بان الحالة االساس توقف االستدعاء الذاتي‪.‬‬
‫في الحالة االسراس‪ ,‬فران الدالرة ال تسرتدعي نفسرها‪ .‬ان اسرتدعاء الدالرة نفسرها لغررض‬
‫انجاز مهمتها الجزئية‪ ,‬تعرف بانها حالة االعادة )‪.(recursive case‬‬
‫هنا نوعين من الحاالت عند استخدام خوارزمية االستدعاء الذاتي (حالرة االسراس‪,‬‬
‫وحالة االعادة)‪ .‬هذل من المهم جدا ترذكرها عنرد اسرتخدام االسرتدعاء الرذاتي‪ ,‬وعنردما‬
‫تحرراول حررل مشرركلة عليررك ان تسررال نفسررك‪ " :‬مرراهي حررالتي االسرراس‪ ,‬ومرراهي حالررة‬
‫االعادة"‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫ان كلمة االستدعاء الذاتي تعني " ان لها صفات الن تعود مرة يانية‪ ,‬او تتكررر"‪ .‬ان‬
‫عملية استدعاء الدالة لنفسها تسرمى اسرتدعاء مباشرر وجميرع االمثلرة فري هرذا الفصرل‬
‫هري مرن نروع االسرتدعاء المباشرر‪ .‬امرا االسرتدعاء غيرر المباشرر فيرتم عنردما دالرة ‪A‬‬
‫تستدعي دالة ‪ B‬ودالة ‪ B‬تستدعي دالة ‪.A‬‬

‫‪ 7.4‬االستدعاء الذاتي باستالدا مثال‬


‫لكري نوضرح عمررل دالرة االسرتدعاء الررذاتي فاننرا سنشررح الموضرروع باسرتخدام مثررال‪,‬‬
‫مثالنررا هنررا ايجرراد مضررروب رقررم معررين )‪ .(factorial‬بدايررة سررنكتب البرنررامج الررذي‬
‫يوجد نتيجة المضروب ومن يم نشرح البرنامج خطوة خطوة‪.‬‬
‫>‪#include <stdio.h‬‬

‫{ )‪int factorial (unsigned int i‬‬

‫{ )‪if(i <= 1‬‬ ‫السطر ‪// 1‬‬

‫;‪return 1‬‬ ‫السطر ‪// 2‬‬

‫}‬

‫;)‪return i * factorial (i - 1‬‬ ‫السطر ‪// 3‬‬

‫}‬

‫{ )(‪int main‬‬

‫; ‪cin>> i‬‬

‫; )‪cout<< "Factorial of \n" << i << “ is ” << factorial(i‬‬

‫;‪return 0‬‬

‫}‬

‫لتوضيح عمل االستدعاء الذاتي وحسرب البرنرامج اعرالل سرنفرض ان المطلروب هرو‬
‫ايجراد مضررروب الرررقم ‪ .4‬بدايررة لنشرررح البرنرامج يررم نوضررح كيفيررة ايجرراد مضرروب‬

‫‪329‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الرقم ‪ .4‬الح ان البداية سيتم ادخال القيمة المطلوب ايجاد المضرروب لهرا ومرن يرم‬
‫تستدعى دالة ايجاد المضروب (سيتم ادخال الرقم ‪ .)4‬الدالة التي سيتم استدعائها في‬
‫هذا البرنامج هي باسم )‪ (factorial‬والتي تجد المضرروب‪ ,‬المردخل لهرا قيمرة الررقم‬
‫الذي نحاول ايجاد المضروب له‪ ,‬هنا سيكون الرقم ‪.4‬‬
‫الحر فرري بدايررة الدالررة هنررا شرررط‪ ,‬هررذا الشرررط يسررتخدم اليقرراف عمليررة االسررتدعاء‬
‫الذاتي وعدم السماح بدخول الدالرة الرى حلقرة تكررار النهائيرة (حالرة االسراس)‪ .‬طبعرا‬
‫شرط التوقف هو عندما نصل الى واحد فان الدالة ستصل نهايتهرا‪ .‬الفكررة هرو ان لرم‬
‫نصل واحد فان الدالة ستستدعي نفسها‪ .‬واحدة من الطرق الرياضية لوصف )!‪:(n‬‬

‫نفرررض كمررا فرري المثررال ان المطلرروب هررو )!‪ ,(4‬وبسرربب ان )‪ (n>0‬فاننررا سنسررتخدم‬
‫الجزء الثاني من التعريف اعالل‪.‬‬
‫‪4! = 4 * 3 * 2 * 1 = 24‬‬

‫من الممكن ايضرا ان نوضرح ان )!‪ (n‬مرن الممكرن كتابتهرا الي قيمرة)‪ (n‬ليسرت‬
‫سالبة‪.‬‬

‫هررذا التعريررف هررو تعريررف االسررتدعاء الررذاتي‪ ,‬الننررا وضررحنا دالررة المضررروب بداللرة‬
‫نفسها‪ .‬ووفقا للتعريف في العالقة اعالل فان‬
‫!‪4! = 4 * (4-1)! = 4 * 3‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫بالطبع فران عمليرة الضررب اليمكرن انجازهرا االن‪ ,‬وذلرك الننرا النعررف قيمرة )!‪.(3‬‬
‫لذلك‪ ,‬لنرى كيف سيتم انجاز هذا العمل عن طريل االستدعاء الذاتي (هنا ترم تجزئرة‬
‫المشكلة الى اجزاء صغيرة مشابهة للمشكلة االصلية) ‪.‬‬
‫نفرض ان حسين هو احد الطلبة في قسرم الحاسروب وطلرب منره ايجراد )!‪ ,(4‬حسرين‬
‫فهم ان‬
‫!‪4! = 4 * (4-1)! = 4 * 3‬‬

‫ونظرا الن حسين ال يعرف قيمة )!‪ ,(3‬لذلك قرر االتصال بزميلته جنى وسالها عن‬
‫قيمررة )!‪ ,(3‬جنررى فكرررت بالمس رألة وهرري تملررك نفررس الصرريغة (تعريررف المضررروب)‬
‫وتوصلت الى ان‬
‫!‪3! = 3 * (3 – 1)! = 3 * 2‬‬

‫‪331‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :7.5‬توضيح لبريقة ايجا المضروب‪.‬‬

‫جنى لم تسرتطع ايجراد النتيجرة النهائيرة حيرث ال يمكنهرا اكمرال عمليرة الضررب نظررا‬
‫لعدم معرفتها بقيمة )!‪ ,(2‬لذلك قررت جنى ان تجعل حسين ينتظر وتتصرل بزميلهرا‬
‫محمد لمعرفة قيمة )!‪.(2‬‬

‫شك ‪ :7.6‬تجزئة مشكلة المضروب الل ا زاء اصغر‪.‬‬

‫محمررد يملررك نفررس العالقررة الرياضررية الترري يملكهررا كررل مررن حسررين وجنررى‪ ,‬لررذلك فقررد‬
‫توصل الى ان‬
‫!‪2! = 2 * (2 - 1)! = 2 * 1‬‬

‫لكن محمد لم يستطع اكمال عملية الضرب لعدم معرفته نتيجة )!‪ ,(1‬لذلك طلرب مرن‬
‫جنى االنتظار لحين ايجاد النتيجة (االن جنى وحسين باالنتظار)‪.‬‬
‫محمد قرر االتصال بوالدته والتي هي مدرسة فيزياء ليسألها عن نتيجة )!‪.(1‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :7.7‬ايجا مضروب الرقم ‪.1‬‬

‫والدة محمد تعرف ذات العالقة‪ ,‬لذلك فهي بسرعة توصلت الى ان‬
‫!‪1! = 1 * (1 – 1)! = 1 * 0‬‬

‫طبعا هي لم تتمكن من انجاز علمية الضرب وذلك النها لم تعرف نتيجة )!‪ ,(0‬لذلك‬
‫فان والدة محمد قررت ان تجعل محمد ينتظر واتصلت بزوجها (والد محمد) مدرس‬
‫الرياضيات لتطلب منه معرفة نتيجرة )!‪ ,(0‬والرد محمرد لرم يحتراج الرى وقرت للتفكيرر‬
‫فهو يعرف ذات العالقة والتعريف‪ ,‬ويعلم ان الجزء االول من التعريف يشير الى ان‬
‫‪n! = 1,‬‬ ‫‪if‬‬ ‫‪n=0‬‬

‫لذلك فهو قد اخبرها بالنتيجة مباشرة وقال لها ان )‪.(0! = 1‬‬


‫عندما علمت والدة محمد ان )‪ (0! = 1‬اكملرت عمليرة الضررب واسرتخرجت النتيجرة‬
‫وكما يلي‬
‫‪1! = 1 * (1 – 1)! = 1 * 0! = 1 * 1 = 1‬‬

‫والدة محمد اسرعت والفرح يغمرها باعالم محمد النتيجة وهي )‪.(1! = 1‬‬

‫‪333‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫محمد بمجرد سماع النتيجة عوض في العالقة التي لدية واستخرج النتيجة كما يلي‬

‫‪2! = 2 * (2 - 1)! = 2 * 1! = 2 * 1 = 2‬‬

‫بعد حصول محمد على النتيجة عاد الى جنى ليعلمها ان )‪.(2! = 2‬‬
‫جنى والتي طال انتظارهرا اكملرت عمليرة الضررب لتسرتخرج قيمرة )!‪( (3‬هري كانرت‬
‫بانتظار نتيجة !‪.)2‬‬
‫‪3! = 3 * (3 – 1)! = 3 * 2! = 3 * 2 = 6‬‬

‫بنشوة النصر اخبرت جنى زميلها حسين بان نتيجة )‪ (3! = 6‬معتذرة عرن الترأخير‬
‫النشغالها قليال بالمطبا!‪.‬‬
‫واخيرررا فرران حسررين اسررتخدم هررذل القيمررة الترري حصررل عنهررا مررن جنررى ليكمررل عمليررة‬
‫الضرب كما في ادنال وهو في داخله يزداد اعجابا بذكاء جنى‪.‬‬

‫‪4! = 4 * (4-1)! = 4 * 3! = 4 * 6 = 24‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :7.8‬استالراج القيمة النهائية لمضروب ‪4‬ب باستالدا ال و ة )‪(recursion‬‬

‫من المؤكد‪ ,‬ان استخدام العودة هي ليست حكرا على مختصي الرياضريات باسرتخدام‬
‫الهواتررف‪ .‬ان لغررات البرمجررة مثررل ‪ C++‬ترردعم العررودة وترروفر للمبرررمجين اداة قوي رة‬
‫وفاعلة لحل نوع محدد من المشاكل بتقليل درجرة التعقيرد او اخفراء تفاصريل المشركلة‬
‫كما في شفرة البرنامج اعالل‪.‬‬
‫لنتابع البرنامج الخاص بمضروب الرقم (‪ )4‬باستخدام الجدول وذلك لغررض تبسريط‬
‫الحل‪.‬‬

‫دول ‪ :7.1‬تحلي برنام ايجا المضروب‪.‬‬

‫اسرررررررتدعاء رقرررررررررررررررررررررررررررررررررررم الفعل‬


‫االيعاز(السطر)‬ ‫العودة‬

‫‪ 4‬ليست صفر‪ ,‬اذن نذهب الى ‪else‬‬ ‫‪1‬‬

‫في هذا الجزء سيتم اعادة !)‪4 * (4 – 1‬‬ ‫‪3‬‬

‫الح هنا ان الناتج هو )‪4*factorial(4-1‬‬

‫‪335‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫وهذا يعني اعادة اسرتدعاء الدالرة‪ factorial‬ومرن داخرل الدالرة‬


‫نفسها لكن بقيمة اقل وهي (‪)3‬هذا االستدعاء االول بقيمة (!‪)3‬‬

‫‪ 3‬ليست صفر‪ ,‬اذن نذهب الى ‪else‬‬ ‫‪1‬‬ ‫‪1‬‬

‫اعادة !)‪ .. 3 * (3 – 1‬يتم االستدعاء الثاني وبقيمة (!‪)2‬‬ ‫‪3‬‬

‫‪ 2‬ليست صفر‪ ,‬اذن نذهب الى ‪else‬‬ ‫‪1‬‬ ‫‪2‬‬

‫اعادة !)‪ .. 2 * (2 – 1‬يتم االستدعاء الثالث وبقيمة (!‪)1‬‬ ‫‪3‬‬

‫‪ 1‬ليست صفر‪ ,‬اذن نذهب الى ‪else‬‬ ‫‪1‬‬ ‫‪3‬‬

‫اعادة !)‪ .. 1 * (1 – 1‬يتم االستدعاء الرابع وبقيمة (!‪)0‬‬ ‫‪3‬‬

‫)‪ (1-1‬هو صفر‪ ,‬لذلك يتم التحول الى االيعاز ‪2‬‬ ‫‪1‬‬ ‫‪4‬‬

‫اعادة ‪1‬‬ ‫‪2‬‬

‫الرقم ‪ 1‬يعوض استدعاء الدالة‪ .‬الرقم ‪ .1‬اعادة ‪1‬‬ ‫‪3‬‬ ‫‪3‬‬

‫الرقم ‪ 1‬يعوض استدعاء الدالة‪ .‬الرقم ‪ .2‬اعادة ‪2‬‬ ‫‪2‬‬

‫الرقم ‪ 2‬يعوض استدعاء الدالة‪ .‬الرقم ‪ .3‬اعادة ‪6‬‬ ‫‪1‬‬

‫الرقم ‪ 6‬يعوض استدعاء الدالة‪ .‬الرقم ‪ .4‬اعادة ‪24‬‬

‫للتاكد من ان حل العودة (االستدعاء الذاتي) يعمل‪ ,‬يجب ان تكون قادر على االجابرة‬
‫بنعم لالس لة الثالث التالية‪:‬‬
‫سررؤال حررول الحالررة االسرراس‪ :‬هررل هنررا طريقررة غيررر االسررتدعاء الررذاتي‬ ‫‪.1‬‬
‫وبدون الدالة اليجاد النتيجة لجزء صغير من المشكلة‪ ,‬وهرل الدالرة تعمرل بشركل‬
‫صحيح عند القيمة االساس‪.‬‬
‫سؤال االستدعاء االصغر‪ :‬هرل ان االسرتدعاء الرذاتي للدالرة يتضرمن حالرة‬ ‫‪.2‬‬
‫تصغير للمشكلة االصلية‪ ,‬بحيث يقود الى الحالة االساس بشكل ال مفر منه‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫سرؤال الحالررة العامررة‪ :‬نفررض ان االسررتدعاء الررذاتي يعمرل بشرركل صررحيح‪,‬‬ ‫‪.3‬‬
‫فهل ان كامل الدالة تعمل بشكل صحيح‪.‬‬
‫لنجرب هذل الشروط او االس لة على دالة المضروب التي تطرقنا لها‪:‬‬
‫ان الحالة االساس تحدث عندما تكون قيمة )‪ ,(n=0‬حيث ان الدالة ستسند‬ ‫‪.1‬‬
‫القيمة ‪ .1‬والتي هي القيمة الصحيحة لمضروب الصفر )!‪ ,(0‬وعندها ال توجد‬
‫استدعاءات عودة اضافية‪ .‬الجواب هو نعم‪.‬‬
‫الجابررة هررذا السررؤال‪ ,‬يجررب ان ننظررر الررى المعررامالت الترري تمرررر الررى‬ ‫‪.2‬‬
‫استدعاء العودة‪ .‬في الدالة )‪ (factorial‬فان استدعاء العودة يمرر )‪.(n-1‬‬
‫في كل مرة يتم فيها االستدعاء الذاتي للدالة ترسل قيمة معامالت اصرغر للدالرة‪,‬‬
‫لحين ان تكون القيمرة المرسرلة تسراوي صرفر‪ .‬فري هرذل الحالرة فاننرا وصرلنا الرى‬
‫اصغر حالة‪ ,‬وال توجد استدعاءات اضافية اخرى‪ .‬الجواب هو نعم‪.‬‬
‫في حالرة دالرة مثرل الدالرة )‪ (factorial‬نحتراج ان نتحقرل مرن ان الصريغة‬ ‫‪.3‬‬
‫التررري نسرررتخدمها واقعرررا نتيجرررة حرررل صرررحيح‪ .‬نفررررض بررران االسرررتدعاء الرررذاتي‬
‫))‪ (factorial (n-1‬تعطينا قيمة صحيحة للمضرروب !)‪ ,(n-1‬عبرارة االعرادة‬
‫ستحسب !)‪ n*(n-1‬وهرذا هرو تعريرف المضرروب‪ ,‬حيرث اننرا نعلرم بران الدالرة‬
‫تعمل لجميع القيم الموجبة‪ .‬لذلك فان االجابة نعم‪.‬‬

‫كتابة وال االستدعاء الذاتي‬ ‫‪7.5‬‬


‫باالمكان استخدام النقاط التالية لكتابة اي دالة استدعاء ذاتي‪:‬‬
‫المفروض ان يكون هنا تعريف واضح لحل المشكلة‪( .‬هرذل برالطبع هري‬ ‫‪.1‬‬
‫الخطوة االولى لحل اي مشكلة برمجية)‪.‬‬
‫تحديد حجرم المشركلة المطلروب حلهرا عنرد اسرتدعاء الدالرة‪ .‬فري االسرتدعاء‬ ‫‪.2‬‬
‫االولرري للدالررة‪ ,‬فرران حجررم كامررل المشرركلة يوضررح فرري قيمررة او قرريم معامررل او‬
‫معامالت الدالة‪.‬‬

‫‪337‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫تحديررد وتعريررف الحالررة االسرراس‪ ,‬والترري توضررح المشرركلة برردون عمليررات‬ ‫‪.3‬‬
‫العودة‪ .‬و يتم التاكد منها عند االجابة بنعم لسؤال الحالة االساس‪.‬‬
‫تعريررف وحررل الحالررة العامررة بشرركل صررحيح بداللررة حالررة اصررغر لررنفس‬ ‫‪.4‬‬
‫المشرركلة (اسررتدعاء ذاترري)‪ .‬هررذل تؤكررد االجابررة نعررم لسررؤالي االسررتدعاء االصررغر‬
‫والحالة العامة‪.‬‬
‫لو حاولنا تطبيل هذل الفقرات على برنامج المضروب‪.‬‬
‫تعريف المشكلة من الممكن ان نختصرل بتعريف دالة المضروب‪ .‬حجم المشكلة هرو‬
‫عدد القيم التي من المفروض ان تضرب وهي تساوي ‪.N‬‬
‫الحالررة االسرراس تحرردث عنرردما تكررون )‪ ,(N = 0‬فرري حالررة اننررا سررلكنا طريررل عرردم‬
‫االستدعاء الذاتي‪.‬‬
‫اخيررررا‪ ,‬الحالرررة العامرررة تحررردث عنررردما تكرررون )‪ (N>0‬يرررؤدي الرررى اسرررتدعاء ذاتررري‬
‫للدالة ‪ factorial‬لحالة اصغر)‪.factorial (N-1‬‬

‫مثال‪ :‬البرنامج التالي يولد متوالية ‪ Fibonacci‬لعدد محدد‪.‬‬ ‫‪‬‬


‫التعريف الرياضي الرقام الفيبوناشي ‪ Fibonacci‬هو‬
‫‪fib(0) = 1‬‬

‫‪fib(1) = 1‬‬

‫)‪fib(n) = fib(n-1) + fib(n-2‬‬

‫>‪#include <iostream‬‬
‫;‪using namespace std‬‬

‫‪int fib(int n) // 1, 1, 2, 3, 5, 8, 13, 21, ...‬‬


‫{‬
‫)‪if (n == 0 || n == 1‬‬
‫;‪return 1‬‬
C++ ‫هياكل البيانات باستخدام‬

return fib(n-1) + fib(n-2);


}

main()
{
int n;

cout << "Enter a non-negative integer: ";


cin >> n;
cout << "Fib(" << n << ") = " << fib(n) << "." << endl;
return 0;
}

‫ برنامج اليجاد مجموع ارقام موجبة بطريقة االستدعاء الذاتي‬:‫ مثال‬


1+2+3+…+n

# include<iostream>
using namespace std;
int sum (int) ; // ‫اعالن عن دالة‬
void main (void) {
int n ، temp ;
cout<<"enter any integer number "<<endl ;
cin>>n ;
temp = sum (n) ;
cout<<"value = "<<n<<"and its sum="<<temp ;
}

int sum (int n) // ‫دالة االستدعاء الذاتي‬


{
int value = 0 ;

339
‫هياكل البيانات باستخدام ‪C++‬‬

‫;)‪if (n==0) return (value‬‬


‫‪else‬‬
‫; )‪value = n + sum(n-1‬‬
‫;)‪return (value‬‬

‫}‬

‫التوضيح التالي من الممكن ان يساعد على ادرا وفهم دالة االستدعاء الذاتي‪.‬‬
‫فلو فرضرنا انره ترم ادخرال قيمرة للمتغيرر (‪ )n=6‬لنررى كيرف سريتم ايجراد المجمروع‪،‬‬
‫اعتمادا على قيمة العبارة‬
‫; )‪value = n + sum (n-1‬‬

‫هنا العبارة ()‪ )sum (n-1‬هي استدعاء للدالة ()‪ ،)sum(int‬ونظرا الن هذا‬
‫االسررتدعاء مررن داخررل الدالررة نفسررها اذن هررو يمثررل اسررتدعاء ذاترري اي اسررتدعاء لنفسرره‬
‫وسيكون عملها كما يأتي‪:‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مع متوالية‬ ‫شك ‪ :7.9‬يبين كيفية تنفيذ الة االستدعاء الذاتي لبرنام‬

‫)‪n + sum (n-1) = 6 + sum (6-1) = 6 + sum (5‬‬

‫‪ ‬يتم استدعاء الدالة اليجاد المجموع عندما (‪ )n=5‬ويضاف الى (‪)6‬‬


‫‪ ‬تستمر العملية لحين الوصرول الرى (‪ )n=0‬فتعراد القيمرة (‪ )value‬والتري قيمتهرا‬
‫(‪.)1‬‬
‫‪ ‬االن يكررون الرجرروع لتعررويض القرريم المسررتنتجة والبرردء اوال بقيمررة ()‪)sum (1‬‬
‫حيث وجدت قيمتة (‪ )1‬لتعوض بمكانها كما في اعالل‬
‫‪ ‬ستجمع نتيجة ()‪ )sum(1‬مع الرقم (‪ )2‬السرتخراج نتيجرة ()‪ )sum(2‬وتسرتمر‬
‫العملية الى النهاية كما في الشكل ‪.7.9‬‬

‫‪341‬‬
‫هياكل البيانات باستخدام ‪C++‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص الثامن‬
‫األشجار الثنائية ‪BINARY TREES‬‬

‫‪ 8.1‬المقدمة‬
‫هنرا عرردد مررن اساسرريات هياكرل البيانررات الترري مررن الممكرن اسررتخدامها لحررل مشرراكل‬
‫التطبيقررات‪ .‬المصررفوفات تعتبررر جيرردة لهياكررل البيانررات المسررتقرة والترري مررن الممكررن‬
‫الوصول اليهرا عشروائيا وهري تنفرذ بسرهولة‪ .‬القروائم الموصرولة مرن جانرب اخرر هري‬
‫ليست مستقرة وهري مثاليرة للتطبيقرات التري تتطلرب عمليرات متكرررة مثرل االضرافة‪,‬‬
‫الحرذف‪ ,‬والتحرديث‪ .‬واحردة مرن مشراكل القروائم الموصرولة هري الوصرول المتسلسرل‬
‫للبيانات‪ .‬هنا هياكل بيانات خاصرة اخررى مثرل المكردس والطرابور التري تسرمح لنرا‬
‫بحل المشاكل المع قدة باستخدام هياكل البيانات المحرددة هرذل‪ .‬هيكرل بيانرات اخرر هرو‬
‫جدول التجزئة )‪ (Hash table‬التي تسمح للمستخدم لبرمجة التطبيقات التي تحتراج‬
‫الى بحث وتحديث متكرر‪.‬‬
‫احد مساو استخدام المصفوفات والقوائم الموصولة لخزن البيانات هو الوقت االزم‬
‫للبحررث عررن عنصررر معررين‪ ,‬وحيررث ان كليهمررا المصررفوفات والقرروائم الموصررولة هرري‬
‫هياكل خطية‪ ,‬فان الوقت المطلوب لبحث قائمة خطية يتناسب مرع حجرم البيانرات فري‬
‫المجموعررة‪ .‬مثررال‪ ,‬اذا كرران حجررم البيانررات فرري المجموعررة هررو ‪ ,n‬عليرره فرران عرردد‬
‫المقارنات التي تحتاجها اليجاد (او عدم ايجاد) عنصر معين ربمرا تكرون مرن السروء‬
‫لضرب ‪ n‬عدد من المررات‪ .‬لرذلك تصرور انرك تريرد البحرث فري قائمرة موصرولة (او‬
‫مصرفوفة) وتحتروي مرثال ‪ n = 106‬عقردة‪ .‬حترى فري الماكنرة التري بإمكانهرا ان تقروم‬
‫بمليون عملية مقارنة بالثانية‪ ,‬فان البحث عن ‪ m‬عنصر ستحتاج الى ‪ m‬من الثرواني‬
‫تقريبا‪ .‬هذا غير مقبول في عالم اليوم حيث ان السررعة فري اكمرال عمليرة معينرة هرو‬
‫مهم جدا‪ .‬وهذا يترجم كمبالغ مالية‪ ,‬عليه فان هنا حاجة لهياكل بيانات افضل (اكثر‬
‫كفاءة) لخزن البيانات والبحث عنها‪.‬‬

‫‪343‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 8.2‬ت ريف االشجار‬


‫االشجار هي هياكل بيانات غير خطية‪ ,‬ترنظم البيانرات بشركل هرمري‪ ,‬واالشرجار امرا‬
‫ان تكون خالية (عدم وجود عقد) او ان تكون عبارة عن جذر فقط او جذر وفررع او‬
‫اكثر من االشجار الفرعية كما في الشكل ‪.8.1‬‬
‫من صفات االشجار غير الخالية‬
‫‪ .i‬هنرررا بالضررربط عقررردة واحررردة‪ ,‬تررردعى الجرررذر لهرررا درجرررة الررردخول صرررفر‬
‫)‪(indegree‬‬
‫‪ .I‬اي عقدل غير الجذر لها درجة الدخول واحد ‪.1‬‬
‫‪ .II‬لكل عقدة ‪ a‬من الشجرة هنا طريل مباشر من الجذر الى العقدة ‪.a‬‬

‫شك ‪ :8.1‬يوضح نماكج من االشجار‪.‬‬

‫شك ‪ :8.2‬هذ ليست اشجار وكلو ‪ .A‬النها ائرية ‪ .B .B-C-E-D-B‬ائرية غير مباشرة‬

‫‪ .C .1-2-4-3‬فرعين غير متصلة ‪A-B , C-D-E‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫ال قدة ‪Node‬‬ ‫‪8.3‬‬


‫عقدة الشجرة تمثل المعلومات المتضمنة فري هيكرل مفررد‪ .‬هرذل العقرد مرن الممكرن ان‬
‫تحتوي على قيم او شرط‪ ,‬او ربما تكون بمثابة هيكل بياني اخرر مسرتقل‪ .‬العقردة هري‬
‫مواقع خزن متجاورة تعرف كهيكل بياني‪ .‬في االشجار الثنائية فان العقدة تتكون من‬
‫يالث حقول‪ ,‬حقل البيانات (او المعلومات) والتي من الممكن ان تكون هذل البيانات‪:‬‬
‫قيم رقيمة‪ ,‬رموز‪ ,‬حروف او نصوص او اي هيكل بيراني مسرتقل‪ .‬وحقلرين للعنراوين‬
‫واحد لعنوان االبن االيمن واالخر لعنروان االبرن االيسرر وهري عبرارة عرن مؤشررات‬
‫(احرردهما يؤشررر الررى العقرردة فرري اليمررين والثرراني يؤشررر الررى العقرردة فرري اليسررار) وهررذل‬
‫العقدة مشابهة للعقدة التي استخدمت في القوائم الموصرولة الثنائيرة فري فصرل القروائم‬
‫الموصولة الح الشكل ‪.8.3‬‬
‫يرجى مالحظة امكانية تمثيل العقدة بخلية مصرفوفة وسرناتي الحقرا عليهرا لكرن غالبرا‬
‫يكون التمثيل على شكل قوائم موصولة‪ .‬الشفرة الخاصة با عالن عن العقدة هي‪:‬‬
‫{ ‪struct node‬‬

‫;‪int data‬‬

‫;‪struct node *leftChild‬‬

‫;‪struct node *rightChild‬‬

‫;}‬

‫شك ‪ :8.3‬عقدة القوائم الموصولة المستالدمة في االشجار الثنائية‪.‬‬

‫‪345‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مصبلحات االشجار ‪Trees Terminology‬‬ ‫‪8.4‬‬


‫العديد من المصطلحات تستخدم لوصف عناصر االشجار‪ .‬نحن نحتراج لمعرفرة هرذل‬
‫المصررطلحات بحيررث يكررون نقاشررنا مفهرروم‪ .‬لحسررن الح ر ‪ ,‬غالبيررة هررذل المصررطلحات‬
‫تتعلرررل باألشرررجار الحقيقيرررة او العالقرررات العائليرررة (مثرررل اسرررتخدامنا لمصرررطلح االب‬
‫واالبرن)‪ ,‬وبرذلك سروف ال يكرون مررن الصرعب ترذكرهم‪ ,‬الشركل ‪ 8.4‬يوضرح الشررجرة‬
‫الطبيعية وشجرة هياكل البيانات‪.‬‬

‫شك ‪ :8.4‬توضيح للتماث بين الشجرة الببي ية )‪ (A‬وشجرة هيك البيانات )‪.(B‬‬

‫في التالي اهم المصطلحات التي تستخدم مع اشجار هياكل البيانات‪.‬‬

‫‪ ‬الجةذر ‪ : Root‬اعلرى عقردة فرري الشرجرة‪ .‬العقردة فري اعلررى الشرجرة دائمرا ترردعى‬
‫الجذر‪ .‬هنا جذر واحد فقط فري الشرجرة‪ .‬عنرد وجرود تجمرع للعقرد وروابرط برين‬
‫العقد والتي تعرف كشجرة‪ ,‬فانره يجرب ان يكرون هنرا مسرار واحرد وواحرد فقرط‬
‫من الجرذر الرى اي عقردة اخررى‪ .‬هنرا نتحردث عرن الجرذر لكامرل الشرجرة‪ .‬احيانرا‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫اعلى عقدة في الشجرة الفرعية تردعى جرذر لتلرك الشرجرة الفرعيرة‪( ,‬هنرا شرجرة‬
‫هياكل البيانات هي شجرة مقلوبة بمعنى الجذر لالعلى واالوراق لالسفل)‪.‬‬
‫االبن ‪ : Child‬عقدة او اكثر التي تلي مباشرة عقردة اخررى‪ .‬اي عقردة ربمرا لهرا‬ ‫‪‬‬
‫رابط او اكثر ينطلل الى االسفل الى عقرد اخررى‪ .‬هرذل العقردة اسرفل عقردة معينرة‬
‫مباشرة تدعى ابن‪.‬‬
‫االب ‪ : Parent‬الفكرة المعاكسة لالبن وهي العقدة التي اعلى االبن وتتصل بره‬ ‫‪‬‬
‫مباشرة‪ .‬اي عقدة (باستثناء الجذر) لها بالضبط رابط واحرد ينطلرل الرى االعلرى‪,‬‬
‫الى اي عقدة اخرى‪ .‬لكل عقدة هنا عقدة واحدة فقط اعلرى منهرا مباشررة تردعى‬
‫االب لهذل العقدة‪.‬‬
‫النسيب ‪ :Sibling‬وهي العقد التي لها نفس االب‪.‬‬ ‫‪‬‬
‫الورقةةة ‪ :Leaf‬العقرردة الترري لرريس لهررا ابنرراء ترردعى العقرردة الورقيررة او ببسرراطة‬ ‫‪‬‬
‫اوراق‪ .‬في الشجرة هنا جذر واحد لكن هنا عدد من االوراق‪.‬‬
‫السلي ‪ :Descendant‬وهي العقد التي نصل اليها بعمليات تكرارية مرن االب‬ ‫‪‬‬
‫الى االبناء‪.‬‬
‫السلف ‪ : Ancestor‬وهي العقد التي نصرل اليهرا بعمليرات تكراريرة مرن االبنراء‬ ‫‪‬‬
‫الى االب‪.‬‬
‫ال قدة الداولية ‪ :Internal node‬هي العقدة التي لها على االقل ابن واحد‪.‬‬ ‫‪‬‬
‫ال قدة الالار ية ‪ :External node‬العقدة التي ليس لها ابناء‪.‬‬ ‫‪‬‬
‫االشةةةجار الفرعيةةةة ‪ :Subtree‬اي عقررردة مرررن الممكرررن ان تعتبرررر جرررذر لشرررجرة‬ ‫‪‬‬
‫فرعيرررة‪ ,‬ان ابنررراء هرررذل العقررردة وابنررراء ابنائهرررا تمثرررل شرررجرة فرعيرررة‪ .‬اذا فكررررت‬
‫بمصررطلحات العوائررل فرران الشررجرة الفرعيررة تتكررون مررن كررل االحفرراد‪ .‬الشررجرة‬
‫الفرعية من الممكن ان تكون مجموعة من العقد او عقدة واحدة‪.‬‬
‫الدر ة ‪ :Degree‬عدد االشجار الفرعية للعقدة‪.‬‬ ‫‪‬‬
‫الرابط (الحافة) ‪ :Edge‬هو الرابط بين عقدة واخرى‪.‬‬ ‫‪‬‬

‫‪347‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.5‬يبين ال قدةب الوراق والرابط‬


‫‪ ‬المسةةار ‪ :Path‬فكررر برران احرردهم يسررير مررن عقرردة الررى عقرردة اخرررى علررى طررول‬
‫الرروابط التري ترربطهم‪ .‬المتواليرة الناتجرة مررن العقرد (الطريرل الرذي يوصرلنا الررى‬
‫العقدة المطلوبة) تدعى مسار‪ .‬اذن هري مجموعرة مرن الرروابط التري ترربط االب‬
‫الى ابنائه والى احفادل وهكذا‪.‬‬

‫شك ‪ :8.6‬شك توضيحي للمسار‪.‬‬

‫‪ ‬المسةةتوى ‪: Level‬المسررتوى لعقرردة معين رة يشررير الررى عرردد االجيررال للعقرردة مررن‬
‫الجررذر‪ .‬اذا فرضررنا الجررذر فرري المسررتوى صررفر‪ ,‬عليرره فرران االبررن سرريكون فرري‬
‫المستوى ‪ ,1‬االبن الحفيد سيكون في المستوى ‪ 2‬وهكذا‪.‬‬
‫‪ ‬المفاتيح ‪ :Keys‬في حقول البيانات في كيان معين توجد قيمة تسمى هذل القيمرة‬
‫مفترراح (اي القيمررة الترري فرري حقررل البيانررات للعقرردة)‪ .‬هررذل القيمررة مررن الممكررن ان‬
‫تستخدم للبحث عرن عنصرر معرين‪ ,‬او انجراز عمليرات محرددة عليهرا‪ .‬عنرد تمثيرل‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الشررجرة علررى شرركل مخطررط للشررجرة‪ ,‬سررنرى دوائررر تمثررل العقررد‪ ,‬وهررذل الرردوائر‬
‫تحمل بيانات هذل البيانات تمثل المفتاح‪.‬‬
‫‪ ‬ارتفا ال قدة ‪ :Node Height‬هو طول الطريرل (عردد الحرواف او الرروابط)‬
‫ألطول طريل بين العقدة والورقة‪.‬‬
‫‪ ‬ارتفا الشجرة ‪ :Tree Height‬ان اطرول مسرار (يتضرمن الجرذر واالوراق)‬
‫يمثررل ارتفرراع الشررجرة‪ .‬بالنسرربة لالشرجار غيررر الخاليررة‪ ,‬فرران االرتفرراع هررو اطرول‬
‫مسار في الشجرة ‪.1 +‬‬

‫شك ‪ :8.7‬يوضح مفهو االرتفا‬


‫‪ ‬عمر ال قدة ‪ :Node Depth‬هو طول الطريل من الجذر الى العقدة‪.‬‬

‫شك ‪ :8.8‬عمر ال قدة‬


‫‪ ‬عمر الشجرة ‪ :Tree Depth‬هو طول الطريل من الجذر الى اعمل عقدة في‬
‫الشجرة‪.‬‬

‫‪349‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫حجةم ال قةدة ‪ : Size of Node‬هرو عردد العقرد التري تمثرل ابنراء واحفراد العقردة‬ ‫‪‬‬
‫(والعقرردة نفسررها تحسررب معهررم) اي ان حجررم الجررذر يمثررل عرردد العقررد الكليررة فرري‬
‫الشجرة من ضمنها الجذر‪.‬‬
‫رتبة الشجرة ‪ :Order of the Tree‬هي اكبر عدد من االبناء تحتويها عقردة‬ ‫‪‬‬
‫من عقد الشجرة‪.‬‬
‫ر ة الدوول ‪ :In Degree‬للعقدة هي عدد الحواف التي تصرل العقردة‪ .‬الجرذر‬ ‫‪‬‬
‫هي العقدة الوحيدة التي لها (‪.)in degree = 0‬‬
‫ر ة الالروج ‪ :Out Degree‬للعقدة هي عدد الحواف التي تتر العقدة‪.‬‬ ‫‪‬‬
‫الزيةةارة ‪ :Visiting‬يررتم زيررارة العقرردة عنرردما يصررل المسرريطر الررى العقرردة‪ ,‬عرادة‬ ‫‪‬‬
‫نجاز بعض العمليات على العقدة وليس للمرور فقط‪ ,‬مثل فحص القيمرة لواحرد‬
‫من حقول البيانات او عرضها‪ .‬ان المرور على عقدة في الطريل الذي ينقلنا من‬
‫عقدة الى اخرى ال يعتبر زيارة للعقدة‪.‬‬
‫المةةرور ‪ :Traversing‬المرررور علررى ش رجرة يعنرري زيررارة كررل العقررد بترتيررب‬ ‫‪‬‬
‫معين‪ .‬مثال‪ ,‬ربما تزور كل العقد بترتيب تصراعدي حسرب قيمرة المفتراح‪ .‬هنرا‬
‫العديد من طرق المرور على العقد كما سنراها الحقا‪.‬‬

‫شك ‪ :8.9‬مثال لشجرة ثنائية‪.‬‬

‫في الشكل ‪ 8.9‬فان العقدة ‪ A‬هي الجذر‪ .‬اما العقدة ‪ B‬والعقدة ‪ C‬هم ابناء العقدة ‪.A‬‬
‫العقدة ‪ B‬مع العقدة ‪ D‬تكون شجرة فرعية‪ .‬العقدة ‪ B‬لها اينان من االبناء وهما‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫االبن االيسر وهنا هو شجرة خالية واالبن االيمن الذي هو ‪ .D‬العقد ‪ A, C, F‬هم‬
‫اسالف العقدة ‪ .H‬العقد ‪ D, E, F‬تكون المستوى الثاني من الشجرة‪ .‬العقدة ‪ A‬هي‬
‫في المستوى صفر‪ .‬المسار من ‪ A‬الى ‪ C‬الى ‪ E‬الى ‪ G‬يمثل طريل بطول ‪ .3‬العقد‬
‫‪ D, G, H, I‬هي اوراق الشجرة‪ .‬العقد ‪ A, B, C, E, F‬هي عقد داخلية‪ .‬العقد ‪G,‬‬
‫‪ H, I‬هي عقد خارجية‪ .‬عمل العقدة ‪ I‬هو ‪ .3‬اما ارتفاع هذل الشجرة هو ‪.4‬‬

‫شك ‪ :8.10‬عناصر الشجرة او مصبلحات الشجرة‪.‬‬

‫فوائد األشجار‬ ‫‪8.5‬‬


‫االشجار مفيدة جدا وتستخدم دائما وذلك النها تتمتع ببعض المميزات الجدية‪:‬‬
‫‪ ‬االشجار تعكس العالقات الهيكلية في البيانات‪.‬‬
‫‪ ‬االشجار تستخدم لتمثيل الهرمية‪.‬‬
‫‪ ‬االشجار توفر عملية اضافة وحذف كفوءة‪.‬‬
‫‪ ‬االشجار هي بيانات مرنة جدا‪ ,‬تسمح بحركة االشجار الفرعية باقل جهد‪.‬‬
‫الشجرة الثنائية ‪Binary tree‬‬ ‫‪8.6‬‬

‫‪351‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الشجرة الثنائية هي هيكل بياني خاص يستخدم الغراض خزن البيانرات‪ .‬واالشرجار‬
‫الثنائية لها الصفات التالية‪:‬‬
‫‪ ‬اذا كانت كل عقدة في الشجرة لها على االكثر اينان من االبناء‪ ,‬فان هذل الشجرة‬
‫تسمى ينائية‪ .‬و تعتبرر االشرجار الثنائيرة هري االبسرط واالكثرر عموميرة‪ .‬االشرجار‬
‫الثنائيررة تتكررون مررن مجموعررة مررن العقررد‪ ,‬بحيررث ان كررل عقرردة تحترروي علررى حقررل‬
‫مؤشر ايمن وحقل مؤشر ايسر فضال عن حقل اخر للبيانات‪ ,‬العقردة االعلرى فري‬
‫الشجرة تسمى جذر‪.‬‬
‫‪ ‬االبناء االينان لكل عقدة في الشجرة الثنائية تدعى االبرن االيسرر واالبرن االيمرن‪,‬‬
‫وفقا لموقعهم عند رسم شجرة معينة‪ ,‬كمرا فري الشركل ‪ .8.11‬العقردة فري الشرجرة‬
‫الثنائية ليس من الضروري ان يكون لها اينان من االبنراء‪ ,‬فربمرا يكرون لهرا ابرن‬
‫واحد سواء باليمين او باليسار‪ ,‬او من الممكن ان ال يكرون لهرا اي ابرن (فري هرذل‬
‫الحالة تسمى ورقة)‪.‬‬

‫شك ‪ :8.11‬شك توضيحي للشجرة الثنائية‪.‬‬

‫‪ 8.6.1‬انوا االشجار الثنائية‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .A‬شجرة ثنائيةة مجةذرة ‪ :Rooted Binary Tree‬هري شرجرة بجرذر حيرث ان‬
‫كل عقدة لها على االكثر اينان من االبناء كما في الشكل ‪.8.12‬‬

‫شك ‪ :8.12‬شجرة ثنائية مجذرة‬

‫‪ .B‬شةجرة ثنائيةة مملةوءة ‪ :Full Binary Tree‬وتردعى احيانرا ( شرجرة ينائيرة‬


‫مناسبة ‪ proper binary tree‬او ‪ ) 2-tree‬وهري شرجرة ينائيرة بحيرث ان كرل‬
‫عقدة عدا االوراق لها اينان من االبناء بالضبط‪ ,‬انظر الشكل ‪.8.13‬‬

‫شك ‪ :8.13‬شجرة ثنائية مملوءة‬


‫‪ .C‬شجرة ثنائية ممتازة ‪ :Perfect Binary Tree‬حيث ان كرل االوراق برنفس‬
‫العمل او نفس المستوى ( احيانا تدعى شرجرة ينائيرة كاملرة وتسربب التشرويش)‪,‬‬
‫كما في الشكل ‪.8.14‬‬

‫‪353‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.14‬شجرة ثنائية ممتازة‪.‬‬

‫‪ .D‬شجرة ثنائية كاملة ‪Complete Binary Tree‬‬

‫الشجرة الثنائية الكاملة هي شجرة ينائية بحيث‪:‬‬

‫‪ ‬كل المستويات عدا من المحتمل المستوى االخير هو بالكامل مملوءة‪ ,‬وكذلك‬


‫‪ ‬المسرتوى االخيررر تكررون جميررع العقررد فرري الجانررب االيسررر (برردون ان تفقررد واحرردة‬
‫بينهم)‪.‬‬

‫شك ‪ :8.15‬شجرة ثنائية كاملة‪.‬‬

‫هنا حاالت ممكنة للشجرة الكاملة‪ ,‬بحيث تكون الشجرة الثنائية‬


‫‪ ‬مملوءة وكاملة‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.16‬شجرة ثنائية مملوءة وكاملة‪.‬‬

‫‪ ‬مملوءة وغير كاملة‬

‫شك ‪ :8.17‬شجرة مملوءة وغير كاملة‪.‬‬

‫‪ ‬كاملة ولكنها غير مملوءة‬

‫شك ‪ :18.18‬شجرة ثنائية كاملة ولكنها غير مملوءة‪.‬‬

‫‪ ‬وايضا ليست كاملة وليست مملوءة‪.‬‬

‫‪355‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.19‬شجرة ثنائية كاملة وليست مملوءة‪.‬‬

‫‪ .E‬شجرة ثنائية متوازنة ‪ :Balance Binary Tree‬حيث ان عمل كل االوراق‬


‫يختلف بمقردار واحرد علرى االكثرر‪ .‬االشرجار المتعادلرة لهرا عمرل يمكرن التنبرؤ بره‬
‫(هي تمثل عدد العقد التي تمر عليها من الجرذر الرى الورقرة‪ ,‬الجرذر يحسرب علرى‬
‫انرره العقرردة صررفروالباقية تحسررب علررى انهررا العمررل ‪ ) .. ,2 ,1‬هررذا العمررل يسرراوي‬
‫جزء العدد الصحيح للعالقة )‪ log2(n‬حيرث ان ‪ n‬يمثرل عردد العقرد فري الشرجرة‬
‫المتعادلة‪ .‬مثال الشجرة المتعادلة التي لها ‪ 3‬عقد يكون عمقها ‪log2(3) = 1.59‬‬
‫اي يساوي ‪.1‬‬
‫تعتبررر الشررجرة متوازنررة اذا كرران كررل مسررتوى فرروق المسررتوى االدنررى مملرروء (بمعنررى‬
‫يحتوي على ‪2n‬عقدة)‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.20‬شجرة ثنائية متوازنة‪.‬‬

‫‪ .F‬شجرة ثنائية غير متوازنة ‪Unbalance Binary Tree‬‬

‫شك ‪ :8.21‬شجرة ثنائية غير متوازنة‪.‬‬

‫‪ .G‬شجرة إعةا ة التوليةد ‪ :Degeneration Tree‬وهري شرجرة ينائيرة بحيرث ان‬


‫لكل عقدة اب هنا فقط ابن يشتر معها‪ .‬هذا يعني انه في قياسات الكفراءة فران‬
‫الشجرة ستعامل مثل هيكل القوائم الموصولة‪.‬‬

‫‪ .H‬االشجار المنحرفة ‪Skew Trees‬‬

‫‪357‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫االشجار المنحرفة هري اشرجار بحيرث تكرون كرل عقردة )عردا العقرد الورقيرة( لهرا ابرن‬
‫واحد فقط‪ .‬هنا نوعين من هذل االشجار‬

‫‪ ‬االول هو االشجار المنحرفة يسارا ‪left skew tree‬‬


‫وهرري شررجرة منحرفررة‪ ,‬بحيررث ان كررل عقرردة ماعرردا الجررذر لهررا عقرردة واحرردة فقررط فرري‬
‫اليسار‪.‬‬

‫شك ‪ :8.22‬شجرة منحرفة يسارا‬

‫‪ ‬النوع الثاني هي االشجار المنحرفة يمينا ‪Right skew tree‬‬


‫هي شجرة منحرفة بحيث كل عقدة عدا الجذر لها عقدة واحدة فقط في اليمين‬

‫شك ‪ :8.23‬شجرة منحرفة يمينا‬

‫اشجار البحث الثنائي ‪Binary Search Tree‬‬ ‫‪8.7‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫هي نوع خاص من االشرجار الثنائيرة‪ .‬الفكررة االساسرية خلرف هرذا النروع مرن هياكرل‬
‫البيانررات هررو ان لهررا مسررتودع خررزن يرروفر طريقررة كفرروءة لترتيررب البيانررات‪ ,‬البحررث‪,‬‬
‫واستعادة البيانات‪.‬‬
‫اشجار البحرث الثنرائي تظهرر سرلو خراص‪ ,‬هرو ان العقردة التري فري الجانرب االيسرر‬
‫(االبن االيسر) يجب ان يكون له قيمة (مفتاح) اقل من قيمرة االب‪ ,‬والعقردة التري فري‬
‫اليمين (االبن االيمن) يجب ان تكون له قيمة (مفتاح) اكبر من قيمة االب‪ ,‬وال يسمح‬
‫بتكرار المفتاح في الشجرة‪.‬‬

‫الشجرة الثنائية التي لها المواصفات التالية تسمى شجرة البحث الثنائي‬
‫‪ ‬كررل قيمررة (مفترراح) فرري الشررجرة تكرررر بالضرربط كحررد اعلررى مرررة واحرردة (اي‬
‫اليوجد تكرار)‬
‫‪ ‬العالقات اكبر من واقل من‪ ,‬تعرف بشكل جيد لقيم البيانات‪.‬‬
‫‪ ‬محددات الترتيب‪ :‬لكل عقدة )‪(n‬‬
‫كل البيانات فري الشرجرة الفرعيرة اليسررى للعقردة )‪ (n‬هري اقرل مرن‬ ‫‪‬‬
‫البيانات في الجذر لتلك الشجرة الفرعية‪.‬‬
‫كل البيانرات فري الشرجرة الفرعيرة اليمنرى للعقردة )‪ (n‬هري اكبرر مرن‬ ‫‪‬‬
‫البيانات التي في الجذر لتلك الشجرة الفرعية‪.‬‬

‫‪ 8.7.1‬وبوات بناء شجرة البحث الثنائي‬


‫‪ .A‬الرقم االول يعتبر جذر‪.‬‬
‫‪ .B‬االرقام التالية اذا كانت اكبر من الجذر توضع في اليمين واذا اقل من الجذر‬
‫توضع في اليسار‪.‬‬

‫مثال ‪ :1‬ارسم شجرة بحث ينائي للبيانات ‪12, 16, 5, 7, 4, 13, 21, 2‬‬

‫‪359‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.24‬شجرة بحث ثنائية لتمثي القيم ‪12, 16, 5, 7, 4, 13, 21, 2‬‬

‫مثال ‪ : 2‬دعنا نرى المثرال الترالي ضرافة قائمرة االرقرام التاليرة والتري سريتم توضريح‬
‫االضافة بالتفصيل‪ ,‬حيث اننا سننتهي بشجرة مثل التي في الشكل ‪:8.25‬‬
‫‪32, 16, 34, 1, 87, 13, 7, 18, 14, 19, 23, 24, 41, 5, 53‬‬

‫حيررث ان القيمررة ‪ 32‬هرري اول قيمررة سرريتم اضررافتها‪ ,‬لررذا فرران ‪ 32‬سررتكون جررذر‬ ‫‪‬‬
‫الشجرة‪.‬‬
‫القيمة التالية هي (‪ )16‬والتي هي اصغر من القيمة ‪ ,32‬لذا فانها ستكون العقردة‬ ‫‪‬‬
‫التي على يسار العقدة ‪.32‬‬
‫(‪ )34‬وحيث ان ‪ 34‬اكبر من ‪ ,32‬عليه فان ‪ 34‬ستكون العقدة التي توضع على‬ ‫‪‬‬
‫يمين الجذر‪.‬‬
‫القيمة (‪ )1‬وهي اصغر من ‪ 32‬لرذا سريكون االتجرال الرى العقردة اليسررى للجرذر‪.‬‬ ‫‪‬‬
‫وبما ان العقدة في اليسار مشغولة بقيمة (‪ ,)16‬لذا يتم اختبار القيمرة ‪ 1‬مرع قيمرة‬
‫العقدة التي في اليسار ‪ ,16‬وحيث ان ‪ 1‬اصرغر مرن ‪ 16‬عليرة فران ‪ 1‬يكرون الرى‬
‫يسار العقدة ‪.16‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫القيمة (‪ )87‬وحيث ان ‪ 87‬اكبرر مرن ‪ 32‬سريكون االتجرال الرى العقردة التري علرى‬ ‫‪‬‬
‫يمين الجذر‪ ,‬وهذل العقردة مشرغولة بالقيمرة (‪ ,)34‬لرذا تقرارن مرع ‪ ,87‬وحيرث ان‬
‫‪ 87‬اكبر من ‪ 34‬لذا فان هذل القيمة ستكون على يمين العقدة ‪.34‬‬
‫(‪ )13‬وحيث ان ‪ 13‬اصغر من ‪ ,32‬سيكون االتجال الى العقدة يسرار الجرذر‪ ,‬يرم‬ ‫‪‬‬
‫تقارن مع العقدة التي على اليسار التي قيمتها ‪ ,16‬وحيث ان ‪ 13‬اصغر من ‪16‬‬
‫تستمر الحركة الى العقدة التي على يسار العقدة ‪ 16‬والتي هري مشرغولة بالعقردة‬
‫التي تحمل القيمرة ‪ 1‬وتقرارن مرع القيمرة الجديردة‪ ,‬وحيرث ان ‪ 13‬اكبرر مرن ‪ 1‬لرذا‬
‫فان القيمة المضافة ‪ 13‬ستكون على يمين العقدة ‪.1‬‬
‫يستمر هذا النهج لبقية القيم ‪.7, 18, 14, 19, 23, 24, 41, 5‬‬ ‫‪‬‬
‫(‪ )53‬وحيث ‪ 53‬اكبر من ‪ 32‬فسيكون موقعها في فرع الشجرة االيمرن للجرذر‪.‬‬ ‫‪‬‬
‫كذلك ‪ 53‬اكبر من ‪ 34‬لذا استمر باتجال اليمين للعقدة ‪ .34‬ايضا ‪ 53‬اصغر مرن‬
‫‪ 87‬لذا يكون االتجال الى يسار العقدة ‪ .87‬بعردها تقرارن مرع ‪ ,41‬وحيرث ان ‪53‬‬
‫اكبر من ‪ 41‬لذا يكون االتجال الى يمين العقردة ‪ ,41‬ونظررا الرى ان يمرين العقردة‬
‫‪ 41‬فار او خالي من اي قيمة لذا فان ‪ 53‬ستكون العقدة التي على يمرين العقردة‬
‫‪.41‬‬
‫الخطوات اعالل تعطيك فكرة عامة عن كيفية خلل االشجار الثنائية‪ .‬يجب عليك‬
‫ان تعلم ان‪:‬‬
‫‪ ‬ربط عقدة الى عقدة اخرى في االشرجار الثنائيرة هرو بطبيعتره واحرد الرى واحرد‪..‬‬
‫اي ان العقدة اليؤشر عليها باكثر من عقدة واحدة‪.‬‬
‫‪ ‬العقدة الواحدة بامكانها ان تؤشر الى اينين من العقد الثانوية كحد اعلى‪.‬‬
‫هنا في الشجرة الثنائية الناتجة في الشركل ‪ ,8.25‬هنرا كثيرر مرن العقرد لرديها مؤشرر‬
‫اليسار خالي‪ ,‬مثل العقد‬
‫‪ 53 ,41 ,34 ,24 ,23 ,19 ,18 ,1 ,14 ,5‬والتي عقدها من اليسار خالية‪.‬‬

‫‪361‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.25‬شجرة ثنائية تم بنائها لتمث القيم ( ‪32, 16, 34, 1, 87, 13, 7, 18, 14, 19,‬‬
‫‪)23, 24, 41, 5, 53‬‬

‫‪ 8.8‬ال مليات التي تجرى علل اشجار البحث الثنائي‬


‫هنررا عرردد مررن العمليررات المهمررة الترري تجرررى علررى شررجرة البحررث الثنررائي‪ ,‬سررنحاول‬
‫توضيحها مع االشارة الى شفرات البرامج الخاصة بها وهي‪:‬‬
‫‪ .A‬البحث‪ :‬وهي عملية البحث عن عنصر معين وحسب قيمته في الشجرة‪.‬‬
‫‪ .B‬االضافة‪ :‬وهي عملية اضافة عنصر جديد للشجرة الثنائية‪.‬‬
‫‪ .C‬الحذف‪ :‬وهي عملية حذف احد عناصر الشجرة الثنائية‪.‬‬
‫‪ .D‬المرررور علررى عناصررر الشررجرة‪ :‬وهرري عمليررة زيررارة جميررع عناصررر الشررجرة‬
‫الثنائية‪.‬‬

‫‪ 8.8.1‬عملية البحث ‪Search Operation‬‬

‫لغرض البحث عن عنصر معين عليك ان تبدا عملية البحث من الجذر‪ ,‬وتتم مقارنة‬
‫قيمرة البيانرات التري تبحررث عنهرا مرع قيمررة المفتراح (قيمرة العقرردة)‪ ,‬وطبعرا امرا ان يررتم‬
‫البحث في فرع الشجرة االيمن اذا كانت قيمة البيانات اكبر من قيمة المفتراح‪ ,‬او يرتم‬
‫البحث في فرع الشجرة االيسر اذا كانت قيمة البيانات اصغر من قيمة المفتراح‪ .‬هرذا‬
‫يتم تنفيذل على كل عقدة لحين الوصول الى البيانات المطلوب البحرث عنهرا او ربمرا‬
‫نصل الى نهاية الشجرة (االوراق) دون ان نجد البيانات‪ .‬خوارزمية البحث هي‪:‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .1‬اذا تساوت بيانات الجذر مع البيانات التي نبحث عنها‪ ,‬عندها سيكون الجذر‬
‫هو العقدة المطلوبة‪.‬‬
‫‪ .2‬اذا لم تساوي الجذر‪ ,‬يتم البحث في العقد االخرى‪.‬‬

‫‪ .A‬اذا كانت البيانات التي نبحث عنها اكبر من بيانات العقدة (المفتاح)‪:‬اذهب‬
‫الى فرع الشجرة االيمن‪.‬‬
‫‪ .B‬اما اذا كانت القيمة التي يتم البحث عنها اصرغر مرن قيمرة المفتراح‪ ,‬اذهرب‬
‫الى فرع الشجرة االيسر‪.‬‬

‫‪ .3‬اذا تم ايجاد القيمة يتم اعادتها (طباعتها‪,‬عرضها او وضعها بمتغير ‪...‬الا)‪.‬‬


‫‪ .4‬اذا لم يتم ايجاد أي بيانات مطابقة يتم عرض رسالة بان البيانات التي نبحث‬
‫عنها غير موجودة‪.‬‬

‫‪ 8.8.2‬عملية االضافة ‪Insert Operation‬‬

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

‫‪ .1‬اذا كانت الشجرة خاليرة (اذا كران الجرذر يسراوي ‪ ,) null‬يرتم خلرل عقردة لتكرون‬
‫هي الجذر‪.‬‬
‫‪ .2‬اذا كان هنا جذر‪ ,‬تتم عملية مقارنة البيانات مع المفتاح (بيانات العقدة)‪.‬‬
‫‪ .3‬يتم عمل حلقة تكرار يجاد الموقع المطلوب لعملية االضافة‪.‬‬

‫‪363‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .A‬اذا كانت البيانات المطلوب اضافتها اكبر من قيمرة المفتراح‪ ,‬يرتم الرذهاب الرى‬
‫فرع الشجرة االيمن‬
‫‪ .B‬بخالف ذلك‪ ,‬أي عندما تكون البيانات اصرغر مرن قيمرة المفتراح فيرتم الرذهاب‬
‫الى فرع الشجرة االيسر‪.‬‬

‫‪ .4‬عند انتهاء حلقة التكرار يتم اضافة البيانات‪.‬‬

‫‪ 8.8.3‬عملية حذذ عنصر ‪Removing an Element‬‬

‫عمليرة ازالررة او حرذف عنصررر مرن شررجرة البحرث الثنررائي هري عمليررة معقردة نسرربة‬
‫للعمليات االخرى‪ .‬حيث من المفروض بعد الحرذف يجرب ان تبقرى الشرجرة بشركل‬
‫مرتب‪.‬‬
‫ان اول خطوة قبل عملية ازالة عنصر من الشجرة هرو ايجراد هرذا العنصرر‪ .‬وهرذا‬
‫يررتم تحديرردل مررن خوارزميررة البحررث‪ .‬بعررد ايجرراد العنصررر المطلرروب هنررا يررالث‬
‫حاالت‪:‬‬
‫‪ .A‬اذا العقدة المراد حذفها هي ورقرة (العقردة التري لريس لهرا ابنراء)‪ ,‬فري هرذل الحالرة‬
‫فان الخوارزمية ستؤشر على الرابط المقابل الذي يربط العقدة مرع االب بالقيمرة‬
‫‪( null‬اي ان العنوان الذي يشرير للعقردة المرراد حرذفها فري حقرل العنروان للعقردة‬
‫السررابقة يجرررب ان يشررير الرررى ‪ .)null‬فمررثال اذا اردنرررا حررذف القيمرررة (‪ )-4‬مرررن‬
‫الشجرة في الشكل ‪ 8.26-A‬فان الناتج سيكون في الشكل ‪( 8.26-B‬حيث سيتم‬
‫وضع ‪ null‬في حقل العنوان االيسر للعقدة التي تحمل القيمة ‪.)2‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ .A :8.26‬شجرة ثنائية مؤشر فيها ال قدة المبلوب حذفها‪ .B .‬الشجرة ب د‬


‫ا راء عملية الحذذ‪.‬‬

‫‪ .B‬اذا العقدة لها فقط شجرة فرعيرة واحردة‪ ,‬شرجرة فرعيرة يمنرى او يسررى (أي لهرا‬
‫ابن واحد)‪ ,‬في هذل الحالة تحذف هذل العقدة من الشرجرة‪ ,‬والخوارزميرة سرتربط‬
‫االبن الوحيد لهذل العقدة (حتى لو كان يمثل جذر لشجرة فرعية) مع العقدة التري‬
‫تمثل اب العقدة التي تم حذفها‪ .‬مثال في الشكل ‪ 8.27‬مطلوب حذف العقدة التري‬
‫لها القيمة ‪.18‬‬

‫‪365‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ .A :8.27‬شجرة ثنائية مؤشر عليها ال قدة المبلوب حذفها‪ .B .‬طريقة ربط ال قد ب د‬
‫الحذذ‪ .C .‬الشجرة ب د الحذذ‪.‬‬

‫الحالة الثالثة‪ :‬ان تكون العقدة المطلوب حذفها لها اينان من االبناء (من الممكن ان‬
‫يكون االبناء جذور ألشجار فرعية)‪ ,‬في هذل الحالة يجب ان نجد العقدة االصغر في‬
‫الشجرة الفرعية اليمنى للعقدة المراد حذفها ونبدلها مع قيمة العقدة المراد حذفها‪ .‬بعد‬
‫هذا التبديل فان العقدة سيكون لها شجرة فرعية واحدة على االكثر‪ ,‬عندها نحذف‬
‫العقدة وفل القواعد او الحاالت االينان اعالل‪ .‬هنا سنقول من الممكن عمل تبديل‬
‫تناظري‪ ,‬أي نعمل نفس الشيء عند العمل على الشجرة الفرعية اليسرى وتكون‬
‫عملية التبديل هنا مع اكبر عنصر في فرع الشجرة االيمن‪ .‬في الشكل ‪ 8.28‬مطلوب‬
‫حذف العقدة التي تحمل القيمة ‪.11‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫يرجى مالحظة ان العقدة المطلوب حذفها ستبقى بمكانها اينراء ابردال القريم لرذلك‬
‫فاننررا عنرردما نبرردل القرريم ال يعنرري ان نحررذف العقرردة الترري اصرربحت تحمررل القيمررة‬
‫المطلوب حذفها وانما حذف العقردة التري كانرت تحمرل تلرك القيمرة بمعنرى عنردما‬
‫نقول مطلوب حذف العقدة التي تحمل القيمرة ‪ 11‬وترم ابردال القيمرة ‪ 11‬مرن هرذل‬
‫العقدة فران هرذا اليغيرر الفكررة الن العقردة هري ذاتهرا مطلروب حرذفها وان حملرت‬
‫قيمة اخرى‪.‬‬

‫شك ‪ :8.28‬شجرة ثنائية محد عليها ال قدة المبلوب حذفها وال قدة التي يتم االبدال م ها‪.‬‬

‫العقدة ‪ 11‬لها شرجرتين فررعيتين ووفقرا لخوارزميتنرا‪ ,‬فانره يجرب ان يرتم التبرديل مرع‬
‫اصغر عنصر من الشجرة الفرعية اليمنى‪ ..‬وهي القيمة ‪ .13‬بعد عملية التبديل‪ ,‬فاننا‬
‫من الممكن ان نزيل ‪( 11‬هي ورقة االن)‪ .‬وستكون النتيجرة النهائيرة كمرا فري الشركل‬
‫‪.8.29‬‬

‫‪367‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.29‬الشجرة ب د اكمال عملية الحذذ‪.‬‬

‫‪ ‬مثال اخر في الشكل ‪ 8.30‬مطلوب حذف العقدة التي لها القيمة ‪ 8‬وهي جذر‪.‬‬

‫شك ‪ :8.30‬شجرة ثنائية قب وب د حذذ القيمة ‪ 8‬من فر الشجرة اليسرى‪.‬‬

‫ان طريقة الحذف تتبع مايلي‪ :‬ابدال العقدة المراد حذفها مع العقدة التي لها اكبر قيمة‬
‫في الشجرة الفرعية اليسرى وبعدها يتم حذف العقدة التي لها القيمة الكبيرة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مرن الممكرن ايضرا وبرنفس الطريقرة ان تبردل المفتراح (القيمرة ‪ )8‬مرع العقردة التري لهرا‬
‫اصغر قيمة في فرع الشجرة اليمنى‪ ,‬ويتم حذف العقدة التي لهرا القيمرة االصرغر كمرا‬
‫في الشكل ‪.8.31‬‬

‫شك ‪ :8.31‬شجرة ثنائية قب وب د حذذ القيمة ‪ 8‬من فر الشجرة اليمنل‪.‬‬

‫مثال اخر في الشكل )‪ (8.32-A‬مطلوب حرذف العقردة التري لهرا القيمرة ‪.11‬‬ ‫‪‬‬
‫في هذل الحالة سيتم االبدال مع اكبر قيمرة فري فررع الشرجرة االيسرر والتري هري ‪,10‬‬
‫بعدها يتم حذف العقدة كما في الشكل )‪ .(8.32-B‬كرذلك مرن الممكرن ان نعمرل علرى‬
‫فرع الشجرة االيمن ونبحث عرن اصرغر قيمرة فري هرذا الفررع وهري القيمرة ‪ 17‬ويرتم‬
‫اجراء التبديل يم حذف العقدة كما في الشكل )‪.(8.32-C‬‬

‫‪369‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ .A :8.32‬شجرة ثنائية محد بها ال قدة المبلوب حذفها‪ .B .‬الشجرة ب د الحذذب تم‬
‫استالدا فر الشجرة االيسر للتبدي ‪ .C .‬الشجرة ب د الحذذب تم استالدا فر الشجرة االيمن‬
‫للتبدي ‪.‬‬

‫عملية المرور ‪Traversal‬‬ ‫‪8.8.4‬‬

‫هرري زيررارة كررل عقرردة فرري الشررجرة وربمررا يررتم طباعررة قيمهررا‪ .‬وبسرربب ان كررل العقررد‬
‫مرتبطة بروابط او مسارات‪ ,‬لذلك يجب ان تكون البداية من الجذر‪ .‬مع مالحظة انره‬
‫من غير الممكن الوصول عشوائيا الى اي عقدة في الشجرة‪.‬‬

‫هنا يالث طرق تستخدم لزيارة الشجرة‪:‬‬

‫‪ In-order Traversal‬المرور بالترتيب االعتيادي‬ ‫‪‬‬

‫‪ Pre-order Traversal‬المرور بالترتيب القبلي‬ ‫‪‬‬

‫‪ Post-order Traversal‬المرور بالترتيب البعدي‬ ‫‪‬‬

‫‪ .A‬المرور بالترتيب االعتيا ي‬

‫في هذل الطريقة فان الزيارة تبدا بفررع الشرجرة االيسرر‪ ,‬بعردها الجرذر ومرن يرم فررع‬
‫الشجرة االيمرن‪ .‬علينرا ان نترذكر دائمرا بران كرل عقردة فري الشرجرة تمثرل فررع شرجرة‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫بنفسررها‪ .‬عنررد المرررور علررى الشررجرة الثنائيررة بالترتيررب االعتيررادي‪ ,‬فرران المخرجررات‬
‫ستكون عبارة عن قيم (او مفاتيح) مرتبة بترتيب تصاعدي‪.‬‬

‫ايسر – ذر – ايمن‬

‫شك ‪ :8.33‬شجرة ثنائية تتم زيارتها ببريقة الترتيب االعتيا ي وحسب الترقيم الموضح في‬
‫الشك ‪.‬‬

‫البداية تكون من الجذر ‪ ,A‬وباتباع طريقة الترتيب االعتيادي ستكون الحركة لليسار‬
‫الى فررع الشرجرة ‪ .B‬فررع الشرجرة ‪ B‬هرو ايضرا جرذر لرذلك تسرتمر الحركرة لليسرار‬
‫(النرره ترتيررب اعتيررادي)‪ .‬بعررد اكمررال فرررع الشررجرة االيسررر تررتم زيررارة الجررذر لفرررع‬
‫الشجرة ومن يم زيارة فرع الشجرة االيمن لهذا الفرع‪ .‬هرذل العمليرة تسرتمر لحرين ان‬
‫تتم زيارة كل العقد‪ .‬مخرجات هذل الطريقة هو‬
‫‪D→B→E→A→F→C→G‬‬
‫خوارزمية هذل الطريقة هي‪:‬‬

‫‪ .1‬زيارة فرع الشجرة االيسر بطريقة التكرار واالستدعاء الذاتي‪.‬‬


‫‪ .2‬زيارة الجذر‪.‬‬

‫‪371‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .3‬زيارة فرع الشجرة االيمن بطريقة التكرار واالستدعاء الذاتي‪.‬‬

‫‪ .B‬الزيارة ببريقة الترتيب القبلي ‪Preorder Travers‬‬

‫في هذل الطريقة فان الجذر سيتم زيارته اوال‪ ,‬بعدها تتم زيارة فرع الشرجرة االيسرر‪,‬‬
‫واخيرا زيارة فرع الشجرة االيمن‪.‬‬

‫ذر – ايسر – ايمن‬

‫شك ‪ :8.34‬شجرة ثنائية تتم زيارتها ببريقة الترتيب القبلي وحسب الترقيم الموضح في‬
‫الشك ‪.‬‬

‫تكون البداية من الجرذر ‪ ,A‬وباتبراع طريقرة الترتيرب القبلري فران الجرذر سريكون اول‬
‫عقدة تتم زيارتها‪ ,‬بعدها يتم االنتقال الرى فررع الشرجرة االيسرر‪ .‬كرذلك فران العقردة ‪B‬‬
‫ستعتبر جذر ويتم زيارتها وبعدها يتم االنتقال الى اليسار‪ .‬هرذل العمليرة تسرتمر لحرين‬
‫زيارة جميع العقد‪ .‬مخرجات هذل الطريقة هي‪:‬‬
‫‪A→B→D→E→C→F→G‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫خوارزمية هذل الطريقة هي‪:‬‬


‫‪ .1‬زيارة عقدة الجذر‪.‬‬
‫‪ .2‬زيارة فرع الشجرة االيسر بطريقة التكرار واالستدعاء الذاتي‪.‬‬
‫‪ .3‬زيارة فرع الشجرة االيمن بطريقة التكرار واالستدعاء الذاتي‪.‬‬

‫‪ .C‬الزيارة ببريقة الترتيب الب دي ‪Postorder Travers‬‬


‫في هذل الطريقة فان الجذر يتم زيارته اخيرا‪ ,‬ولذلك جاء االسم الترتيب البعردي‪ .‬فري‬
‫البداية تتم زيارة فررع الشرجرة االيسرر‪ ,‬يرم زيرارة فررع الشرجرة االيمرن‪ ,‬واخيررا ترتم‬
‫زيارة الجذر‪.‬‬
‫ايسر – ايمن ‪ -‬ذر‬

‫شك ‪ :8.35‬شجرة ثنائية تتم زيارتها ببريقة الترتيب الب دي وحسب الترقيم الموضح في‬
‫الشك ‪.‬‬

‫البدايررة مررن العقرردة ‪ ,A‬وباتبرراع طريقررة الترتيررب البعرردي فسرريكون المسررار الررى فرررع‬
‫الشررجرة االيسررر ‪ .B‬ايضررا العقرردة ‪ B‬تعتبررر جررذر فيررتم االسررتمرار الررى اليسررار‪ .‬بعررد‬
‫اكمال زيارة فرع الشجرة االيسر تتم زيارة فررع الشرجرة االيمرن الي جرذر‪ ,‬تسرتمر‬
‫هذل العملية لحين المرور على كامل العقد في الشجرة‪ .‬نتيجة هذل الطريقة هي‪:‬‬

‫‪373‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪D→E→B→F→G→C→A‬‬

‫خوارزمية الترتيب البعدي هي‪:‬‬

‫‪ .1‬زيارة فرع الشجرة االيسر بطريقة التكرار واالستدعاء الذاتي للدالة‪.‬‬


‫‪ .2‬زيارة فرع الشجرة االيمن بطريقة التكرار واالستدعاء الذاتي للدالة‪.‬‬
‫‪ .3‬زيارة الجذر‪.‬‬

‫مثرال‪ :‬فرري الشرركل ‪ 8.36‬شررجرة ينائيررة المطلرروب المرررور علررى عناصرررها باسررتخدام‬
‫طرق المرور الثالث‪.‬‬

‫شك ‪ :8.36‬شجرة ثنائية‪.‬‬

‫‪a b d h e c f g‬‬ ‫‪ Preorder‬الترتيب القبلي‪:‬‬


‫‪ Inorder‬الترتيب االعتيا ي‪h d b e a f c g :‬‬

‫‪h d e b f g c a‬‬ ‫‪ Postorder‬الترتيب الب دي‪:‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫مثةةال‪ :‬فرري الشرركل ‪ 8.37‬شررجرة ينائيررة المطلرروب المرررور علررى عناصرررها باسررتخدام‬
‫خوارزميات الترتيب الثالث‪.‬‬

‫شك ‪ :8.37‬شجرة ثنائية‪.‬‬

‫‪10, 14, 19, 27, 31, 35, 42‬‬ ‫الترتيب االعتيا ي ‪:‬‬
‫‪27, 14, 10, 19, 35, 31, 42‬‬ ‫الترتيب القبلي ‪:‬‬
‫‪10, 19, 14, 31, 42, 35, 27‬‬ ‫الترتيب الب دي ‪:‬‬

‫من الممكن ان نفهم او نتابع طريقة المرور من خالل االشكال (وهي طريقة تستخدم‬
‫العالمات)‪ ,‬ال تختلف عن الطرقية السابقة اال انها ربما تسهل الفهم‪.‬‬
‫هرري ببسرراطة ان نضررع عالمررة علررى عقرردة واحرردة تمثررل طريقررة الترتيررب كمررا فرري‬
‫الشكل ‪.8.38‬‬

‫شك ‪ : 8.38‬عقد مفر ة توضح كيفية المرور عليها باستالدا ع مة تمث الجذر‪.‬‬

‫‪375‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫في الشكل ‪ 8.38‬نالح االشارة الحمراء والتي تشير الى الجذر والفرع مرن الردائرة‬
‫تشير الى االبن االيسر وااليمرن ويكرون متابعرة المررور مرن اليسرار الرى اليمرين لكرل‬
‫عقرردة (العالمررة الحمررراء تشررير الررى موقررع الجرردر نسرربة للفررروع عنررد المرررور برراي‬
‫ترتيب) ‪ .‬فمرثال بالترتيرب القبلري فران االشرارة الحمرراء هري فري اقصرى اليسرار وهرذا‬
‫يعنرري انهررا سررتكون اول مرن يررتم زيارترره يررم االبررن االيسررر واخيرررا االبررن االيمررن‪ .‬فرري‬
‫الترتيب االعتيادي فان العالمة الحمراء هي في الوسط وهذا يعني ان الجذر سريكون‬
‫في الوسط‪ ,‬حيث نبردا مرن اليسرار وهنرا سريكون االبرن االيسرر يرم يراتي بعردها الجرذر‬
‫المعلررم بالعالمررة الحمررراء واخيرررا االبررن االيمررن‪ .‬وهكررذا للترتيررب البعرردي حيررث ان‬
‫العالمة الحمراء تشير الى اليمرين وهرذا يعنري ان الجرذر سريكون براليمين ولرذلك فران‬
‫الترتيب يبدا بالعقدة اليسرى يم اليمنى وبعدها الجذر‪.‬‬
‫هذل العملية يمكن اجرائها لجميع عقد الشجرة وحسب طريقرة المررور فمرثال اذا كران‬
‫المطلوب مرور بالترتيب القبلي فيتم تعليم جميع العقرد برنفس الطريقرة التري قمنرا بهرا‬
‫في الشكل ‪ 8.38‬وعندها يرتم المررور علريهم جميعرا بسرهولة مرن اليسرار الرى اليمرين‪,‬‬
‫كما هو موضح في الشكل ‪.8.39‬‬

‫شك ‪ :8.39‬توضيح لبريقة المرور باستالدا الت ليم‪.‬‬


C++ ‫هياكل البيانات باستخدام‬

‫برنامج شامل الغلب العمليات التي تجرى على االشجار الثنائي‬ 8.8.5
#include<iostream>

#include<cstdlib>

using namespace std;

struct tree {

int info;

tree *Left, *Right;

};

tree *root;

class Binary_tree{

public:

Binary_tree();

void insert1(int);

tree *insert2(tree *, tree *);

void Delete(int);

void pretrav(tree *);

void intrav(tree *);

void posttrav(tree *);

};

377
C++ ‫هياكل البيانات باستخدام‬

Binary_tree::Binary_tree() {

root = NULL;

tree* Binary_tree::insert2(tree *temp,tree *newnode) {

if (temp==NULL) {

temp=newnode;
}

else if (temp->info < newnode->info) {

insert2(temp->Right, newnode);

if(temp->Right = =NULL)

temp->Right = newnode;

else{

insert2(temp->Left,newnode);

if(temp->Left==NULL)
C++ ‫هياكل البيانات باستخدام‬

temp->Left=newnode;

return temp;

void Binary_tree::insert1(int n){

tree *temp=root,*newnode;

newnode=new tree;

newnode->Left=NULL;

newnode->Right=NULL;

newnode->info=n;

root=insert2(temp,newnode);

void Binary_tree::pretrav(tree *t = root){

if(root == NULL){

cout<<"Nothing to display";

}else

if(t != NULL){

cout<<t->info<<" ";

pretrav(t->Left);

pretrav(t->Right);

379
C++ ‫هياكل البيانات باستخدام‬

void Binary_tree::intrav(tree *t = root){

if(root==NULL){

cout<<"Nothing to display";
} else

if(t!=NULL){

intrav(t->Left);

cout<<t->info<<" ";

intrav(t->Right);

void Binary_tree::posttrav(tree *t = root){

if(root==NULL){

cout<<"Nothing to display";

} else

if(t!=NULL){

posttrav(t->Left);
C++ ‫هياكل البيانات باستخدام‬

posttrav(t->Right);

cout<<t->info<<" ";

void Binary_tree::Delete(int key)

tree *temp = root,*parent = root, *marker;

if (temp==NULL)

cout<<"The tree is empty"<<endl;

else {

while (temp!=NULL && temp->info!=key){

parent=temp;

if (temp->info<key){

temp=temp->Right;

} else {

temp=temp->Left;

marker=temp;

if (temp==NULL)

381
C++ ‫هياكل البيانات باستخدام‬

cout<<"No node present";

else if (temp==root){

if (temp->Right = =NULL && temp->Left = =NULL) {

root=NULL;

else if (temp->Left==NULL){
root=temp->Right;

else if (temp->Right==NULL){

root=temp->Left;

else {

tree *temp1;

temp1 = temp->Right;

while (temp1->Left!=NULL){

temp=temp1;

temp1=temp1->Left;

if (temp1!=temp->Right){

temp->Left=temp1->Right;

temp1->Right=root->Right;
C++ ‫هياكل البيانات باستخدام‬

temp1->Left=root->Left;

root=temp1;

else{

if (temp->Right==NULL && temp->Left==NULL){

if (parent->Right==temp)

parent->Right=NULL;

else

parent->Left=NULL;

else if (temp->Left==NULL){

if (parent->Right==temp)

parent->Right=temp->Right;

else

parent->Left=temp->Right;

else if (temp->Right==NULL){

if (parent->Right==temp)

parent->Right=temp->Left;

else

383
C++ ‫هياكل البيانات باستخدام‬

parent->Left=temp->Left;

}else {

tree *temp1;

parent=temp;

temp1=temp->Right;

while (temp1->Left!=NULL){
parent=temp1;

temp1=temp1->Left;

if (temp1!=temp->Right){

temp->Left=temp1->Right;

temp1->Right=parent->Right;

temp1->Left=parent->Left;

parent=temp1;

delete marker;

int main(){

Binary_tree bt;
C++ ‫هياكل البيانات باستخدام‬

int choice, n, key;

while (1){

cout<<"\n\t1. Insert\n\t2. Delete\n\t3. Preorder Traversal\n\t4.


Inorder Treversal\n\t5. Postorder Traversal\n\t6. Exit" <<endl;

cout<<"Enter your choice: ";

cin>>choice;

switch(choice){

case 1:

cout<<"Enter item: ";

cin>>n;

bt.insert1(n);

break;

case 2:

cout<<"Enter element to delete: ";

cin>>key;

bt.Delete(key);

break;

case 3:

cout<<endl;

bt.pretrav();

break;

case 4:

385
‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪cout<<endl‬‬

‫;)(‪bt.intrav‬‬

‫;‪break‬‬

‫‪case 5:‬‬

‫;‪cout<<endl‬‬

‫;)(‪bt.posttrav‬‬
‫;‪break‬‬

‫‪case 6:‬‬

‫;)‪exit(0‬‬

‫}‬

‫}‬

‫;‪return 0‬‬

‫}‬

‫‪ 8.9‬اشجار الت ابير الرياضية ‪Expression Tree‬‬


‫المترررجم فرري الحاسرروب يسررتخدم االشررجار الثنائيررة لتمثيررل التعررابير الرياضررية‪ .‬ه رذل‬
‫االشجار الثنائية التي تستخدم العالقات الرياضية تسمى اشجار تعرابير‪ ,‬فهري اشرجار‬
‫تحتوي مجموعة من العقرد وكرل عقردة تحتروي علرى عمليرات ينائيرة (وهري العمليرات‬
‫الترري تنفررذ علررى اينرران مررن المعررامالت مثررل عمليررات الجمررع والطرررح وغيرهررا) او‬
‫معامالت ( وهي القيم التي تنفذ عليها العمليات الرياضية)‪.‬‬
‫كمررا سرربل وان وضررحنا فرري فصررل المكرردس فرران العالقررات الرياضررية مررن الممكررن ان‬
‫نمثلها بثالث طرق وهي )‪ (infix, prefix, and postfix‬وهذل جميعا من الممكن‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫ان نمثلها في شجرة ينائية كما سبل وان وضرحنا فري هرذا الفصرل‪ .‬سرنحاول توضريح‬
‫كيفية تحويل هذل التعابير الرى اشرجار ينائيرة وكرذلك كيرف مرن الممكرن قرراءة شرجرة‬
‫تعبير رياضي‪ .‬في الجدول ‪ 8.1‬توضيح للتعابير الرياضية التي سبل وان تم شرحها‬
‫في فصل المكدس‪.‬‬

‫دول ‪ :8.1‬توضيح للت ابير الرياضية باشكالها الث ث‪.‬‬

‫نفرررض ان تعبيررر رياضرري يحترروي علررى عوامررل الجمررع (‪ ,)+‬الطرررح (‪ ,)-‬الضرررب‬


‫(*)‪ ,‬والقسرمة (‪ )/‬فرري شررجرة التعبيررر‪ ,‬عليرره فرران كرل عامررل رياضرري لديرره اينرران مرن‬
‫االبناء اما ان تحتوي هذل االبناء معامل‪ ,‬او تعبير يانوي (شجرة فرعية)‪.‬‬
‫شجرة التعبير الثنائي تتكون من ‪:‬‬
‫‪ ‬عقد االوراق والتي تحتوي على معامل مفرد (من الممكن ان تكرون قريم‪ ,‬او‬
‫حروف او حتى نصوص وكلمات ‪...‬الا)‪.‬‬
‫‪ ‬عقد ليست ورقيرة والتري تحتروي عوامرل رياضرية ينائيرة مثرل ‪(+, -, *, /,‬‬
‫)‪.%‬‬
‫‪ ‬اشجار فرعية يمين ويسار العامل الرياضي‪ ,‬توصف على انها تعبير فرعي‬
‫او يانوي‪.‬‬
‫الح الشكل ‪ 8.40‬الذي يصف التعابير الرياضية‪.‬‬

‫‪387‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.40‬اشجار الت ابير الرياضية‪.‬‬

‫م حظة‪ :‬في شجرة التعبير فان كل عامل رياضي هو عقدة داخلية ‪ interior‬والتري‬
‫لهررا ابنرراء‪ ,‬االبنرراء امررا معررامالت او تعررابير يانويررة‪ .‬ودائمررا المعررامالت هرري فري العقررد‬
‫الورقية‪.‬‬
‫الخطررروات التاليرررة توضرررح طريقرررة تنفيرررذ خوارزميرررة بنررراء شرررجرة تعبيرررر للتعبيرررر‬
‫الرياضي ‪ a+b*c‬على شكل ترتيب بعردي‪ .‬ترذكر ان التعامرل مرع التعبيرر الرياضري‬
‫سيتم عن طريل المكدس كما سبل ووضحنا في فصل المكردس‪ .‬هنرا للسرهولة سروف‬
‫نمثررل المكرردس علررى شرركل افقرري (هررو بكررل الحرراالت تمثيررل افتراضرري)‪ .‬تررذكر ان كررل‬
‫عنصر هو شجرة يانوية توصف بجذرها‪ .‬اذن التعبير البعدي للعالقة يكون‪:‬‬
‫‪abc*+‬‬

‫‪ .1‬الخطوة االولى‪ :‬يتم تمييز الحررف ‪ a‬كمعامرل‪ .‬نخلرل عقردة ورقيرة تحتروي قيمرة‬
‫الحرف او الرمز ‪ ,a‬يدفع في المكدس ‪.s‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.41‬بداية المكدس‪.‬‬

‫‪ .2‬الخطوة الثانية‪ ,‬والثالثة‪ :‬يتم تمييرز الحررفين ‪ b, c‬كمعرامالت‪ ,‬ويرتم تكروين عقرد‬
‫ورقية وتدفع الى المكدس‪.‬‬

‫شك ‪ :8.42‬المكدس ب د اضافة اثنال من الم ام ت‪.‬‬

‫‪ .3‬الخطول الرابعة‪ :‬يرتم تمييرز * كعامرل رياضري‪ ,‬فري هرذل الحالرة اليردفع للمكردس‬
‫النره عامرل رياضري وانمررا نعمرل علرى خلرل عقرردة جديردة علرى ان تكرون قيمتهررا‬
‫الرمرز )*(‪ .‬يرتم سرحب اينران مرن العقرد الموجرودة فري اعلرى المكردس كمرا سربل‬
‫وتعلمنا في فصل المكدس (العقدل ‪ c‬والعقدة ‪ ,) b‬هذل سرتكون االشرجار الثانويرة‬
‫اليمررين واليسررار للعقرردة الجديرردة )*( علررى الترروالي كمررا فرري الشرركل ‪ .8.43‬تررربط‬
‫االشجار الثانوية وتدفع الشجرة الثانوية المتكونة التي جذرها * الى المكدس‪.‬‬

‫شك ‪ :8.43‬المكدس ب د تنفيذ ال ام الرياضي )*(‪.‬‬

‫‪389‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .4‬الخطول الخامسة‪ :‬يتم تمييز الرمز(‪ )+‬كعامل‪ .‬يتم خلل عقدة جديدة تكون قيمتها‬
‫هي (‪ ,)+‬هنا يتم سحب العقدتين الثانويتين من اعلى المكدس وتربطان الى هذل‬
‫العقدة الجديدة يم يعاد دفع العقردة المتكونرة الرى المكردس والتري جرذرها هرو (‪)+‬‬
‫كما في الشكل ‪.8.44‬‬

‫شك ‪ :8.44‬المكدس ب د اضافة ال ام الرياضي )‪.(+‬‬

‫‪ .5‬الخطررول السادسررة‪ :‬عنررد الوصررول الررى اخررر عنصررر فرري التعبيررر‪ ,‬فرران العنصررر‬
‫الوحيد المتبقي في المكدس هو جذر شجرة التعبير‪.‬‬

‫‪ 8.9.1‬ووارزمية بناء شجرة الت بير الرياضي‬


‫‪ .1‬اذا كرران الرمررز هررو معامررل تخلررل شررجرة بعقرردة واحرردة ويرردفع مؤشرررها الررى‬
‫المكدس‪.‬‬
‫‪ .2‬اذا كان الرمز هو عامل رياضي فيعامل هذا الرمز على انه جرذر‪ ,‬يرربط هرذا‬
‫الجذر باينين من الموجودات في اعلرى المكردس سرواء كانرت (عقرد او اشرجار‬
‫فرعية) ويتم تكوين شجرة فرعية جديدة وتعاد الى اعلى المكدس‪.‬‬
‫‪ .3‬اعلى المكردس (عقردة او شرجرة فرعيرة) سريتم سرحبه اوال ويرربط بالجرذر فري‬
‫الجانب االيمرن ليكرون االبرن االيمرن‪ ,‬بينمرا الرذي يليره يرربط بالجرذر علرى انره‬
‫االبن االيسر‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫مثال‪ :‬مطلوب بناء شجرة تعبير للتعبير الرياضي ( ‪)abc*+de*f+g*+‬‬

‫الخطوة االولى‪ :‬العوامل يتم دفعها الرى المكردس‪ ,‬لرذلك يرتم اوال دفرع العامرل )‪(a‬‬
‫الى المكدس‪ ,‬يم دفع العامل )‪ ,(b‬وبعردها يرتم دفرع العامرل )‪ (c‬الرى المكردس كمرا‬
‫في الشكل )‪.(8.45-A‬‬
‫الخطوة الثانيرة‪ :‬االن الردور للعامرل الرياضري )*(‪ ,‬فري هرذل الحالرة سريتم سرحب‬
‫عنصرين من اعلى المكردس ويربطران بواسرطة العامرل الرياضري )*(‪ ,‬يرم يعراد‬
‫الناتج الى اعلى المكدس كما في الشكل )‪.(8.45-B‬‬

‫شك ‪ :8.45‬وضع المكدس ب د اضافة عد من الم ام ت وال ام )*(‪.‬‬

‫الخطوة الثالثة‪ :‬االن جاء دور المعامل )‪ (d‬فيتم دفعه الرى المكردس‪ ,‬يرم يراتي‬
‫دور المعامل )‪ (e‬فيتم ايضا دفعه الى المكدس كما في الشكل ‪.8.46‬‬

‫‪391‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.46‬المكدس ب د اضافة عد من الم ام ت‪.‬‬

‫الخطوة الرابعة‪ :‬في هذل الخطوة سيتم تنفيذ العامرل الرياضري )*( ‪ ,‬ودائمرا العوامرل‬
‫الرياضية تتطلب سرحب اينران مرن المعرامالت فري اعلرى المكردس ويربطران بالعامرل‬
‫الرياضي )*( ‪ ,‬نؤكد علرى ان العنصرر الرذي فري اعلرى المكردس يكرون االبرن االيمرن‬
‫للجذر بينما الذي يليه يكون االبن االيسر للجذر‪ ,‬بعد انجاز الربط يعاد فررع الشرجرة‬
‫المتولدة الى المكدس‪ ,‬بعدها ياتي دور المعامل )‪ (f‬والذي يدفع الى المكدس مباشررة‪,‬‬
‫كما في الشكل ‪ .8.47-A‬يم ياتي دور العامل (‪ )+‬والمعامل )‪ (g‬شكل ‪.8.47-B‬‬

‫شك ‪ :8.47‬المكدس ب د عد من عمليات االضافة‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫تستمر العملية لحين اكمال جميع عناصر التعبير الرياضي وبذلك سيكون الناتج مرن‬
‫هذل العملية في المكدس وهو عبارة عن شجرة تعبير كما في الشكل ‪.8.48-B‬‬

‫شك ‪ .A 8.48:‬المكدس ب د عد من االضافات‪ .B .‬المكدس ب د اكمال ميع عناصر الت بير‬


‫الرياضي‪.‬‬

‫مثال‪ :‬الشكل ‪ 8.49‬هو شجرة تمثل التعبير الرياضي‬


‫)‪3 * ( 7 + 1) / 4 + ( 17 – 5‬‬

‫االسهم الحمراء توضح كيفية حساب قيم التعبير بطريقة الترتيب االعتيادي‪.‬‬

‫‪393‬‬
C++ ‫هياكل البيانات باستخدام‬

.‫ شك توضيحي لبريقة قراءة شجرة ت بير‬:8.49 ‫شك‬

‫ برنام لتنفيذ ال مليات علل شجرة الت بير‬8.9.2

#include <iostream.h>
#include <conio.h>

struct node {
char data;
node *left;
node *right;
};

char postfix[35];
int top=-1;
node *arr[35];

int r (char inputchar){ //‫لفحص الرمز اذا كان معامل او عامل رياضي‬
if (inputchar = = '+' || inputchar = = '-' || inputchar = = '*' || inputchar =
= '/')
return (-1);
C++ ‫هياكل البيانات باستخدام‬

else if (inputchar>= 'a' || inputchar <= 'z')


return(1);
elseif(inputchar>= 'A' || inputchar <= 'Z')
return(1);
elsereturn(-99); // ‫في حالة الخطأ‬
}

//‫تستخدم الضافة عنصر مفرد الى المصفوفة‬


void push(node *tree){
top++;
arr[top]=tree;
}

node *pop(){
top--;
return(arr[top+1]);
}

void create_expr_tree(char *suffix){


char symbol;
node *newl,*ptr1,*ptr2;

int flag; // ‫) عندما يكون معامل‬1( ‫) عندما يكون عامل و‬1-( ‫مؤشر تكون قيمته‬

symbol = suffix[0]; // ‫قراءة الرمز االول من الترتيب البعدي‬

expr.for(int i=1;symbol!=NULL;i++){ // ‫االستمرار لغاية نهاية التعبير‬

flag= r (symbol); // ‫فحص الرمز اذا كان عامل او معامل‬

if (flag == 1)// ‫اذا الرمز معامل‬


{
newl = new node;
newl->data = symbol;
newl->left = NULL;
newl->right = NULL;
push(newl);
}
else{ // ‫اذا الرمز عامل سحب اثنين من المعامالت‬

395
C++ ‫هياكل البيانات باستخدام‬

ptr1=pop();
ptr2=pop();
newl = new node;
newl->data = symbol;
newl->left = ptr2;
newl->right = ptr1;
push(newl);
}
symbol=suffix[i];
}
}

void preOrder(node *tree){


if ( tree!=NULL){
cout<<tree->data;
preOrder(tree->left);
preOrder(tree->right);
}
}

void inOrder(node *tree){


if ( tree!=NULL){
inOrder( tree->left);
cout<< tree->data;
inOrder(tree->right);
}
}

void postOrder(node *tree){


if ( tree!=NULL){
postOrder( tree->left);
postOrder( tree->right);
cout<<tree->data;
}
}

void main(){
‫هياكل البيانات باستخدام ‪C++‬‬

‫;)(‪clrscr‬‬
‫;"‪cout<<"*****Expression Tree*****\n‬‬
‫;" ‪cout<<"Enter Postfix Expression :‬‬
‫;‪cin>>postfix‬‬

‫خلق شجرة تعبير رياضي ‪//‬‬


‫;)‪create_expr_tree(postfix‬‬

‫عملية المرور على شجرة التعبير ‪//‬‬


‫;" ‪cout<<"\n In-Order Traversal :‬‬
‫;)]‪inOrder(arr[0‬‬

‫;" ‪cout<<"\n Pre-Order Traversal :‬‬


‫;)]‪preOrder(arr[0‬‬

‫;" ‪cout<<"\n Post-Order Traversal :‬‬


‫;)]‪postOrder(arr[0‬‬
‫;)(‪getch‬‬
‫}‬

‫‪ 8.10‬تمثي االشجار الثنائية ‪Binary Tree Representations‬‬


‫االشجار الثنائية في هياكل البيانات تمثل بطريقتين‪ .‬هذل الطرق هي‪:‬‬
‫‪ ‬التمثيل على شكل مصفوفات‪.‬‬
‫‪ ‬التمثيل على شكل قوائم موصولة‪.‬‬

‫تمثي الشجرة الثنائية علل شك مصفوفة‪.‬‬ ‫‪8.10.1‬‬

‫في التمثيل على شكل مصفوفة فاننا سنستخدم مصفوفة احاديرة البعرد لتمثيرل الشرجرة‬
‫الثنائية‪.‬‬
‫السررؤال االن كيررف مررن الممكررن تمثيررل الشررجرة الثنائيررة باسررتخدام المصررفوفات؟ ف ري‬
‫الحقيقة‪ ,‬هنا عدد من الطرق لعمل ذلك‪ ,‬سوف نناقش واحدة منها‪.‬‬

‫‪397‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫االشررجار الثنائيررة مررن الممكررن ان تخررزن بمصررفوفة احاديررة فرري الررذاكرة وفقررا للقواعررد‬
‫التالية‪:‬‬
‫‪ .1‬قيم االشجار الثنائية تخزن في المصفوفة وتسمى المصفوفة شجرة )‪.(tree‬‬
‫‪ .2‬جرررذر الشرررجرة يخرررزن فررري الموقرررع االول للمصرررفوفة (أي فررري الموقرررع ‪,0‬‬
‫]‪.) tree[0‬‬
‫‪ .3‬االبن االيسر للشجرة يخزن في الموقع )‪ ,(2i + 1‬بينما يخزن االبن االيمرن‬
‫فري الموقرع )‪ i( (2i + 2‬يمثرل الررقم التسلسرلي ‪ index‬او موقرع االب فري‬
‫المصفوفة)‪ ,‬الح الشكل ‪.8.50‬‬
‫‪ .4‬ان اكبررر حجررم لمصررفوفة الشررجرة هررو )‪ ,(2d+1 -1‬حيررث ان ‪ d‬يمثررل عمررل‬
‫الشجرة‪.‬‬
‫‪ .5‬الشررجرة الخاليررة او فرررع الشررجرة الخررالي يحرردد بالقيمررة ‪ .null‬فرراذا كانررت‬
‫الشجرة ‪ tree [0] = null‬فان هذا يعني ان الشجرة خالية‪.‬‬
‫‪ .6‬الحر ان الشررجرة الترري لهررا )‪ (N‬مررن العقررد لرريس دائمررا تشررغل اول )‪ (N‬مررن‬
‫مواقع المصفوفة‪ ,‬كما في الشكل ‪.8.51‬‬
‫‪ .7‬اذا كان موقع االبن في المصفوفة هو )‪ (i‬فان موقع االب في المصرفوفة يرتم‬
‫حسابة باستخدام العالقة ) ‪ ( (i – 1) / 2‬مع مالحظرة اهمرال الكسرر النراتج‬
‫من القسمة‪.‬‬
‫من فوائد هرذل الطريقرة الخطيرة هرو سرهولة الوصرول الرى عناصرر الشرجرة وسرهولة‬
‫المررور علررى عناصررر الشررجرة‪ ,‬كررذلك الكفراءة باسررتخدام المسرراحة الخزنيررة اذا كانررت‬
‫الشجرة كاملة‪ .‬بالمقابرل فران مرن مسراو اسرتخدام هرذل الطريقرة هرو عردم االسرتخدام‬
‫الكفوء للمساحة الخزنية خصوصا اذا لم تكن الشجرة كاملة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :8.50‬شجرة ثنائية محد عليها ارقا المواقع لك عقدة في المصفوفة‪.‬‬

‫شك ‪ :8.51‬شجرة منحرفة يمينا يتم وزنها في مصفوفةب الحظ عد وزل قيمها بمواقع‬
‫متجاورة من بداية المصفوفة‪.‬‬

‫التمثي علل شك قوائم موصولة‪.‬‬ ‫‪8.10.2‬‬

‫في هرذل الحالرة يرتم اسرتخدام قروائم موصرولة ينائيرة )‪ (double linked list‬لتمثيرل‬
‫الشرررجرة الثنائيرررة‪ .‬فررري القررروائم الموصرررولة الثنائيرررة وكمرررا عرفنرررا فررري فصرررل القررروائم‬
‫ا لموصولة فان كل عقدة تتكون من يالث حقول‪ .‬الحقل االول يخزن به عنوان االبرن‬

‫‪399‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫االيسررر‪ ,‬الحقررل الثرراني يخررزن برره البيانررات الحقيقيررة والحقررل الثالررث يخررزن برره عنرروان‬
‫االبن االيمن‪.‬‬
‫في هذا التمثيل فان العقدة سيكون لها الهيكل التالي‬

‫عملية تمثيل الشجرة على شكل قوائم موصولة موضحة بالشكل ‪.8.52‬‬

‫شك ‪ :8.52‬تمثي الشجرة ببريقة القوائم الموصولة‬

‫‪ 8.10.3‬شفرة برنام لتنفيذ طريقة المصفوفات مع االشجار الثنائية‪.‬‬

‫البرنامج ي نفيذ اشجار البحث الثنائي بطرقة المصفوفات مع اجراء عدد من عمليرات‬
‫المرور التي تجرى على االشجار‪.‬‬
C++ ‫هياكل البيانات باستخدام‬

‫ اليحبذ استخدام المصفوفات مرع اشرجار البحرث الثنرائي وذلرك النهرا تحتراج‬: ‫م حظة‬
‫ يفضل استخدام القوائم الموصولة والتي سبل وان ترم كتابرة‬.‫الى مساحة ذاكرة كبيرة‬
.‫شفرتها خالل هذا الفصل‬

#include<iostream>
using namespace std;
public:
int size;
int* array;

void insertElement(int x);


void searchElement(int x);
void inOrder(int currentIndex);
void preOrder(int currentIndex);
void postOrder(int currentIndex);
void parent(int x);
int extendSize(int x);

BinarySearchTree (int size) {


this -> size = extendSize(size);
cout << this -> size << endl;
this -> array = new int[this -> size];
for (int x = 0; x < this -> size; x++){
array[x] = NULL;
}
}

401
C++ ‫هياكل البيانات باستخدام‬

};

int BinarySearchTree::extendSize(int x) {
int value = 0;
for (int y = 0; y < x + 1; y++) {
value = (2 * value) + 2;
}
return value;
}

void BinarySearchTree::insertElement(int x) {
int currentIndex = 0;
cout << "Adding: " << x;
while(true) {
if(array[currentIndex] == NULL){
array[currentIndex] = x;
cout << " Inserted at index: " << currentIndex << endl;
break;
}else if(array[currentIndex] <= x) {
if (array[currentIndex] == x){
cout << "ERROR!-- Repeating element" << endl;
break;
}else
cout << " Right ";
currentIndex = (2 * currentIndex + 2);
}else if(array[currentIndex] >= x) {
C++ ‫هياكل البيانات باستخدام‬

if (array[currentIndex] == x){
cout << "ERROR!-- Repeating element" << endl;
break;
}else
cout << " Left ";
currentIndex = (2 * currentIndex + 1);
}

}
}

void BinarySearchTree::searchElement(int x){


int currentIndex = 0;
while (true) {
if (array[currentIndex] == NULL) {
1. cout << "Not Found" << endl;
break;
}
if (array[currentIndex] == x) {
cout << "Found at index: " << currentIndex << endl;
break;
}
else if(array[currentIndex] < x) {
currentIndex = (2 * currentIndex + 2);
}
else if(array[currentIndex] > x) {
currentIndex = (2 * currentIndex + 1);

403
C++ ‫هياكل البيانات باستخدام‬

void BinarySearchTree::parent(int x){


while (x != 0) {
x = (x-1) / 2;
cout << "---";
}

void BinarySearchTree::inOrder(int currentIndex){


if (array[currentIndex] != NULL) {
inOrder(2 * currentIndex + 1);
parent(currentIndex);
cout << array[currentIndex] << endl;
inOrder(2 * currentIndex + 2);

}
}

void BinarySearchTree::postOrder(int currentIndex) {


if (array[currentIndex] != NULL){
C++ ‫هياكل البيانات باستخدام‬

postOrder(2 * currentIndex + 1);


postOrder(2 * currentIndex + 2);
parent(currentIndex);
cout << array[currentIndex] << " " << endl;
}

void BinarySearchTree::preOrder(int currentIndex) {


if (array[currentIndex] != NULL) {
preOrder(2 * currentIndex + 1);
parent(currentIndex);
cout << array[currentIndex] << " " << endl;
preOrder(2 * currentIndex + 2);
}
}

int main () {
BinarySearchTree frank(5);
frank.insertElement(4);
frank.insertElement(6);
frank.insertElement(9);
frank.insertElement(3);
frank.insertElement(2);
frank.searchElement(1);
frank.inOrder(0);
};

405
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص التاسع‬
‫تكديس هياك البيانات‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪HEAP DATA STRUCTURE‬‬

‫‪ 9.1‬المقدمة‬
‫تطرقنا في الفصرل السرابل الرى االشرجار الثنائيرة بشركل عرام‪ ,‬واالشرجار الثنائيرة مرن‬
‫الممكررن ان تكررون بياناتهررا مرتبررة او ال تكررون مرتبررة‪ ,‬عنرردما تكررون بيانررات االشررجار‬
‫الثنائية مرتبة فان ذلك يدعى التكديس )‪ .(Heap‬وبرالرغم مرن ان التكرديس هرو لريس‬
‫مرتب بشكل كامل‪ ,‬اال انه يتوافل مرع مبراديء الترتيرب‪ .‬والتكرديس عرادة هرو شرجرة‬
‫كاملة مرتبة البيانات‪.‬‬

‫‪ 9.2‬ت ريف التكديس ‪Heap‬‬


‫تكديس هياكل بيانات هي شجرة ينائية مع الخواص التالية‪:‬‬
‫‪ .1‬ان تكون شجرة ينائية كاملرة (يعنري كرل مسرتوى يكرون مملروء بالعقرد ماعردا‬
‫المسررتوى االسررفل احتمررال ان ال يكررون مملرروء وبهررذل الحالررة يررتم مررأل هررذا‬
‫المستوى من اليسار الى اليمين)‪.‬‬
‫‪ .2‬ان تكون القريم مرتبرة ترتيرب تصراعدي او تنرازلي (اي ان تكرون القريم التري‬
‫تخزن فري العقرد مرتبرة بحيرث تكرون قيمرة عقردة االب اكبرر او تسراوي قيمرة‬
‫االبرن وهكرذا لجميررع العقرد (هررذا فري الترتيرب التنررازلي‪ ,‬الترتيرب التصرراعدي‬
‫بالعكس))‪.‬‬

‫‪407‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :9.1‬اشجار ثنائية مالتلفة )‪ (A‬فقط هي تكديس‪.‬‬

‫في الشكل ‪ 9.1‬فقط ‪ A‬هو تكديس‪ .‬بينما ‪ B‬هو ليس تكديس بسبب كونه غير كامل‪,‬‬
‫وكذلك فان ‪ C‬هو ليس تكرديس برالرغم مرن انره كامرل ولكرن اليحقرل الشررط الثراني‬
‫حيث ان القيم غير مرتبة‪.‬‬
‫التكديس هي حالة خاصة من االشجار الثنائية الموزونة‪ ,‬حيث ان عقدة الجذر تقارن‬
‫مع ابنائها وتنظم او ترتيب وفقا لذلك‪ .‬هنا نوعان من التكديس‪.‬‬
‫‪ .1‬التكديس االصغر ‪Min-Heap‬‬
‫وهو التكديس الذي تكون فيه قيمة الجذر اصغر من او تساوي قيم ابناءل‪.‬‬
‫فلو فرضنا لدينا المدخالت التالية‪ ,‬فسيكون تمثيله كما في الشكل ‪.9.2‬‬
‫)‪(35, 33, 42, 10, 14, 19, 27, 44, 26, 31‬‬

‫شك ‪ :9.2‬تمثي القيم علل شك تكديس اصغر‪.‬‬

‫‪ .2‬التكديس االكبر ‪Max-Heap‬‬


‫حيث ان قيمة عقدة الجذر اكبر من او تساوي قيم عقرد االبنراء‪ .‬اذا اسرتخدمنا‬
‫ذات المدخالت في مثال التكديس االصغر فان الناتج هو الشكل ‪.9.3‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :9.3‬تمثي البيانات علل شك تكديس اكبر‬

‫‪ 9.3‬ووارزمية انشاء التكديس االكبر‬


‫بداية البد ان نشير الى اننا سنستخدم نفس المثال الذي استخدم اعرالل لتوضريح خلرل‬
‫التكديس االكبر‪ .‬كرذلك البرد مرن االشرارة الرى ان خوارزميرة التكرديس االصرغر هري‬
‫تتبررع ذات الخطرروات فرري التكررديس االكبررر باسررتثناء ان المقارنررة سررتكون مررع القرريم‬
‫االصغر وليس القيم االكبر‪.‬‬
‫سنشتل خوارزمية التكديس االكبر بحشر عنصر واحرد فري كرل مررة‪ .‬فري اي وقرت‪,‬‬
‫فان التكديس يجب ان يحاف على خصائصه‪.‬‬

‫‪ ‬ووارزمية التكديس‬
‫‪ .1‬خلل عقدة جديدة‪ ,‬توضع في نهاية التكديس (تكون متصلة مع اخر عقدة في‬
‫الشجرة)‪.‬‬
‫‪ .2‬اسناد قيمة جديدة لهذل العقدة‪.‬‬
‫‪ .3‬تقارن قيمة هذل العقدة مع قيمة االب لها‪.‬‬
‫‪ .4‬اذا كانت قيمة العقدة الجديدة اكبرر مرن قيمرة العقردة االب‪ ,‬ترتم عمليرة االبردال‬
‫بينهما‪.‬‬
‫‪ .5‬تعراد الخطروات )‪ (3, 4‬لحرين ان يرتم ضربط مواصرفات التكرديس (اي تكرون‬
‫قيمة االب اكبر او تساوي من قيمة االبناء)‪.‬‬

‫‪409‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ ‬دعنا نوضح هذل الخوارزمية من خالل مثال وباستخدام القيم‬


‫)‪(35, 33, 42, 10, 14, 19, 27, 44, 26, 31‬‬

‫‪ ‬بداية ستكون القيمة االولى (‪ )35‬هي العقدة االولى وتمثل عقدة الجذر‪.‬‬
‫‪ ‬القيمة الثانية هي ‪ 33‬وستكون في نهاية التكرديس‪ ,‬تقرارن قيمتهرا بقيمرة االب‬
‫التي هي االن الجذر )‪ (33≤35‬نالح انهرا اصرغر اذن سرتكون ابرن لعقردة‬
‫الجذر‪.‬‬

‫شك ‪ :9.4‬ربط عقدة ديدة لشجرة التكديس‪.‬‬

‫‪ ‬القيمررة االخرررى هرري (‪ )42‬وهرري سررتكون االبررن الثرراني (الشررجرة موزونررة)‬


‫وتربط مع الجذر‪ ,‬تقرارن قيمتهرا مرع الجرذر الرذي هرو اب لهرا )‪,(42 ≤ 35‬‬
‫هنا القيمة ‪ 42‬اكبر‪ ,‬لذلك يجب ان ترتم عمليرة التبرديل برين االب واالبرن كمرا‬
‫في الشكل‪.9.5‬‬

‫شك ‪ :9.5‬اضافة عقدة وتبدي ‪.‬‬

‫‪ ‬القيمررة االخرررى فرري المجموعررة هرري ‪ 10‬وهرري سررتكون فرري اسررفل التكررديس‬
‫(الشجرة) وتكون العقدة (‪ )33‬اب لها‪ ,‬تقارن القيمتين )‪ (10 ≤ 33‬ونالحر‬
‫ان ‪ 33‬اكبر منها‪ .‬لذا ستكون العقدة ‪ 33‬اب للعقدة ‪.10‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :9.6‬اضافة عقدة ديدة‪.‬‬

‫‪ ‬القيمة (‪ )14‬وسيكون موقعها هو االبن الثاني للعقدة (‪ .)33‬تقرارن مرع قيمرة‬


‫االب لها‪ (14 ≤ 33) ,‬لذا ال يوجد تبديل‪ ,‬وتعتبر االبن الثاني للعقدة (‪.)33‬‬

‫شك ‪ :9.7‬اضافة عقدة ديدة‪.‬‬

‫‪ ‬نستمر بقراءة قيم المجموعة والقيمة (‪ )19‬وستكون ابن للعقدة (‪ ,)35‬تقارن‬


‫القيمتان )‪ (19 ≤ 35‬ونظرا الى ان قيمة العقدة (‪ )35‬اكبر من القيمرة (‪)19‬‬
‫لذا ال يوجد تبديل وتكون العقدة (‪ )19‬ابن للعقدة (‪.)35‬‬

‫‪411‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :9.8‬اضافة عقدة ديدة‪.‬‬

‫‪ ‬القيمة التالية في المجموعة (‪ )27‬وستكون االبن الثراني للعقردة (‪( )35‬دائمرا‬


‫اضررافة العقررد يسررتمر مررن اليسررار الررى اليمررين النهررا شررجرة كاملررة)‪ ,‬تقررارن‬
‫القيمتان )‪ ,(27 ≤ 35‬نعم نتيجة المقارنة هو ان (‪ )35‬اكبر من (‪ )27‬لذا ال‬
‫يوجد تبديل وتربط العقدة (‪ )27‬بالعقدة (‪ )35‬لتكون االبن الثاني لها‪.‬‬

‫شك ‪ :9.9‬اضافة عقدة ديدة‪.‬‬

‫‪ ‬القيمة التالية (‪ )44‬وهي ستكون ابن العقدة (‪ ,)10‬تقارن القيمة المضافة مع‬
‫قيمة االب )‪ ,(44 ≤ 10‬في هذل الحالة فان ‪ 10‬اصغر مرن ‪ 44‬لرذا البرد مرن‬
‫التبديل‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :9.10‬اضافة عقدة وا راء التبدي بين االبن واالب‪.‬‬

‫‪ ‬بعد اجراء التبديل يالح ان القيمرة (‪ )44‬اصربحت ابنرا للعقردة (‪ )33‬وعليره‬


‫تقارن القيم (االبن (‪ )44‬مع االب الجديرد) للمحافظرة علرى صرفات التكرديس‬
‫)‪ (44 ≤ 33‬ايضا هنا ان القيمة (‪ )44‬هي اكبرر مرن القيمرة (‪ ,)33‬لرذا تبردل‬
‫القيمتين‪.‬‬

‫شك ‪ :9.11‬استمرار عملية التبدي ‪.‬‬

‫‪ ‬العقدة (‪ )44‬اصبحت ابنا للعقدة (‪ )42‬لذا تقارن قيمهم )‪ (44 ≤ 42‬ونالح‬


‫ان القيمة (‪ )44‬اكبر من القيمة (‪ )42‬عليه تجرى عملية التبديل‪.‬‬

‫‪413‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :9.12‬التبدي الثالث لكي نحافظ علل مواصفات التكديس‪.‬‬

‫‪ ‬بعررد اتمررام عمليررات االبرردال يررتم قررراءة القيمررة االخرررى مررن مجموعررة قرريم‬
‫المدخالت وهي القيمة (‪ ,)26‬ستكون هذل القيمرة االبرن الثراني للعقردة (‪,)33‬‬
‫تقارن هذل القيم )‪ (26 ≤ 33‬وهنا القيمرة (‪ )26‬اصرغر مرن القيمرة (‪ )33‬لرذا‬
‫ال يوجد تبديل‪.‬‬

‫شك ‪ :9.13‬اضافة عقدة ديدة‪.‬‬

‫‪ ‬القيمررة االخيرررة وهرري القيمررة (‪ )31‬والترري سررتكون ابنررا للعقرردة (‪ )14‬وتررتم‬


‫المقارنرة )‪ (31 ≤ 14‬ونظررا الرى ان القيمرة (‪ )31‬اكبرر مرن (‪ )14‬لرذا ترتم‬
‫عملية التبديل بينهما‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :9.14‬اضافة عقدة ديدة وا راء التبدي مع االب‪.‬‬

‫‪ ‬بعد التبديل ستكون العقدة (‪ )31‬ابنا للعقدة (‪ )42‬واذا ما قارنا القيمتين سنجد‬
‫ان العقرردة (‪ )31‬اصررغر مررن العقرردة (‪ )42‬لررذا اليوجررد تبررديل‪ .‬بهررذا نكررون ق رد‬
‫خلقنا شجرة التكديس‪.‬‬

‫‪ 9.4‬الحذذ من شجرة التكديس‬


‫ان عملية الحذف سواء كان التكديس االكبر او التكديس االصرغر يرتم بحرذف الجرذر‪.‬‬
‫وذلك الزالة القيمة االكبر او القيمة االصغر‪.‬‬
‫‪ ‬ووارزمية الحذذ‬

‫حذف عقدة الجذر‪.‬‬ ‫‪.1‬‬


‫تحريررك العنصررر االخيررر فرري المسررتوى االدنررى الررى الجررذر (بمعنررى سررتكون‬ ‫‪.2‬‬
‫القيمة االقل هي الجذر في حالة التكديس االكبر وبالعكس في حالرة التكرديس‬
‫االصغر)‪.‬‬
‫مقارنة قيمة عقدة الجذر الجديدة مع قيمة ابنهرا (دائمرا تبردا المقارنرة اوال مرع‬ ‫‪.3‬‬
‫االبن االيسر يم االبن االيمن)‪.‬‬
‫اذا كانررت القرريم غيررر متوافقررة وفقررا لنرروع التكررديس فتررتم عمليررة التبررديل (فرري‬ ‫‪.4‬‬
‫التكديس االكبر اذا كان االبن اكبر من االب تتم التبديل وبالعكس لالصغر)‪.‬‬
‫اعرررادة الخطررروات )‪ (3, 4‬لحرررين ان توليرررد شرررجرة تكرررديس محافظرررة علرررى‬ ‫‪.5‬‬
‫خواصها‪.‬‬

‫‪415‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ ‬مثةةال علررى تطبيررل خوارزميررة الحررذف علررى التكررديس الررذي تررم انشررا ل سررابقا‪.‬‬
‫موضح في الشكل ‪.9.15‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :9.15‬توضيح عملية الحذذ‪.‬‬

‫‪ 9.5‬تمثي التكديس‬
‫من الممكن تنفيذ التكديس باستخدام القوائم الموصولة كما فعلنا مع االشجار الثنائيرة‪,‬‬
‫ولكن من المفضل واالسهل تنفيذ التكديس باستخدام المصفوفات‪.‬‬
‫لتنفيررذ ذلررك يررتم ترررقيم شررجرة التكررديس مررن االعلررى لالسررفل ابتررداءا مررن الجررذر الررذي‬
‫سيكون رقمه صفر ( وذلك الن المصفوفات في ‪ C++‬تبردأ بصرفر)‪ ,‬تررقم العقرد فري‬
‫كل مستوى من اليسار الى اليمرين‪ .‬بعرد التررقيم تخرزن كرل عقردة فري الموقرع المقابرل‬
‫للرقم الذي وضع على العقدة‪ ,‬حيث تخرزن العقردة ‪ i‬فري الموقرع ‪ i‬مرن المصرفوفة‪ .‬ان‬
‫حجم المصفوفة سيكون بقدر عدد العقد في التكديس‪.‬‬

‫‪ ‬مثال لنالح التكديس في الشكل ‪ 9.16‬وكيفية تمثيله في المصفوفة‪.‬‬

‫‪417‬‬
C++ ‫هياكل البيانات باستخدام‬

.‫ تمثي التكديس علل شك مصفوفة‬:9.16 ‫شك‬

.‫ برنام لتمثي التكديس مع ال مليات التي تجرى عليه‬9.5.1

#include <stdio>

using namespace std;

int array[100], n ;

main() {

int choice, num ;


n = 0 ; /* ‫*تمثل عدد العقد في التكديس‬/
while (1)
{

cout<< "1.Insert the element \n" ;


cout<< "2.Delete the element \n" ;
cout<< "3.Display all elements \n" ;
cout<< "4.Quit \n" ;
cout<< "Enter your choice : " ;

cin>> choice ;
C++ ‫هياكل البيانات باستخدام‬

switch (choice)
{
case 1:
cout<< "Enter the element to be inserted to the list : " ;
cin>> num ;
insert (num, n) ;
n = n + 1;
break;
case 2:
cout<< "Enter the elements to be deleted from the list: " ;
cin>> num ;
delete (num);
break;
case 3:
display();
break;
case 4:
exit(0);
default:
cout<< "Invalid choice \n" ;
} /* switch ‫*نهاية‬/
} /* while ‫*نهاية‬/
} /* main() ‫*نهاية‬/

display()
{
int i;
if (n == 0)
{
cout<< "Heap is empty \n" ;
return;
}
for (i = 0; i < n; i++)
cout<< array[i] << endl ;
} /* display() ‫*نهاية‬/

insert (int num, int location)


{
int parentnode;
while (location > 0)

419
C++ ‫هياكل البيانات باستخدام‬

{
parentnode =(location - 1)/2;
if (num <= array[parentnode])
{
array[location] = num;
return;
}
array [location] = array[parentnode];
location = parentnode;
} /* while ‫*نهاية‬/

array [0] = num; /* ‫* اسناد رقم الى عقدة الجذر‬/

} /* insert() ‫*نهاية‬/

delete(int num)
{
int left, right, i, temp, parentnode;

for (i = 0; i < num; i++) {


if (num = = array[i])
break;
}
if (num != array[i])
{
cout<< " not found in heap list\n" << num ;
return;
}
array [i] = array[n - 1];
n = n - 1;
parentnode = (i - 1) / 2; /* i ‫*ايجاد اب العقدة‬/
if (array [i] > array [parentnode])
{
insert (array[i], i);
return;
}

left = 2 * i + 1; /* i ‫*االبن االيسر للعقدة‬/


C++ ‫هياكل البيانات باستخدام‬

right = 2 * i + 2; /* i ‫*االبن االيمن للعقدة‬/


while (right < n)
{
if (array[i] >= array[left] && array[i] >= array[right])
return;
if (array[right] <= array[left])
{
temp = array[i];
array [i] = array[left];
array [left] = temp;
i = left;
}
else
{
temp = array[i];
array [i] = array[right];
array [right] = temp;
i = right;
}
left = 2 * i + 1;
right = 2 * i + 2;
}/* while ‫*نهاية‬/

if (left == n - 1 && array[i]) {


temp = array[i];
array[i] = array[left];
array[left] = temp;
}
}

421
‫هياكل البيانات باستخدام ‪C++‬‬

‫الفص ال اشر‬
‫المالببات ‪GRAPHS‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 10.1‬المقدمة‬
‫في عالم الرياضيات وعلوم الحاسروب‪ ,‬نظريرة المخططرات هري دراسرة المخططرات‬
‫التي تتعامل مع العالقة بين الروابط والر وس (العقد)‪.‬‬
‫االشجار الثنائية توفر طرق مفيدة جردا لتمثيرل العالقرات عنردما يكرون التنظريم تنظريم‬
‫هرمي‪ ,‬حيث ان العقدة يشار اليها بعقدة واحدة هي االب وكل عقردة تشرير الرى اينرين‬
‫مررن العقررد كحررد اعلررى (فرري حررال االشررجار الثنائيررة) كمررا سرربل وشرررحنا فرري فصررل‬
‫االشجار‪ .‬اذا تم ازالة الشرط الخاص بان يكون لكل عقدة اينان من االبنراء‪ ,‬فسريكون‬
‫لنا شجرة عامة كما في الشكل ‪.10.1‬‬

‫شك ‪ :10.1‬شجرة عامة‪.‬‬

‫ايضا اذا تم ازالة الشرط الخاص بان يكون لكل عقردة اب واحرد فسريكون لردينا شركل‬
‫يسمى مخطط ‪.graph‬‬

‫‪ 10.2‬ماهو المالبط ‪Graph‬‬


‫هرو تمثيررل رسرومي لمجموعررة مررن الكيانرات‪ ,‬حيررث ان بعرض االزواج مررن الكيانررات‬
‫ترررتبط بررروابط‪ .‬الكيانررات المترابطررة مررن الممكررن تمثيلهررا بنقرراط (ولكرري تكررون اكثررر‬
‫وضوحا تمثل بدوائر)‪ ,‬وخطوط تربط هذل النقاط‪.‬‬

‫‪423‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ 10.3‬تببيقات نظرية المالببات‬


‫نظرية المخططات لها تطبيقات بحقول مختلفة من الهندسة‪:‬‬

‫‪ ‬الهندسررة الكهربائيررة‪ ..‬مفرراهيم نظريررة المخططررات تسررتخدم بشرركل واسررع فرري‬


‫تصميم الدوائر الكهربائية‪.‬‬
‫‪ ‬علوم الحاسبات‪ ..‬تستخدم نظرية المخططات لدراسة الخوارزميات‪ .‬مثال‬
‫‪o Kruskal's Algorithm‬‬
‫‪o Prim's Algorithm‬‬
‫‪o Dijkstra's Algorithm‬‬

‫شبكات الحاسوب‪ ..‬العالقة بين الحواسيب المترابطرة مرع بعرض فري الشربكة‬ ‫‪‬‬
‫تتبع مبدأ نظرية المخططات‪.‬‬
‫العلوم‪ ..‬هيكل الجزي ات والهيكل الكيميائي للمواد‪ ,‬هيكرل ‪ DNA‬كلهرا تمثرل‬ ‫‪‬‬
‫بالمخططات‪.‬‬
‫اللغات‪ ..‬شجرة التعبير للغة وقواعد اللغة تستخدم المخططات‪.‬‬ ‫‪‬‬
‫امور عامة‪ ..‬الطرق ‪ Routes‬بين المدن مرن الممكرن تمثيلهرا بالمخططرات‪.‬‬ ‫‪‬‬
‫بالرغم من الترتيب الهرمي فان المعلومات مثل شجرة العائلرة مرن الممكرن‬
‫ان تستخدم كنوع خاص من المخططات تدعى االشجار‪.‬‬

‫‪ 10.4‬مصبلحات المالببات‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫النقبة ‪ :Point‬هي موقع خاص فري فضراء يتكرون مرن بعردين او يرالث ابعراد‪ .‬لكري‬
‫نفهمهررا اكثررر ف ران النقطررة تمثررل باحررد حررروف الهجرراء‪ .‬مررن الممكررن تمثيلهررا كمررا ف ري‬
‫الشكل ‪.10.2‬‬

‫شك ‪ :10.2‬تمثي نقبة في المالبط‬

‫الالط ‪ :Line‬هو الرابط بين نقطتين‪ .‬وهو يمثل كما في الشكل ‪10.3 .‬‬

‫شك ‪ :10.3‬وط يربط النقبتين )‪.(a, b‬‬

‫الراس او ال قدة ‪ :Vertex‬هي النقطة التري تكرون ملتقرى لعردد مرن الخطروط‪ .‬وهري‬
‫تسررمى عقرردة‪ .‬وكمررا فرري النقرراط فرران هررذل العقررد تمثررل بررالحروف الهجائيررة‪ .‬كمررا فرري‬
‫الشكل ‪.10.2‬‬
‫الحواذ ‪ :Edge‬الحواف هو مصطلح رياضي للخط الرابط بين راسين (عقردتين)‪.‬‬
‫العديرد مرن الحرواف التري مرن الممكرن ان نرسرمها او نخلقهرا مرن عقردة مفرردة‪ .‬بردون‬
‫العقد فان الحواف ال يمكن خلقها‪ .‬يجب ان يكون هنا عقدة بداية وعقردة نهايرة‪ .‬هرذل‬
‫الحواف سنسميها روابط لكي تكون اكثر وضوحا‪ .‬كما في الشكل ‪.10.3‬‬
‫مما تقدم من الممكن تعريف المخطط على انه عبارة عرن مجموعرة مرن العقرد تردعى‬
‫ر وس ومجموعة من الخطوط التي تربط كل اينين من الر وس تدعى روابط‪.‬‬
‫المخطط يحتوي على االقل رابط واحد يربط مجموعة من العقرد تتكرون مرن عقردتين‬
‫دون ان تكون هنا عقدة ترتبط بنفسها‪.‬‬
‫)‪G = (V, E‬‬ ‫يمثل المخطط رياضيا‬
‫حيث ان‬
‫) ‪ ( V‬تمثل مجموعة العقد‪.‬‬

‫‪425‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫) ‪ ( E‬مجموعة من الروابط التي تربط العقد‪.‬‬


‫)‪ e = (u, v‬هو الرابط بين اينان من العقد‪.‬‬
‫في الشكل ‪ ,10.4‬فان‬
‫}‪V= {a,b,c,d,e‬‬
‫})‪E= {(a,b),(a,c),(a,d), (b,e),(c,d),(c,e),(d,e‬‬

‫شك ‪ :10.4‬مالبط يتكول من ومس عقد‪.‬‬

‫المخططات من الممكن ان تكون متجهرة او غيرر متجهرة‪ ,‬فري االشركال المتجهرة فران‬
‫كل خط والذي يسمى قوس ‪ Arc‬يكون له اتجال يمثل كيفيرة المررور او االنتقرال‪ ,‬امرا‬
‫غير المتجهة فان لها خطوط تسمى حواف ‪ edge‬ويمكن ان تتنقل بكال االتجاهين‪.‬‬
‫الحلقة ‪ :Loop‬في المخطط فان الرابط الذي يرسم من عقدة الى نفس العقدة‪ ,‬يردعى‬
‫حلقة‪ .‬الشكل ‪ 10.5‬يوضح ذلك‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.5‬يوضح الحلقة في المالبط‪.‬‬

‫في الشكل ‪ 10.5‬نالح ان )‪ (V‬هي عقدة ولها الرابط )‪e = (V, V‬‬

‫‪ ‬ال قد المتجاورة ‪ :Adjacent Vertices‬وهي اينان من العقد بينها رابط‬


‫يربطهما‪.‬‬
‫‪ ‬ر ةةة ال قةةدة )‪ :Degree (of a vertex‬وهرري تمثررل عرردد الررر وس‬
‫المتجاورة في المخطط البسريط‪ .‬هري عردد الرروابط التري تتعلرل بتلرك العقردة‪.‬‬
‫الح الشكل ‪ 10.6‬والذي يحدد درجة كل عقدة (االرقام التري داخرل العقرد)‪.‬‬
‫من الممكرن ان نقرول هري عردد الرروابط التري تررتبط بتلرك العقردة‪ .‬ان درجرة‬
‫العقدة الي عقدة )‪ (v‬هي‬
‫‪deg (v) ≤ n - 1 ∀ v ∈ G‬‬

‫حيث ان )‪ (n‬تمثل عدد العقد في المخطط‪ .‬وهذا يعنري ان اي عقردة بامكانهرا‬


‫ان ترررتبط مررع كررل عقررد المخطررط باسررتثناء نفسررها‪ .‬لررذلك فرران درجررة العقرردة‬
‫تساوي عدد العقد فري المخطرط مطرروح منهرا واحرد الرذي يمثرل العقردة التري‬
‫نحسب لها الدرجة النه ال يمكن ان تعمل ارتباط بنفسها (اذا كان هنا حلقة‬
‫ضمن المخطط فهذا ال يعتبر مخطط بسيط)‪.‬‬
‫درجة العقدة من الممكن ان تحسب لحالتي المخطرط المتجره والمخطرط غيرر‬
‫المتجه‪ .‬في الشكل ‪ 10.6‬تم تحديد الدرجة لكل عقدة في مخطط غير متجه‪.‬‬

‫‪427‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.6‬مالبط غير متجه تم تحديد ر ة ك عقدة عليه‪.‬‬

‫فرري المخططررات المتجرره فرران كررل عقرردة لهررا نرروعين مررن الرردرجات‪ .‬درجررة الرردخول‬
‫)‪ (indegree‬وهرررري تمثررررل عرررردد الررررروابط الترررري ترررردخل الررررى العقرررردة ويرمررررز لهررررا‬
‫))‪ ,(deg+(V‬واالخرى هي درجة الخروج )‪ (outdegree‬وهي تمثل عدد الروابط‬
‫التي تخرج من العقدة ويرمز لها ))‪.(deg-(V‬‬

‫شك ‪ :10.7‬مالبط متجه تم تحديد ‪ .A :‬ر ة الالروج لك عقدة‪ .B .‬ر ة الدوول لك عقدة‪.‬‬

‫عقةةدة م لقةةة ‪ :Pendent Vertex‬العقرردة الترري مقرردار درجتهررا تسرراوي ‪1‬‬ ‫‪.1‬‬
‫تسمى عقدة معلقة‪ ,‬في الشكل ‪ 10.8‬فان كل مرن )‪ (a, b‬لهرا درجرة ‪ ,1‬لرذلك كالهمرا‬
‫يعتبران معلل‪.‬‬

‫شك ‪ :10.8‬عقد ‪pendent‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .2‬ال قدة الم زولةة ‪ :Isolated Vertex‬هري العقردة التري لهرا درجرة تسراوي‬
‫صفر‪ .‬الح الشكل ‪ 10.9‬ان كل واحدة من هذل العقد لها درجة صفر‪ ,‬لذلك‬
‫تدعى معزولة اي ليس لها ارتباط مع اي عقدة اخرى‪.‬‬

‫شك ‪ :10.9‬عقد م زولة‬


‫‪ .3‬ر ةة التةوالي للمالبةط ‪ :Degree Sequence of A Graph‬فري المخطرط‬
‫اذا كانت درجة جميع العقد مرتبة ترتيب تنازلي او ترتيرب تصراعدي‪ ,‬عليره فران‬
‫المتوالية الناتجة تدعى درجة التوالي للمخطط‪ .‬لنالح الشكل ‪.10.10‬‬

‫شك ‪ :10.10‬مالبط يوضح ر ة التوالي‪.‬‬

‫في الشكل ‪ 10.10‬فان العقد }‪ { d, a, b, c, e‬لها درجة توالي هي‪:‬‬


‫}‪.{3, 2, 2, 2, 1‬‬

‫مثال اور‪ :‬الشكل ‪ 10.11‬يحتوي على العقرد }‪ {a, b, c, d, e, f‬والتري لهرا درجرة‬
‫توالي هي }‪{2, 2, 2, 2, 2, 0‬‬

‫‪429‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.11‬مالبط له ر ة توالي‪.‬‬

‫‪ .4‬التجاور ‪ :Adjacency‬التجاور نوعان‪:‬‬


‫‪ ‬العقد المتجاورة‪ :‬في المخططات يقال عن اينان من العقد متجراورة‪ ,‬اذا كران‬
‫هنررا رابررط بررين هرراتين العقرردتين‪ .‬ان تجرراور العقررد يجررب ان يكررون بررربط‬
‫عقدتين برابط مفرد‪.‬‬
‫‪ ‬الرابط المتجاور‪ :‬في المخططات‪ ,‬يقال عن اينين من الرروابط متجراورة‪ ,‬اذا‬
‫كانت هنا عقدة مشتركة بين الررابطين‪ .‬ان تجراور الررابطين يجرب ان يرتم‬
‫بوجود عقدة مفردة مشتركة‪.‬‬
‫في الشكل ‪ 10.12‬فان‬
‫)‪ (a, b‬عقدتان متجاورتان وذلك لوجود رابط مفرد مشتر بينهما وهو )‪.(ab‬‬
‫العقردتين )‪ (a, d‬همرا ايضررا عقردتين متجرراورتين وذلرك لوجررود رابرط مفرررد مشررتر‬
‫بينهم وهو )‪.(ad‬‬
‫الرابطين )‪ (ab, be‬هما رابطين متجاورين وذلك لوجود عقدة مشرتركة بيرنهم وهري‬
‫العقدة )‪.(b‬‬
‫الرابطين )‪ (be, de‬هما رابطين متجاورين وذلك لوجود عقدة مشرتركة بيرنهم وهري‬
‫العقدة )‪.(e‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.12‬مالبط يوضح التجاور بنوعيه‪.‬‬

‫‪ ‬الروابط المتوازية ‪ :Parallel Edges‬في المخططات اذا كان زوج من العقرد‬


‫ترررتبط برراكثر مررن رابررط واحررد‪ ,‬عليرره فرران هررذل الررروابط تسررمى روابررط متوازيررة‪.‬‬
‫الح الشكل ‪ 10.13‬فران العقردتين )‪ (a, b‬همرا عقردتين ترتبطران بررابطين همرا‬
‫)‪ ,(ab, ab‬لذلك يسميان رابطين متوازيين‪.‬‬

‫شك ‪ :10.13‬روابط متوازية‪.‬‬

‫‪ ‬مالبةط مت ةد ‪ :Multi Graph‬المخطرط الرذي يحتروي علرى روابرط متوازيرة‬


‫اضافة الى روابط غير متوازية يسمى مخطط متعدد‪ .‬الح الشكل ‪.10.14‬‬

‫‪431‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.14‬مالبط مت د ‪.‬‬


‫‪ .5‬المسار ‪ :Path‬هي متوالية من العقد بحيث ان العقد المتعاقبة ) ‪ (vi , vi+1‬تكون‬
‫متجاورة‪ .‬الح الشكل ‪.10.15‬‬

‫شك ‪ :10.15‬مالبط موضح عليه المسارات‪.‬‬

‫‪ .6‬المسار البسيط ‪ :Simple Path‬هو المسرار الرذي لريس فيره عقرد مكرررة‪ ,‬كمرا‬
‫في الشكل ‪.10.16‬‬

‫شك ‪ :10.16‬مسار بسيط‬


‫‪ .7‬ائري ‪ :cycle‬مسار بسيط‪ ,‬ماعدا ان العقردة االخيررة هري العقردة االولرى‪ ,‬الحر‬
‫الشكل ‪.10.17‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪:10.17‬مالبط ائري‪.‬‬

‫م حظة‪ :‬الفشل في اي رابط يؤدي الى عدم تررابط النظرام (المخطرط بشركل عرام‬
‫اقل سماح لالخطاء او الفشل) الح الشكل ‪.10.18‬‬

‫شك ‪ :10.18‬مالبط يوضح كيف يؤثر الفش (القبع) ب زل زء كبير من الشبكة‪.‬‬

‫في المقابل فان الشكل الدائري هو اكثر سماح للفشرل او االخطراء‪ ,‬هرو يحتراج عردد‬
‫من الروابط بقدر عدد الر وس او العقد‪ ,‬انظر الشكل ‪.10.19‬‬

‫‪433‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.19‬مالبط ائري يوضح كيف من الممكن تجاوز الفش او القبع‪.‬‬

‫‪ .8‬مالبط فرعي ‪ :Subgraph‬مجموعة جزئية من العقد والروابط تشكل مخطط‬


‫فرعي‪.‬‬
‫‪ .9‬المكةةةةول المتةةةةرابط ‪ :Connected Component‬هرررري اكبررررر عرررردد مررررن‬
‫المخططات الفرعية المترابطة‪ .‬في الشكل ‪ 10.20‬يالث مكونات مترابطة‪.‬‬

‫شك ‪ :10.20‬مكونات متراببة‪.‬‬

‫‪ .1‬مالبط موزول ‪ :Weighted Graph‬هو المخطط الذي يكون فيه كرل رابرط‬
‫يحتوي على قيمة محددة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.21‬مالبط موزول‬

‫‪ .2‬شجرة (حرة) )‪ :Tree (free‬اشكال مترابطة بدون دوائر‪.‬‬


‫‪ .3‬الغابات ‪ :Forest‬تجمع لالشجار‪.‬‬

‫شك ‪ :10.22‬مالبط يوضح مفهو الغابة واالشجار (الحرة)‪.‬‬


‫‪ ‬المالبةةط الكامة ‪ :Complete Graph‬المخطررط الررذي تكررون فيرره كررل ازواج‬
‫العقد متجاورة‪.‬‬
‫لنفرض ان )‪ (n‬يمثل عدد العقد‪ .‬ونفرض ان )‪ (m‬يمثل عدد الروابط‪ .‬عليه فان‬

‫‪435‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫كل )‪ (n‬من العقد سيكون لها )‪ (n-1‬من الروابط‪ .‬لكن نحن نحسب كل رابرط مررتين‬
‫لذلك فان العالقة تكون )‪((n ( n-1) /2‬‬
‫في الشكل ‪ 10.23‬فان عدد العقد هي (‪ )5‬ولذلك فان عدد الروابط ستكون‬
‫‪5 (5 – 1) / 2 = 10‬‬

‫شك ‪ :10.23‬مالبط كام ‪.‬‬

‫عليه‪ ,‬فاذا لم يكن المخطط كامل فان عدد الروابط سيكون اقل من )‪.(n (n-1)/2‬‬
‫بالنسبة للشجرة فان عدد الروابط تساوي‬
‫‪m=n–1‬‬

‫م حظة‪ :‬اذا كانت )‪ ,(m < n-1‬فان المخطط سيكون غيرر متررابط كمرا واضرح فري‬
‫الشكل ‪.10.24‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.24‬مالبط غير مترابط‬

‫‪ ‬شجرة ممتدة ‪ :Spanning Tree‬الشجرة الممتدة للمخطرط )‪ (G‬هري مخطرط‬


‫فرعي له المواصفات التالية‬
‫‪ ‬هو شجرة‪.‬‬
‫‪ ‬يحتوي على كل عقد المخطط )‪.(G‬‬

‫شك ‪ :10.25‬مقارنة بين المالبط والشجرة الممتدة‪.‬‬

‫‪ ‬المسافة بين عقدتين )‪ :d(U, V‬ان المسافة بين العقدة )‪ (U‬والعقدة )‪ (V‬هري‬
‫اقصر مسار بين العقدتين‪ .‬فاذا كان هنا اكثر من مسار يصل بين العقدتين فان‬
‫اقصر واحد هو يمثل المسافة‪.‬‬

‫شك ‪ :10.26‬مالبط لحساب المسافة‪.‬‬

‫‪437‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫هنا في الشكل ‪ 10.26‬فان المسرافة مرن العقردة )‪ (d‬الرى العقردة )‪ (e‬او ببسراطة )‪(de‬‬
‫هو واحد حيث يوجد رابط واحد بينهم‪ .‬هنا عدة مسارات من العقدة )‪ (d‬الى العقردة‬
‫)‪ (e‬وهي‬

‫‪‬‬ ‫(المسافة = ‪da, ab, be ) 3‬‬


‫‪‬‬ ‫(المسافة = ‪df, fg, ge ) 3‬‬
‫‪‬‬ ‫‪de‬‬ ‫هي اقصر مسافة (المسافة = ‪) 1‬‬
‫‪‬‬ ‫(المسافة = ‪df, fc, ca, ab, be ) 5‬‬
‫‪‬‬ ‫(المسافة = ‪da, ac, cf, fg, ge ) 5‬‬

‫انحراذ ال قةدة ‪ :Eccentricity of A Vertex‬فري المخطرط المتصرل فران‬ ‫‪‬‬

‫انحراف العقدة هو اكبر مسافة بين عقدة واي عقدة اخرى في المخطرط‪ ,‬ويرمرز‬
‫لهررا )‪ .e(V‬بالنسرربة للمخططررات غيررر المتصررلة فرران جميررع العقررد لهررا انحررراف‬
‫يساوي ما النهاية‪.‬‬
‫في الشكل ‪ 10.26‬فان انحراف العقدة )‪ (a‬هو ‪.3‬‬
‫لحسراب االنحررراف يررتم تحديررد المسررافات بررين العقرردة )‪ (a‬وجميررع العقررد االخرررى‬
‫وتكون المسافة االكبر هي التي تمثل االنحراف‪ .‬لنحسب المسافة بين العقدة )‪(a‬‬
‫وباقي العقد وهي‪:‬‬
‫)‪(ab‬‬ ‫الى العقدة )‪ (b‬المسافة = ‪1‬‬
‫)‪(ac‬‬ ‫الى العقدة )‪ (c‬المسافة = ‪1‬‬
‫المسافة الى العقدة‬
‫)‪d = 1 (ad‬‬

‫‪e=2‬‬ ‫)‪(ab, be) OR (ad, de‬‬

‫‪f=2‬‬ ‫)‪(ac, cf‬‬ ‫)‪OR (ad, df‬‬

‫)‪g = 3 (ac, cf, fg) OR (ad, df, fg‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ ‬نصف قبر المالبط المتص ‪Radius of A Connected Graph‬‬


‫ان االنحراف االصغر من بين انحرافات كل العقد يعتبرر نصرف قطرر المخطرط‬
‫‪ .G‬المسرافة الصررغرى مررن بررين كررل المسرافات العظمررى بررين عقرردة وجميررع العقررد‬
‫االخرى يعتبر نصف قطر المخطط )‪ .(G‬يرمز لها )‪.r(G‬‬
‫بكالم اخرر مرن برين كرل االنحرافرات للعقرد فري المخطرط‪ ,‬يرتم اختيرار االنحرراف‬
‫االصرغر ليمثرل نصرف القطرر‪ .‬فري الشركل ‪ 10.26‬فران ) ‪ ( r(G) = 2‬والتري‬
‫تمثل اصغر انحراف للعقدة )‪ .(d‬الحر ان االنحرراف للعقرد فري الشركل ‪10.26‬‬
‫هي‪:‬‬

‫‪e(b) = 3‬‬

‫‪e(c) = 3‬‬

‫‪e(d) = 2‬‬

‫‪e(e) = 3‬‬

‫‪e(f) = 3‬‬

‫‪e(g) = 3‬‬

‫‪ ‬قبر المالبط ‪Diameter of a Graph‬‬


‫ان اكبررر قيمررة لالنحررراف لكررل العقررد يعتبررر القطررر للمخطررط (هنررا يختلررف مفهرروم‬
‫القطررر ونصررف القطررر عمررا تعلمنررال فرري الرياضرريات عنررد التعامررل مررع الرردائرة)‪.‬‬
‫ويرمز لها )‪.d(G‬‬

‫‪439‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫اذن يتم حساب االنحراف لجميع العقرد كمرا فعلنرا مرع نصرف القطرر‪ ,‬واالنحرراف‬
‫االكبرررر مرررن برررين هرررذل القررريم يعتبرررر هرررو قطرررر المخطرررط‪ .‬القطرررر للمخطرررط فررري‬
‫الشكل ‪ 10.26‬هو ) ‪ (d(G) = 3‬والتي هي اكبر قيمة انحراف‪.‬‬

‫نقبةةة التمركةةز ‪ :Central Point‬عنرردما تتسرراوى درجررة االنحررراف‬ ‫‪‬‬

‫للمخطط مع نصف قطرل فان هذل النقطة تسمى نقطرة التمركرز‪ .‬بكرالم اخرر عنرد‬
‫حسرراب نصررف القطررر‪ ,‬وعنررد تطررابل هررذل القيمررة مررع انحررراف عقرردة مررا فرران هررذل‬
‫العقرردة تعتبررر المركررز‪ .‬فرري الشرركل ‪ 10.26‬فرران نصررف القطررر يسرراوي ‪ ,2‬وهرري‬
‫تطابل درجة االنحراف للعقدة )‪.(d‬‬
‫المركز ‪ :Center‬هي مجموعة نقاط التمركرز فري المخطرط‪ .‬فري مثرال المخطرط‬ ‫‪‬‬

‫اعالل فان مركز المخطط هو }‪ .{d‬الح الشكل ‪.10.27‬‬

‫شك ‪ :10.27‬انحرافات المالبط (االرقا او ال قد تمث انحراذ ال قدة)‪.‬‬

‫المحيط ‪ :Circumference‬عدد الروابط في اطرول دائررة فري المخطرط )‪(G‬‬ ‫‪‬‬

‫تسمى المحيط‪ .‬في الشكل ‪ 10.26‬فان المحيط يسراوي )‪ ,(6‬والرذي يمثرل اطرول‬
‫دائرة في المخطط متمثلة‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫)‪(a-c-f-g-e-b-a‬‬ ‫او‬ ‫‪(a-c-f-d-e-b-a).‬‬

‫المقاس ‪ :Girth‬عدد الروابط فري اقصرر دائررة فري المخطرط )‪ .(G‬ويرمرز لره‬ ‫‪‬‬

‫)‪ .g(G‬في الشكل ‪ 10.26‬فان المقاس يساوي ‪ 4‬وهو يمثل‬

‫)‪(a-c-f-d-a‬‬ ‫‪or‬‬ ‫)‪(d-f-g-e-d‬‬ ‫‪or‬‬ ‫‪(a-b-e-d-a).‬‬

‫‪ 10.5‬اولةر و سةور كةونزبيرج ‪Euler and the Bridges of‬‬


‫‪Koenigsberg‬‬

‫ربما الكثير منا سمع بلغز الجسور التري موضرحة بالشركل ‪ ,10.28‬المطلروب براللغز‬
‫هو المرور على كل جسر في الشركل مررة واحردة فقرط والعرودة الرى نقطرة االنطرالق‬
‫(الجسور هي المستطيالت السوداء في الشكل)‪ ,‬فهل حاولرت ان تحرل هرذل المسرالة؟‪,‬‬
‫وان كنت لم تحاول فهل من الممكن ان تحل المسالة قبل ان تنتقل الى موضوع اخرر‬
‫في هذا الفصل‪ .‬اتمنى لكم وقتا ممتعا‪.‬‬

‫‪441‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.28‬لغز سور كونزبيرج‪.‬‬

‫نظرية اولر ‪Euler’s Theorem‬‬ ‫‪10.5.1‬‬

‫في العام ‪ 1736‬اعلن اولر عن نظريته الشهيرة والتي تفيد‪:‬‬

‫"أي مالبط من الممكن ال تمر علل ك رابط فيه مرة واحدة فقط وت و الل نقبة‬
‫البداية او ال قةدة التةي بةدأت منهةاب اكا واكا فقةط كانةت كة ال قةد لهةا ر ةة زو يةة‬
‫( ر تها رقم زو ي)"‪.‬‬

‫االن نعود الى اللغز‪ ,‬وعليك االستعانه بنظرية اولر لالجابة عن اللغز‪.‬‬

‫‪ 10.6‬انوا المالببات‬

‫هنا انواع متعددة مرن المخططرات تعتمرد علرى عردد العقرد‪ ,‬عردد الرروابط‪ ,‬التررابط‪,‬‬
‫وكامل هيكل المخطط‪ .‬سنتطرق ألنواع قليلة مهمة من المخططات في هذا الفصل‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .1‬المالبةط الفةارغ ‪ :Null Graph‬وهرو المخطرط الرذي ال يحتروي علرى رابرط‪.‬‬


‫كمثال في الشكل ‪ 10.29‬هنا يالث عقد لكن ال يوجد بينها رابط‪.‬‬

‫شك ‪ :10.29‬مالبط فارغ‪.‬‬

‫‪ .2‬المالبةةط الوضةةيع ‪ :Trivial Graph‬المخطررط الررذي لرره عقرردة واحرردة يسررمى‬


‫المخطط الوضيع‪ .‬في الشكل ‪ 10.30‬فان هنا عقدة واحدة وليس لها أي رابط‪.‬‬

‫شك ‪ :10. 30‬مالبط وضيع‪.‬‬

‫‪ .3‬مالبط غير متجه ‪ :Undirected Graph‬هو المخطط الذي تكرون روابطره‬


‫غير متجه‪.‬‬

‫‪443‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.31‬مالبط غير متجه‬

‫‪ .4‬مالبط متجه ‪ :Directed Graph‬هو المخطط الذ يكون فيه كل رابرط محردد‬
‫اتجاهه من عقدة الى اخرى (او من الممكن نفس العقدة)‪.‬‬

‫شك ‪ :10.32‬مالبط متجه‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.33‬مالبط متجه‬

‫‪ .5‬المالبط البسيط ‪ :Simple Graph‬هو المخطط الذي ال يحتوي علرى حلقرات‬


‫او روابط متوازية‪.‬‬

‫ان اكبر عدد للروابط في مخطط مفرد‪ ,‬عدد عقدل يساوي )‪ (n‬هو‬

‫‪= n (n – 1) / 2‬‬

‫كما سبل ووضحنا في هذا الفصل‪ .‬ان اكبرر عردد مرن المخططرات البسريطة الممكنرة‬
‫عندما يكون لدينا )‪ (n‬من العقد هو‬

‫‪= 2n(n-1)/2‬‬
‫‪ .6‬المالبةةط المتةةرابط ‪ :Connected Graph‬اي عقرردتين فرري المخطررط تكررون‬
‫مترابطة بواسطة مسار‪ ,‬الشكل ‪.10.34‬‬

‫‪445‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.34‬توضيح الفارق بين المالبط المترابط وغير المترابط‪.‬‬

‫‪ .7‬المالبةةةط غيةةةر المتصةةة ‪ :Disconnected Graph‬يكرررون المخطرررط غيرررر‬


‫مترابط اذا احتوى على االقل عقدتين غير مترابطتين‪ .‬الح الشكل ‪.10.34‬‬

‫‪ .8‬المالبط االعتيا ي ‪ :Regular Graph‬هو المخطط الذي تكرون جميرع عقردة‬


‫لها نفس الدرجة‪ .‬في اي مخطط عندما تكون درجة جميع العقد فيه تساوي )‪,(k‬‬
‫عليه فان المخطط يسمى (مخطط اعتيادي من الدرجرة ‪ .)k‬فري الشركل ‪10.35‬‬
‫فان المخطط والذي جميع عقدل لها الدرجة ‪ 2‬يسمى (مخطط اعتيادي – ‪.) 2‬‬

‫شك ‪ :10.35‬مالبط اعتيا ي من الدر ة ‪.2‬‬

‫‪ .9‬المالبط الكام ‪ :Complete Graph‬هو المخطط الذي تكون فيره كرل عقردة‬
‫مرتبطة مع جميع العقد في المخطط‪ .‬الح الشكل ‪.10.36‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.36‬مالبط كام ‪.‬‬

‫‪ .10‬مالبط ائري ‪ :Cycle Graph‬المخطط البسيط الذي له )‪ (n‬من العقد بحيرث‬


‫)‪ ,(n>=3‬وله )‪ (n‬من الروابط يسمى مخطط دائري اذا جميع روابطه عملرت‬
‫دائرة بطول )‪ .(n‬الشكل ‪ 10.37‬له اربع عقد واربع روابط ويكون دائرة بطول‬
‫‪.4‬‬

‫شك ‪ :10.37‬مالبط ائري‪.‬‬

‫‪ 10.7‬طرق المرور علل المالبط ‪Graph Traversal‬‬


‫هنا طريقتين ممكنه للمرور على المخططات‪:‬‬
‫المرور بالعمل اوال ‪Depth First Search‬‬
‫المرور جانبيا اوال ‪Breadth First Search‬‬

‫المرور ببريقة ال مر اوال ‪Depth First Traversal‬‬ ‫‪10.7.1‬‬


‫خوارزميررة البحررث بطريقررة العمررل اوال تمررر علررى المخطررط بحركررة باتجررال العمررل‬
‫ويستخدم المكدس لتحديد العقدة الالحقة لبدا البحث عند حصول نهاية مغلقرة او ميترة‬
‫في اي عملية تكرار‪.‬‬

‫‪447‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫المرور على كل العقد ابتداء من عقدة بداية مقترحرة (نحرن مرن يحردد نقطرة البدايرة)‪.‬‬
‫عليه‪ ,‬فان المرور سيتبع مبدا المجاور اوال مع االخذ بنظر االعتبار مايلي‪:‬‬
‫‪ ‬عدم المرور على أي عقدة ألكثر من مرة واحدة فقط‪.‬‬
‫‪ ‬فقط تلك العقد التي من الممكن الوصول لها يتم زيارتها‪.‬‬
‫‪ ‬من المهم هنا‪ ,‬ان نستخدم مكدس هياكل البيانات‪ .‬سيتم اضافة العقد التي يرتم‬
‫زيارتها الى المكدس بترتيب يتم سحبها من المكدس بحيث ان الداخل اخيررا‬
‫يخرج اوال‪.‬‬
‫زيارة العقدة يتضمن اعادة البيانات التي في العقردة واضرافة مجاورهرا الرى المكردس‪.‬‬
‫على كل‪ ,‬فاننا النعمل أي فعل في الحاالت التالية‪:‬‬
‫اذا كان المجاور اساسا في المكدس‪ ,‬او اذا كان المجاور قد سبل وان تمت زيارته‪.‬‬
‫‪ ‬ووارزمية المرور‬
‫القاعدة االولل‪ :‬تحديد عقدة البداية‪ ,‬زيارة العقد المجاورة لها التي لم يتم زيارتها‪.‬‬
‫القاعةدة الثانيةة ‪ :‬اذا لررم يرتم ايجرراد عقرد مجرراورة‪ ,‬يرتم سررحب عقردة مررن المكردس‪( .‬يررتم‬
‫سحب جميع العقد من المكدس التي ليس لها عقرد مجراورة‪ .‬اي يرتم السرحب لحرين ان‬
‫نجد عقدة لها مجاور او لحين ان يفر المكدس)‪.‬‬
‫القاعدة الثالثة‪ :‬اعد القاعدة االولى والثانية لحين ان يفر المكدس‪.‬‬
‫م حظة‪ :‬العقدة التي يتم زيارتها يفضل تعليمها او تاشيرها لتسهيل العمل‪.‬‬
‫لنتابع هذل الخوارزمية باستخدام الشكل ‪.10.38‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫الشك ‪ :10.38‬مثال لمالبط مع مكدس فارغ‬

‫‪ .1‬بداية ابدأ بمكدس فار ‪.‬‬


‫‪ .2‬يتم زيارة اول عقدة وهري العقردة )‪ (S‬ونردفعها فري المكردس‪ ,‬ويرتم تعليمهرا علرى‬
‫انها تمت زيارتها‪ .‬كما في الشكل ‪.10.39‬‬
‫نبحررث عررن اي عقرردة مجرراورة للعقرردة )‪ .(S‬هنررا يررالث عقررد مجرراورة لهررا وهرري‬
‫)‪ (A, B, C‬ومن الممكن ان نختار اي واحدة منهم‪ .‬في هذا المثال سوف نختار‬
‫العقدة حسب حروف الهجاء‪ ,‬وهي العقدة )‪.(A‬‬

‫شك ‪ :10.39‬المكدس ب د زيارة اول عقدة‪.‬‬


‫‪ .3‬تؤشرررر العقررردة )‪ (A‬علرررى انهرررا تمرررت زيارتهرررا وادفعهرررا فررري المكررردس كمرررا فررري‬
‫الشركل ‪ .10.40‬ابحرث عرن اي عقردة مجراورة للعقردة )‪ .(A‬فري هرذل الحالرة فران‬
‫العقدتين )‪ (S, D‬كالهما تجاور العقدة )‪ (A‬لكن من المفروض ان نختار العقدة‬
‫التي لم يتم زيارتها وبالتالي سيتم اختيار العقدة )‪.(D‬‬

‫‪449‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.40‬المكدس ب د اضافة ال قدة الثانية‪.‬‬

‫‪ .4‬االن جاء دور زيارة العقدة )‪ (D‬وتدفع الى المكدس بعد ان تعلم على انهرا تمرت‬
‫زيارتها‪ ,‬كما في الشكل ‪.10.41‬‬
‫نبحث عن العقد المحاورة لها وسنجد ان العقدتين )‪ (B, C‬كالهما تجاور العقدة‬
‫)‪ (D‬وكالهما لم يتم زيارتهما‪ .‬وسنختار حسب الحروف االبجدية‪ ,‬لتكون العقدة‬
‫)‪ (B‬هي العقدة المختارة‪.‬‬

‫شك ‪ :10.41‬المكدس ب د عملية التحديث‪.‬‬

‫‪ .5‬يتم زيارة العقدة )‪ (B‬وتعلم على انها تمرت زيارتهرا وتردفع الرى المكردس فيكرون‬
‫شكل المكدس كما في الشكل ‪.10.42‬‬
‫هنا عند الفحص عن العقد المجاورة سوف ال نجد اي عقدة مجاورة للعقردة )‪(B‬‬
‫لم يتم زيارتها سابقا‪ .‬فري هرذل الحالرة يرتم سرحب العقردة التري فري اعلرى المكردس‬
‫)‪ ,(B‬وتفحررص العقررردة التررري بعررردها )‪ (D‬ان كانرررت لهرررا عقررردة مجررراورة لرررم يرررتم‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫زيارتها‪ ,‬سنجد هنا العقدة )‪( (C‬اذا لم نجرد نسرتمر بسرحب العقرد التري فري اعلرى‬
‫المكدس)‪ .‬سيكون شكل المكدس بعد سحب العقدة التي في االعلرى )‪ (B‬كمرا فري‬
‫الشكل ‪.10.43‬‬

‫شك ‪ :10.42‬المكدس ب د اضافة عقدة‬

‫شك ‪ :10.43‬المكدس ب د سحب عقدة‪.‬‬

‫‪451‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .6‬تتم زيارة العقدة )‪ (C‬وتعلم على انها تمرت زيارتهرا يرم تردفع الرى المكردس‪ ,‬كمرا‬
‫هو واضح من الشكل ‪.10.44‬‬
‫يتم البحث عن العقد المجاورة والتري لرم ترتم زيارتهرا‪ .‬ونظررا لعردم وجرود عقردة‬
‫مجاورة للعقدة )‪ (C‬لم تتم زيارتها نسحب العقردة التري فري اعلرى المكردس )‪.(C‬‬
‫نستمر بسرحب العقردة التري فري االعلرى واحردة بعرد االخررى (وفري كرل مررة يرتم‬
‫فحص العقدة في اعلى المكدس ان كران لهرا مجراور) لحرين ان يرتم العثرور علرى‬
‫عقدة لها مجاور لم يتم زيارته‪ .‬فري مثالنرا هرذا سريتم سرحب جميرع العقرد دون ان‬
‫نعثر على عقدة مجاورة ولذلك متى مرا فرر المكردس فران عمليرة المررور علرى‬
‫عقد المخطط تكون قد تمت‪.‬‬
C++ ‫هياكل البيانات باستخدام‬

.‫( فيه‬C) ‫ المكدس ب د فع ال قدة‬:10.44 ‫شك‬

SADBC ‫ نتيجة المرور ستكون‬

‫ (يركرز علرى المثرال‬Depth First ‫ برنرامج المررور علرى المخطرط بطريقرة‬


.)‫اعالل‬
#include <stdio>

#include <stdlib>

#include <stdbool>

#define MAX 5

using namespace std ;

struct Vertex {

char label;

bool visited;

};

// ‫متغيرات المكدس‬

int stack[MAX];

int top = -1;

// ‫مصفوفة العقد‬

struct Vertex* lstVertices[MAX];

453
C++ ‫هياكل البيانات باستخدام‬

// ‫مصفوفة التجاور‬

int adjMatrix[MAX][MAX];

// ‫حساب عدد العقد‬

int vertexCount = 0;

// ‫دوال المكدس‬

void push(int item) {

stack[++top] = item;

int pop() {

return stack[top--];

int peek() {

return stack[top];

bool isStackEmpty() {

return top == -1;


C++ ‫هياكل البيانات باستخدام‬

// ‫دوال المخطط‬

// ‫اضافة عقدة الى قائمة العقد‬

void addVertex(char label) {

struct Vertex* vertex = (struct Vertex*) malloc(sizeof(struct Vertex));

vertex->label = label;

vertex->visited = false;

lstVertices[vertexCount++] = vertex;

// ‫اضافة رابط الى مصفوفة الروابط‬

void addEdge(int start,int end) {

adjMatrix[start][end] = 1;

adjMatrix[end][start] = 1;

// ‫عرض العقدة‬

void displayVertex(int vertexIndex) {

cout<< lstVertices[vertexIndex]->label);

// ‫استدعاء عقدة مجاورة لم يتم زيارتها‬

455
C++ ‫هياكل البيانات باستخدام‬

int getAdjUnvisitedVertex(int vertexIndex) {

int i;

for(i = 0; i<vertexCount; i++) {

if(adjMatrix[vertexIndex][i] == 1 && lstVertices[i]->visited == false)


{

return i;
}

return -1;

void depthFirstSearch() {

int i;

// ‫تعليم العقدة االولى على انها تمت زيارتها‬

lstVertices[0]->visited = true;

// ‫عرض العقدة‬

displayVertex(0);
C++ ‫هياكل البيانات باستخدام‬

// ‫دفع دليل العقدة الى المكدس‬

push(0);

while(!isStackEmpty()) {

// ‫استدعاء العقد المجاورة التي لم يتم زيارتها للعقدة التي في اعلى المكدس‬

int unvisitedVertex = getAdjUnvisitedVertex(peek());

// ‫عدم وجود عقدة مجاورة‬

if(unvisitedVertex == -1) {

pop();

}else {

lstVertices[unvisitedVertex]->visited = true;

displayVertex(unvisitedVertex);

push(unvisitedVertex);

// ‫ تحديث عمليات التعليم السابق‬,‫ انتهاء عملية البحث‬,‫المكدس فارغ‬

for(i = 0;i < vertexCount;i++) {

lstVertices[i]->visited = false;

457
C++ ‫هياكل البيانات باستخدام‬

int main() {

int i, j;

for(i = 0; i<MAX; i++) // ‫ضبط المجاورات‬

for(j = 0; j<MAX; j++)

adjMatrix[i][j] = 0;
}

addVertex('S'); // 0

addVertex('A'); // 1

addVertex('B'); // 2

addVertex('C'); // 3

addVertex('D'); // 4

addEdge(0, 1); // S - A

addEdge(0, 2); // S - B

addEdge(0, 3); // S - C

addEdge(1, 4); // A - D

addEdge(2, 4); // B - D

addEdge(3, 4); // C - D
‫هياكل البيانات باستخدام ‪C++‬‬

‫; " ‪cout<< "Depth First Search:‬‬

‫;)(‪depthFirstSearch‬‬

‫;‪return 0‬‬

‫}‬

‫نتيجة البرنامج اعالل هي ‪S A D B C :‬‬

‫‪ 10.7.2‬المرور الجانبي اوال ‪Breadth First‬‬

‫ان خوارزمية البحث الجانبي اوال سرتمر علرى المخطرط برالتحر علرى كرل مسرتوى‬
‫فرري المخطررط ويسررتخدم الطررابور للتررذكير بالعقررد الترري ترراتي الحقررا لبرردا البحررث عنررد‬
‫الوصول الى نهاية ميتة‪.‬‬
‫الخوارزمية تمر على جميرع العقرد‪ ,‬بدايرة مرن عقردة بدايرة محرددة‪ .‬هنرا‪ ,‬المررور يتبرع‬
‫مبدا التجاور اوال مع االخذ بنظر االعتبار مايلي‪:‬‬
‫‪ ‬ال تتم زيارة عقدة اكثر من مرة واحدة فقط‪.‬‬
‫‪ ‬فقط العقد التي من الممكن الوصول لها يتم زيارتها‪.‬‬
‫مهم هنا‪ ,‬ان نستخدم طابور هياكل البيانات‪ .‬سيستخدم لحفر العقرد التري يرتم زيارتهرا‬
‫اخيرا بترتيب االضافة الى الطابور بمعنى من يدخل اوال يخرج اوال‪.‬‬
‫زيارة العقدة يتضمن اعادة البيانات التي في العقدة واضافة العقدة التي تجاورها الرى‬
‫الطابور‪ .‬على كل‪ ,‬سوف ال يتم اتخاذ أي فعل تحت الشروط التالية‪:‬‬
‫‪ ‬اذا كان المجاور موجودا اساسا في الطابور‪.‬‬
‫‪ ‬اذا المجاور سبل وان تم زيارتة‪.‬‬

‫‪459‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ ‬ووارزمية البحث الجانبي‬


‫القاعدة االولةل‪ :‬زيرارة العقردة المجراورة‪ .‬اشررها بانهرا تمرت زيارتهرا‪ .‬اعرضرها‪ ,‬قرم‬
‫بحشرها في الطابور‪.‬‬
‫القاعدة الثانية‪ :‬اذا لم تجد عقدة مجاورة‪ ,‬ازل اول عقدة من الطابور‪.‬‬
‫القاعدة الثالثة‪ :‬كرر القاعدة االولى والثانية لحين ان يفر الطابور‪.‬‬
‫لنشرح هذل الطريقة باستخدام الشكل والذي يظهر فيه المخطط الذي نرغرب المررور‬
‫عليه‪ ,‬تم انشاء طابور فار واضح بالشكل ‪.10.45‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.45‬المالبط الذي سيتم زيارة عقد وكذلو تمثي لبابور فارغ‪.‬‬

‫‪ .1‬تتم عملية المرور بداية بزيارة العقدة االولى هنا )‪ ,(S‬وعند زيارتها تعلم (نغير‬
‫لونهررا فقررط للمتابعررة‪ ,‬برمجيررا مررن الممكررن ان تكررون عالمتهررا ‪ ,) true‬كمررا فرري‬
‫الشكل ‪.10.46‬‬

‫شك ‪ :10.46‬المالبط ب د زيارة ال قدة االولل‪.‬‬

‫‪ .2‬يتم البحث عن العقردة المجراورة‪ ,‬الحر وجرود يرالث عقرد مجراورة )‪(A, B, C‬‬
‫ويتم االختيار وفقا للحروف االبجدية فتكون العقردة التاليرة هري العقردة )‪ .(A‬يرتم‬
‫تعليم العقدة )‪ (A‬وحشرها في الطابور كما في الشكل ‪.10.47‬‬

‫‪461‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.47‬البابور ب د التحديث‪.‬‬

‫‪ .3‬العقدة الالحقة والتي هي مجاورة للعقدة )‪ (S‬وحسب التسلسرل االبجردي سرتكون‬


‫العقدة )‪ ,(B‬سيتم زيارتها وتعليمها على انها تمت زيارتها وتحشر في الطرابور‬
‫كما في الشكل ‪. 10.48‬‬

‫شك ‪ :10.48‬البابور ب د التحديث‬

‫‪ .4‬العقدة االخرى المجاورة للعقدة )‪ (S‬والتي لرم يرتم زيارتهرا بعرد هري العقردة )‪(C‬‬
‫فيصار الى زيارتها وتعلم على انها تمت زيارتهرا‪ ,‬يرم تحشرر فري الطرابور‪ ,‬كمرا‬
‫في الشكل ‪.10.49‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.49‬البابور ب د حشر عقدة ديدة‪.‬‬

‫‪ .5‬االن العقدة )‪ (S‬ليس لها اي عقدة مجاورة لم يتم زيارتها لرذلك يرتم سرحب عقردة‬
‫مررن الطررابور وهنررا سرريتم سررحب العقرردة )‪ .(A‬ويكررون شرركل الطررابور كمررا فرري‬
‫الشكل ‪.10.50‬‬

‫شك ‪ :10.50‬البابور ب د سحب عنصر منه‪.‬‬

‫‪ .6‬االن بالنسربة للعقردة الترري ترم سررحبها مرن الطررابور نفحرص عررن مجاوراتهرا فنجرد‬
‫العقدة )‪ (D‬مجاورة لها‪ ,‬لذلك تعلم هذل العقدة علرى انهرا تمرت زيارتهرا‪ ,‬وتحشرر‬
‫في الطابور‪ .‬كما في الشكل ‪.10.51‬‬

‫‪463‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.51‬البابور ب د التحديث‪.‬‬

‫‪ .7‬االن ال توجررد عقررد مجرراورة للعقرردة )‪ (A‬لررم يررتم زيارتهررا‪ ,‬فيررتم سررحب عقرردة م رن‬
‫الطررابور وتفحررص ان كرران لهررا مجرراورات لررم يررتم زيارتهررا‪ .‬هررذل العمليررة تسررتمر‬
‫لحين ان نجد عقدة مجاورة لم يتم زيارتها او يفر الطابور وبذلك تكون عمليرة‬
‫المرور قد انتهت‪.‬‬
‫‪ ‬نتيجة عملية المرور ستكون ‪S A B C D‬‬
‫‪ ‬برنررامج المرررور علررى المخطررط باسررتخدام طريقررة ‪( Breadth First‬سررنركز‬
‫على المثال اعالل كنموذج للبرمجة)‪.‬‬
‫>‪#include <stdio‬‬

‫>‪#include <stdlib‬‬

‫>‪#include <stdbool‬‬

‫‪#define MAX 5‬‬

‫; ‪using namespace std‬‬

‫{ ‪struct Vertex‬‬

‫;‪char label‬‬

‫;‪bool visited‬‬

‫;}‬

‫متغيرات الطابور ‪//‬‬

‫;]‪int queue[MAX‬‬

‫;‪int rear = -1‬‬


C++ ‫هياكل البيانات باستخدام‬

int front = 0;

int queueItemCount = 0;

// ‫متغيرات المخطط‬

// ‫مصفوفة العقد‬

struct Vertex* lstVertices[MAX];

// ‫مصفوفة المجاورات‬

int adjMatrix[MAX][MAX];

// ‫حساب عدد العقد‬

int vertexCount = 0;

// ‫دوال الطابور‬

void insert(int data) {

queue[++rear] = data;

queueItemCount++;

int removeData() {

queueItemCount--;

return queue[front++];

465
C++ ‫هياكل البيانات باستخدام‬

bool isQueueEmpty() {

return queueItemCount == 0;

// ‫دوال المخطط‬

// ‫اضافة عقدة الى قائمة العقد‬

void addVertex(char label) {

struct Vertex* vertex = (struct Vertex*) malloc(sizeof(struct Vertex));

vertex->label = label;

vertex->visited = false;

lstVertices[vertexCount++] = vertex;

// ‫اضافة رابط الى مصفوفة الروابط‬

void addEdge(int start,int end) {

adjMatrix[start][end] = 1;

adjMatrix[end][start] = 1;

}
C++ ‫هياكل البيانات باستخدام‬

// ‫عرض العقدة‬

void displayVertex(int vertexIndex) {

cout<< lstVertices[vertexIndex]->label ;

// ‫استدعاء العقدة المجاورة التي لم يتم زيارتها‬

int getAdjUnvisitedVertex(int vertexIndex) {

int i;

for(i = 0; i<vertexCount; i++) {

if(adjMatrix[vertexIndex][i] == 1 && lstVertices[i]->visited == false)

return i;

return -1;

void breadthFirstSearch() {

int i;

// ‫تعليم العقدة االولى على انها تمت زيارتها‬

lstVertices[0]->visited = true;

// ‫عرض العقدة‬

467
C++ ‫هياكل البيانات باستخدام‬

displayVertex(0);

// ‫اضافة دليل العقدة الى الطابور‬

insert(0);

int unvisitedVertex;

while(!isQueueEmpty()) {
// ‫استدعاء العقد التي لم يتم زيارتها للعقدة التي في بداية الطابور‬

int tempVertex = removeData();

// ‫عدم وجود عقد مجاورة‬

while((unvisitedVertex = getAdjUnvisitedVertex(tempVertex)) != -1)


{

lstVertices[unvisitedVertex]->visited = true;

displayVertex(unvisitedVertex);

insert(unvisitedVertex);

// ‫ ضبط اشارات التعليم‬, ‫ انتهاء عملية المرور‬,‫الطابور فارغ‬

for(i = 0;i<vertexCount;i++) {

lstVertices[i]->visited = false;

}
C++ ‫هياكل البيانات باستخدام‬

int main() {

int i, j;

for(i = 0; i<MAX; i++) // ‫ضبط المجاورات‬

for(j = 0; j<MAX; j++)

adjMatrix[i][j] = 0;

addVertex('S'); // 0

addVertex('A'); // 1

addVertex('B'); // 2

addVertex('C'); // 3

addVertex('D'); // 4

addEdge(0, 1); // S - A

addEdge(0, 2); // S - B

addEdge(0, 3); // S - C

addEdge(1, 4); // A - D

addEdge(2, 4); // B - D

addEdge(3, 4); // C - D

cout<< "\nBreadth First Search: " ;

breadthFirstSearch();

469
‫هياكل البيانات باستخدام ‪C++‬‬

‫;‪return 0‬‬

‫}‬

‫نتيجة البرنامج هي‪S A B C D :‬‬

‫‪ 10.8‬العمليات االولي االساسي التي تجرى على المخططات‬

‫هناك عدد من العمليات التي تجرى على المخططات‪ ,‬غالبا هذه العمليات تؤدي الى‬
‫تحوير المخططات‪ .‬سنحاول ان نتطرق الى اغلب هذه العمليات‪ .‬بعض‬
‫العمليات ستكون سهلة جدا وواضحة عند التطرق لتمثيل المخططات‪.‬‬

‫‪ .1‬حذذ عقدة ‪Delete vertex‬‬


‫ماذا يحدث عند حذف عقدة من المخطط )‪G(V, E‬؟‬
‫ال يمكننا ان نحرذف عقردة بنجراح اذا لرم يرتم ازالرة (حرذف) كرل الرروابط التابعرة لهرذل‬
‫العقدة‪ .‬هذل العملية تغير مجموعرة العقرد وعائلرة الرروابط للمخطرط‪ .‬لرذلك عنرد حرذف‬
‫عقدة فان كل الروابط المتعلقة بهذل العقدة يتم حذفها ايضا‪.‬‬
‫الشكل ‪ 10.52‬يساعد في فهم حذف العقدة‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.52‬توضيح عملية حذذ عقدة من المالبط‪.‬‬

‫‪ .2‬م ال قد ‪contract vertex‬‬


‫واحدة من العمليات المهمة في المخططات هي دمج العقد‪ .‬من الممكن انجازها بدمج‬
‫اينرران او اكثررر مررن العقررد بعقرردة واحرردة‪ .‬كررذلك‪ ,‬مررن الممكررن ان تنجررز برردمج الررروابط‪,‬‬
‫والتي سنراها الحقا‪.‬‬
‫ليس مرن الممكرن دمرج عقردة واحردة فقرط‪ ,‬ان عمليرة الردمج تحتراج الرى مجموعرة مرن‬
‫العقد على االقل اينران‪ .‬وعمليرة الردمج تنجرز عنردما يكرون هنرا رابرط برين العقردتين‬
‫المراد دمجهما‪ .‬العملية اساسا ستزيل كل الرروابط برين العقردتين‪ .‬فري الشركل ‪10.53‬‬
‫فرران العقرردتين )‪ (1, 2‬تررم دمجهمررا‪ ,‬والعقرردتين )‪ (5, 6‬ايضررا تررم دمجهمررا‪ .‬الحر ان‬
‫الرابط الذي يربط العقدتين قبل الدمج يتم ازالته عند الدمج‪.‬‬

‫شك ‪ :10.53‬يوضح طريقة م ال قد‬

‫‪471‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .3‬م الرابط ‪contracting an edge‬‬


‫دمج رابط هو مشابه بالضبط لدمج العقد‪ .‬فهو يزيل الرابط من المخطط ويدمج العقد‬
‫التي يربطها هذا الرابط‪.‬‬
‫‪ .4‬اضافة وحذذ رابط ‪Add and Delete Edge‬‬
‫اضافة رابط الى المخطط من الممكن انجرازل برربط عقردتين مطلروب اضرافة الررابط‬
‫بينهما‪ .‬حذف رابط من الممكن عمله بازالة الرابط بين عقدتين مقترحة‪.‬‬

‫‪ 10.9‬تمثي المالبط ‪Graph Representation‬‬


‫هنررا عرردة طرررق لتمثيررل المخططررات‪ ,‬نحرراول ان نرردرج اهررم هررذل الطرررق واالكثررر‬
‫شيوعا‪.‬‬
‫‪ .1‬قائمة التجاور‪ :‬ان ابسط تمثيل يكون مرن خرالل مرا يسرمى قائمرة التجراور والتري‬
‫تحدد كل العقد المجاورة لكل عقدة في المخطط‪ .‬هذل القائمة من الممكرن تنفيرذها‬
‫على شكل جدول كما في الشكل ‪.10.54‬‬

‫شك ‪ :10.54‬مالبط عا ‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.55‬يوضح قائمة التجاور للمالبط في الشك ‪10.54‬‬

‫‪ .2‬القوائم الموصولة‪ :‬كذلك من الممكن تمثيلها على شكل قوائم موصرولة‪ ,‬كمرا فري‬
‫الشكل ‪.10.56‬‬

‫‪473‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.56‬مصفوفة التجاور للمالبط في الشك ‪10.54‬‬

‫‪ .3‬مصفوفة المتجاورات ‪Adjacency matrix‬‬


‫مصررفوفة المتجرراورات هرري طريقررة لتمثيررل )‪ (n‬مررن العقررد فرري المخطررط )‪G(V, E‬‬
‫بمصفوفة حجمها )‪ ,(n × n‬بحيث ان جميع مدخالتها هي قيم منطقية )‪ .(0, 1‬وهري‬
‫واحدة من طرق تمثيل المخططات البسيطة‪.‬‬
‫يتم ضبط (‪ ) aij = true‬اذا كان هنا رابط بين العقدتين )‪.(i, j‬‬
‫ان مدخالت المصفوفة )]‪ (a[i][j‬من الممكن تعريفها وفقا لما يلي‪:‬‬

‫‪ ‬الروابط من الممكن ان تكون غير متجه‪ ,‬في حالة (‪ ) aij = true‬وكذلك‬


‫(‪ ) aji = true‬اي ان ) ‪.( aji = aij‬‬
‫بداية يتم خزن المصفوفة (مصفوفة ينائية) بحجم ‪ N×N‬حيرث ان ‪ N‬هرو عردد العقرد‬
‫في المخطط‪ .‬هذا يعني اذا كان هنا رابط بين العقردتين تكرون قيمتره ‪ 1‬واذا لرم يكرن‬
‫هنا رابط تكون القيمة صفر‪ .‬الح الشكل ‪.10.57‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.57‬مصفوفة التجاور لمالبط غير المتجه‬

‫‪.(aij‬‬ ‫‪ ‬او يكون المخطط متجه في حالة ان تكون ) ‪aji‬‬


‫فرري المخططررات المتجرره مررن الممكررن ان نسررتخدم ‪ 1‬عنررد وجررود رابررط بررين )‪(i, j‬‬
‫ونستخدم ‪ 1-‬بالعكس اي عندما يكون الرابط بين )‪.(j, i‬‬

‫‪475‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.58‬مصفوفة التجاور لمالبط متجه‪.‬‬

‫‪ ‬في المخططات الموزونة المتجهة‪ ,‬نضع الوزن على الرابط المتجه بدال من‬
‫‪.1‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.59‬مصفوفة التجاور لمالبط موزول متجه‪.‬‬

‫في هذا التمثيل‪ ,‬فان عمليرات اضرافة رابرط‪ ,‬حرذف رابرط‪ ,‬وفحرص وجرود رابرط فقرط‬
‫تتضمن اضافة قيم للمصفوفة او قراءة مدخالت المصفوفة )]‪ (a[i][j‬كما يلي‪:‬‬
‫{ )‪void addEdge(int i, int j‬‬

‫;‪a[i][j] = true‬‬

‫}‬

‫{ )‪void removeEdge(int i, int j‬‬

‫;‪a[i][j] = false‬‬

‫}‬

‫{ )‪bool hasEdge(int i, int j‬‬

‫;]‪return a[i][j‬‬

‫}‬

‫‪477‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.60‬مالبط متجه مع مصفوفة التجاور له‬

‫‪ .4‬قوائم التجاور ‪Adjacency Lists‬‬


‫هنا عد طرق لتنفيذ قوائم التجاور‪ .‬في هذا الفصل سنقدم احدى الطرق البسيطة‪.‬‬
‫قوائم التجاور هي طريقرة تمثيرل للمخططرات مفيردة‪ ,‬فري هرذل الطريقرة فران المخطرط‬
‫)‪ G(V, E‬سيمثل علرى شركل مصرفوفة قروائم‪ ,‬حيرث ان كرل مردخل للمصرفوفة يمثرل‬
‫احدى عقد المخطط والتي تمثل عقدة الراس لقائمة تشمل جميع العقرد المرتبطرة بهرا‪.‬‬
‫نفرض ان المصفوفة التي تمثل المخطط تسمى )‪( (ad‬وهري مصرفوفة قروائم)‪ ,‬لرذلك‬
‫فان )]‪ (ad[i‬تمثل قائمرة تحتروي علرى جميرع العقرد المجراورة للعقردة )‪ .(i‬عليره‪ ,‬هري‬
‫تحتروي علرى كرل الفهرارس (ارقرام العقرد) بحيرث ان )‪( ((i, j) E‬اي وجرود رابرط‬
‫بين )‪ ,) (i, j‬كما في الشكل ‪.10.61‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.61‬قائمة التجاور لمالبط متجه‪.‬‬

‫في طريقة قوائم التجاور فان اضافة رابط برين )‪ (i, j‬تتطلرب فقرط اضرافة العقردة )‪(j‬‬
‫الى القائمة )]‪.(ad[i‬‬
‫;‪int n‬‬

‫;‪List *ad‬‬

‫{ )‪void addEdge(int i, int j‬‬

‫;)‪ad[i].add(j‬‬

‫}‬

‫عملية ازالة رابط والذي يربط بين العقدتين )‪ (i, j‬يتم باجراء عملية البحرث اوال فري‬
‫القائمة )]‪ (ad[i‬لحين ايجاد )‪ (j‬وعندها يتم ازالتها‪.‬‬
‫{ )‪void removeEdge(int i, int j‬‬

‫{ )‪for (int k = 0; k < adj[i].size(); k++‬‬

‫{ )‪if (adj[i].get(k) = = j‬‬

‫;)‪adj[i].remove(k‬‬

‫;‪return‬‬

‫}‬ ‫}‬ ‫}‬

‫‪479‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.62‬مالبط مع قوائم التجاور التي تمثله‬

‫‪ .5‬النروع االخرر مرن المصرفوفات هري مصرفوفة الحردوث )‪(incidence matrix‬‬


‫وهري تمثررل العالقرة بررين العقرد والررروابط ووفقررا للعالقرة التاليررة (الشركل ‪10.63‬‬
‫يوضح ذلك)‪:‬‬

‫الشك ‪ :10.63‬يوضح مصفوفة الحدوث للمالبط في الشك ‪.10.52‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫ووارزمية يكسترا ‪Dijkstra's algorithm‬‬ ‫‪10.10‬‬

‫هي خوارزمية اليجاد اقصر طريل (االقل وزنرا) برين اينران مرن العقرد المحرددة فري‬
‫مخطط موزون ال يحتوي على روابط لها اوزان سالبة‪.‬‬
‫هي تحل مشكلة المسار االقصر لعقدة واحدة‬ ‫‪‬‬
‫مفرراهيم الخوارزميررة االساسررية‪ :‬خلررل جرردول معلومررات حررول افضررل الطرررق‬ ‫‪‬‬
‫المعروفة حاليا للوصول الى كل عقدة ( تشمل المسافة‪ ,‬العقردة السرابقة) وتحسرينها‬
‫لحين الحصول على افضل حل‪.‬‬
‫‪ ‬ابسررط عمليررة تنفيررذ لهررذل الخوارزميررة هررو بحف ر العقررد فرري قائمررة موصررولة او‬
‫مصفوفة‪.‬‬
‫ان طرول المسرار ))‪ ( p = (v0, v1, v2 … vk‬هرو مجمروع االوزان لروابطهرا‬
‫المتتالية‪.‬‬
‫= )‪Length (p‬‬

‫المسرافة برين )‪ (u, v‬تمثرل برالترميز ))‪ ( (u, v‬وهرو طرول اقصرر مسرار اذا كران‬
‫هنا مسار بين )‪ ,(u, v‬وبخالف ذلك فالطول يساوي )∞(‪.‬‬
‫في الشكل ‪ ,10.64‬فان المسافة ))‪ (p= (a, b, c, e‬تساوي (‪.)6‬‬
‫وذلك الن اقصر مسافة بين )‪ (a, e‬تساوي (‪.)6‬‬

‫‪481‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.64‬مالبط موزول‪.‬‬

‫في المخطط من الممكن ان تكون‪:‬‬


‫‪ ‬العقد تمثل المدن‪.‬‬
‫‪ ‬اوزان الروابط تمثل المسافة بين مدينتين (بالسريارة) (اذا كران هنرا طريرل‬
‫يربط بين المدينتين)‪.‬‬
‫خوارزميررة ‪ Dijkstra‬تسرررتخدم اليجررراد الطريرررل االقصررر برررين مدينرررة واي مدينرررة‬
‫اخرى‪.‬‬
‫وبوات الالوارزمية ‪Dijkstra(V1, V2):‬‬ ‫‪10.10.1‬‬

‫ان هدف الخوارزمية هو المحافظة على )]‪ (d[V‬الن يكون بطول‬ ‫‪.1‬‬
‫)‪ (S, V‬والذي هو اقصر مسار بين عقدة المصدر وكل عقدة )‪.(V‬‬
‫دائما ) )‪ (d[V] ≥ (S, V‬وان المسافة ]‪ d[V‬تساوي طول المسار المعلروم‪,‬‬ ‫‪.2‬‬
‫الن )∞ = ]‪ (d[V‬اذا لم يكن هنا مسار‪.‬‬
‫بد اية يتم تحديد العقدة المصدر وهي العقدة التي سريتم حسراب المسرافة نسربة لهرا‬ ‫‪.3‬‬
‫(من الممكن اعتبارها عقدة البداية)‪.‬‬
‫تحدد المسافة لكل عقد المخطط )]‪ ,(d[V‬في البداية تكون مسافة عقدة المصردر‬ ‫‪.4‬‬
‫تساوي صفر‪ ,‬بينما مسافة جميع العقد االخرى تساوي ما النهاية‪.‬‬
‫الخوارزمية تعالج العقد واحدة بعد االخرى حسب ترتيب معين‪ .‬هنا ان معالجرة‬ ‫‪.5‬‬
‫العقرردة )‪ (u‬مررثال تعنرري ايجرراد المسررارات الجديرردة وتحررديث المسررافات )]‪(d[V‬‬
‫لجميررع العقررد )‪ (v‬والترري تنتمرري الررى مجرراورات العقرردة )‪ (u‬اذا كرران التحررديث‬
‫ضررروري‪ .‬ان عمليررة حسرراب المسررافات والتحررديث الررذي يحرردث بموجبرره تسررمى‬
‫)‪ .(relaxation‬عند معالجة جميع العقد فان‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫) )‪ ( d[v] = (S, V‬اي اننرا نكرون قرد حسربنا اقصرر مسرافة لكرل العقرد فري‬
‫المخطط‪.‬‬
‫‪ .6‬عملية التحديث تتم في حالة ان يكون المسار من عقدة المصردر)‪ (S‬الرى العقردة‬
‫)‪ (V‬هو اصغر من المسافة )]‪ (d[V‬الموجودة على العقدة )‪ ,(V‬في هذل الحالة‬
‫يتم وضع المسافة الجديدة للعقدة )‪ ,(V‬بخالف ذلك ال تتم عملية التحديث‪.‬‬
‫‪ .7‬ترررتم عمليرررة تنفيرررذ الخوارزميرررة وذلرررك بخرررزن العقررردة فررري طرررابور االفضرررلية‬
‫)‪ (priority queue‬عند قرائتها‪ ,‬بحيث تكون القيمرة المفتاحيرة لكرل عقردة هري‬
‫مسافتها ]‪ .d[V‬فتكون قيمة االفضلية للعقدة )‪ (S‬تساوي صفر‪.‬‬
‫تخررزن المسررافة الررى العقرردة )‪( (S‬والترري هرري صررفر) وجميررع العقررد االخرررى (قيمتهررا‬
‫االبتدائية ما النهاية) في جدول خاص يسمى جدول المسافات‪.‬‬
‫‪ .8‬يررتم ايجرراد العقرردة )‪ (V‬الترري لهررا اقررل قيمررة (مسررافة) مررن الطررابور (سرريكون موقررع‬
‫العقدة المختارة في بداية الطابور)‪ ,‬ويتم ازالتها من الطابور‪.‬‬
‫‪ .9‬نحررردد العقرررد المجررراورة )‪ (W‬للعقررردة )‪ .(V‬لكرررل عقررردة مرررن العقرررد المجررراورة‬
‫للعقدة )‪ (V‬نقوم بما يلي‪:‬‬
‫‪ .A‬حساب المسافة الجديدة من العقدة )‪ (V‬الى العقدة المجاورة )‪.(W‬‬
‫المسافة الجديدة )‪ = (d‬المسافة الى العقدة )‪ + (V‬وزن )‪.(V, W‬‬
‫‪ .B‬اذا كانت المسافة القديمة (المسافة التري خزنرت فري جردول المسرافات) تسراوي (‬
‫∞) (اي انها لم تحسب سابقا) فنقوم بما يلي‪:‬‬
‫‪ .I‬خزن المسافة الجديدة )‪ (d‬في جدول المسافات‪.‬‬
‫‪ .II‬حشر او خزن العقدة )‪ (W‬في طابور االفضلية مع افضلية قيمتها )‪.(d‬‬
‫‪ .III‬خزن ( المسار = ‪) V‬‬
‫‪ .C‬اذا كانت المسافة التي تم حسابها )‪ (d‬اصغر من المسافة القديمة‪ ,‬فنقوم بما يلي‪:‬‬
‫‪ .I‬تحديث المسافة القديمرة للعقردة بحيرث تكرون قيمتهرا تسراوي المسرافة الجديردة‬
‫)‪.(d‬‬
‫‪ .II‬تحديث االفضلية للعقدة )‪ (W‬بحيث تكون قيمتها تساوي )‪.(d‬‬
‫‪ .III‬تحديث المسار الى )‪ (W‬ليكون )‪.(V‬‬

‫‪483‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .10‬يتم فحص الطابور‪ ,‬اذا كان الطابور غير فار ‪ ,‬العودة الى الخطوة (‪ .)8‬اما اذا‬
‫كان الطابور فار فهذا يعني ان عملية ايجاد المسافات االقصر قد انتهت‪.‬‬

‫مثةةال‪ :‬مطلرروب ايجرراد المسررافات االقصررر بررين عقرردة المصرردر )‪ (A‬وجميررع العقررد‬
‫االخرى في المخطط في الشكل ‪.10.65‬‬

‫شك ‪ :10.65‬مالبط موزول مبلوب ايجا اقصر مسافة بين ال قدة ‪ A‬وباقي ال قد‪.‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .1‬اختار العقدة التي لها اقل مسرافة فري القائمرة‪ ,‬واضرح هنرا ان العقردة المصردرهي‬
‫التي لها اقل مسافة وتساوي صفر‪ .‬مجاورات العقدة )‪ (A‬هي )‪.(B, D‬‬

‫شك ‪ :10.66‬المالبط ب د اوتيار ال قدة المصدر وتحديد المجاورات‪.‬‬

‫نقوم بتحديث المسافات لمجاورات هذل العقدة‪ .‬كما في الشكل ‪.10.67‬‬


‫مسافة العقدة )‪.2 = (B‬‬
‫مسافة العقدة )‪.1 = (D‬‬
‫‪ .2‬اختيار العقدة التي لها المسافة االصغر من القائمة (هنا سرتكون العقردة ‪.) D‬‬
‫مجاورات العقدة )‪ (D‬هي )‪.(C, E, F, G‬‬

‫‪485‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.67‬اوتيار ال قدة كات المسافة االصغر‪.‬‬

‫‪ .3‬تحررديث المسررافات للعقررد المجرراورة للعقرردة )‪ .(D‬الحرر هنررا ان المسررافة تقرراس‬


‫اعتبارا من العقردة المصردر )‪ (A‬مررورا بالعقردة )‪ (D‬الرى العقرد المجراورة لهرا‪.‬‬
‫انظر الشكل ‪.10.68‬‬

‫مسافة العقدة )‪.3 = 2 + 1 = (C‬‬


‫مسافة العقدة )‪.3 = 2 + 1 = (E‬‬
‫مسافة العقدة )‪.9 = 8 + 1 = (F‬‬
‫مسافة العقدة )‪.5 = 4 + 1 = (G‬‬

‫شك ‪ :10.68‬المالبط ب د حساب المسافات‪.‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .4‬يتم اختيار العقدة التي لها اقل مسافة من القائمة بعد التحديث وهنا ستكون العقدة‬
‫)‪ .(B‬يتم تحديث مسافات العقد المجاورة لها وهي العقد )‪ .(D, E‬الحر هنرا ان‬
‫المسافة )‪ (D‬ال يتم تحديثها وذلك النها معروفة اساسا‪ ,‬كذلك فان المسافة للعقدة‬
‫)‪ (E‬ال يتم تحديثها الن المسافة الجديدة اكبر من المسافة التي حسبت سابقا‪.‬‬

‫شك ‪ :10.69‬اوتيار ال قدة ‪ B‬وتحديث المسافات‪.‬‬


‫‪ .5‬اختيرار العقردة التري لهرا اقرل مسررافة مرن القائمرة والتري هري العقردة )‪ (E‬وتحرديث‬
‫مسافات المجاورات وهي العقد )‪ .(G‬في هذل الحالة ال يوجد تحديث الن مسافة‬
‫العقدة اصغر من المسافة الجديدة‪ .‬انظر الشكل ‪.10.70‬‬

‫‪487‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪:10.70‬اوتيار ال قد ‪.E‬‬

‫‪ .6‬اختيررار العقرردة الترري لهررا اقررل مسررافة مررن القائمررة وهرري العقرردة )‪ ,(C‬وتحررديث‬
‫مجاوراتها‪ .‬كما في الشكل ‪.10.71‬‬
‫مسافة العقدة )‪.8 = 5 + 3 = (F‬‬

‫شك ‪ :10.71‬اوتيار ال قدة ‪ C‬وتحديث مجاوراتها‪.‬‬


‫‪ .7‬اختيررار العقررردة التررري لهرررا اقرررل مسررافة وهررري العقررردة )‪ (G‬وتحرررديث مجاوراتهرررا‪.‬‬
‫الشكل ‪.10.72‬‬
‫مسافة العقدة )‪ = (F‬القيمة االصغر بين )‪.6 = (8, 5+1‬‬
‫يتم اختيار المسافة االقل بالنسبة للعقدة )‪ ,(F‬حيث ان المسافة السابقة كانت (‪)8‬‬
‫بينما المسافة الحالية هي (‪.)6‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.72‬اوتيار ال قدة ‪ G‬وتحديث المسافات‪.‬‬

‫‪ .8‬اختيار العقدة التي لها اقل مسافة وهي العقدة )‪ (F‬وتحديث المجاورات‪.‬‬

‫شك ‪ :10.73‬اوتيار ال قدة ‪ F‬وتحديث المجاورات‪.‬‬


‫‪ ‬مثةةال اوةةر‪ :‬اكثررر توضرريحا وذلررك باسررتخدام الجررداول لتبسرريط العمررل ومالحظررة‬
‫الفارق مع المثال السابل‪ .‬لردينا المخطرط فري الشركل ‪ 10.74‬والمطلروب حسراب‬
‫اقصر مسار بين العقدة )‪ (V3‬وجميع العقد االخرى‪.‬‬

‫‪489‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫شك ‪ :10.74‬مالبط مبلوب حساب اقصر مسافة بين ال قدة وباقي ال قد‪.‬‬

‫رتررب القرريم االبتدائيررة علررى شرركل جرردول (وهرري القرريم المستسررقاة مررن المخطررط فرري‬
‫الشكل ‪ 10.74‬قبل اجراء اي عملية عليه)‪.‬‬
‫دول ‪ :10.1‬القيم االبتدائية للمالبط في الشك ‪. 10.71‬‬

‫العقد جدول المسافات قوائم المجاورات مع اوزانها‬

‫}‪V2{3}, V4{2‬‬ ‫‪-‬‬ ‫∞‬ ‫‪V1‬‬

‫}‪V5 {8‬‬ ‫‪-‬‬ ‫∞‬ ‫‪V2‬‬

‫}‪V1{6}, V4{3}, V6{19‬‬ ‫‪-‬‬ ‫‪0‬‬ ‫‪V3‬‬

‫}‪V2{4}, V6{7‬‬ ‫‪-‬‬ ‫∞‬ ‫‪V4‬‬

‫}‪V4{1}, V7{2‬‬ ‫‪-‬‬ ‫∞‬ ‫‪V5‬‬

‫}‪V7{4‬‬ ‫‪-‬‬ ‫∞‬ ‫‪V6‬‬

‫}‪V4{5‬‬ ‫‪-‬‬ ‫∞‬ ‫‪V7‬‬

‫م حظة‪:‬‬
‫‪ ‬سيتم استخدام )‪ DT(i, j‬لالشارة الى الخلية في الصف )‪ (i‬والعمود )‪ (j‬في‬
‫جدول المسافات (تمثل المسافة المحسوبة)‪.‬‬
‫‪ ‬كذلك فان )‪ (V:n‬تعني ان المسافة من )‪ (V3‬الى العقدة )‪ (V‬تساوي )‪.(n‬‬
‫‪ (PQ) ‬سيرمز الى طابور االفضلية )‪. (Priority Queue‬‬

‫‪ ‬وبوات الح ‪:‬‬

‫‪ .1‬بدايرررة أخرررزن )‪ (V3:0‬فررري طرررابور االفضرررلية‪ .‬سررريكون الطرررابور علرررى الشررركل‬


‫‪PQ: V3:0‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ .2‬طالما الطابور ليس فارغا اعمل ما لي‪:‬‬


‫‪ .A‬حذف العقدة التي لهرا اقرل قيمرة مرن الطرابور وهري هنرا )‪( (V3‬عرادة العقردة‬
‫التي لها اقل قيمة تكون في اقصى اليسار من طابور االفضلية)‪.‬‬
‫قائمة المجاورات للعقردة )‪ (V3‬هري )}‪ (V1{6}, V4{3}, V6{19‬كمرا‬
‫في الجدول ‪.10.1‬‬
‫لكل واحد من هذل المجاورات أعمل ما يلي‪:‬‬
‫‪ .I‬أقرأ العقدة المجاورة من القائمة }‪( V1{6‬العقدة المجاورة االولى)‪.‬‬
‫أحسب المسافة الى العقدة ‪ V1‬النها لم تحسب من قبل (قيمتها ∞)‪.‬‬ ‫‪‬‬
‫مسافة )‪ = DT(1,1‬المسافة الى )‪ ).. (V3‬ممثلرة فري )‪) DT(3,1‬‬ ‫‪o‬‬
‫‪ +‬الرابط بين )‪( 6 = (V3, V1‬الح هنا ان )‪ DT(3,1‬تساوي صفر)‬
‫سررجل المسررار‪( DT(1, 2) = V3 ,‬سررتمثل الصررف االول النهررا‬ ‫‪‬‬
‫‪ V1‬والعمود الثاني النها تحديث للمسافة في جدول المسافات)‪.‬‬
‫خزن ‪ V1:6‬في الطابور‪.‬‬ ‫‪‬‬
‫وضع الطابور سيكون‬
‫‪PQ: V1:6‬‬
‫‪ .II‬أقرأ العقدة المجاورة الثانية }‪V4{3‬‬
‫‪ ‬أحسب المسافة الى ‪ V4‬النها لم تحسب سابقا‪.‬‬
‫مسرررافة )‪ = DT(4,1‬المسرررافة الرررى )‪ (.. (V3‬متمثلرررة فررري )‪+ ) DT(3,1‬‬
‫الرابط بين )‪3 = (V3, V4‬‬
‫‪ ‬سجل المسار‪DT(4, 2) = V3 ,‬‬
‫‪ ‬خزن ‪ V4:3‬في الطابور‪.‬‬
‫وضع الطابور سيكون‬
‫‪PQ: V4:3, V1:6‬‬

‫‪ .III‬أقرأ العقدة المجاورة الثالثة }‪V6{19‬‬

‫‪491‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ ‬أحسب المسافة الى ‪ V6‬النها لم تحسب سابقا‪.‬‬


‫مسرررافة )‪ = DT(6,1‬المسرررافة الرررى )‪ (.. (V3‬متمثلرررة فررري )‪+ ) DT(3,1‬‬
‫الرابط بين )‪19 = (V3, V6‬‬
‫‪ ‬سجل المسار‪DT(6,2) = V3 ,‬‬
‫‪ ‬خزن ‪ V6:19‬في الطابور‪.‬‬
‫وضع الطابور سيكون‬
‫‪PQ: V4:3, V1:6, V6:19‬‬

‫م حظةةة‪ :‬العناصررر فرري الطررابور مرتبررة حسررب االفضررلية (القيمررة االقررل تمثررل‬
‫افضرلية عليررا)‪ .‬لرذلك فرران عمليرة سررحب عنصرر مررن الطرابور سرريكون دائمرا مررن‬
‫اقصى يسار الطابور‪.‬‬

‫دول ‪ :10.2‬دول المسافات ب د م الجة مجاورات ال قدة ‪.V3‬‬

‫دول المسافات‬ ‫ال قد‬

‫‪V3‬‬ ‫‪6‬‬ ‫‪V1‬‬

‫∞‬ ‫‪V2‬‬

‫‪0‬‬ ‫‪V3‬‬

‫‪V3‬‬ ‫‪3‬‬ ‫‪V4‬‬

‫∞‬ ‫‪V5‬‬

‫‪V3‬‬ ‫‪19‬‬ ‫‪V6‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫∞‬ ‫‪V7‬‬

‫‪ .B‬يرررتم سرررحب وازالرررة عقررردة مرررن بدايرررة الطرررابور وسرررتكون العقررردة ( ‪,)V4:3‬‬
‫مجاورات هذل العقدة هي (}‪ ,)V2{4}, V6{7‬لكل واحد من مجاورات العقردة‬
‫‪ V4‬قم باالعمال التالية‪:‬‬

‫‪ .I‬أقرأ العقدة المجاورة االولى }‪V2{4‬‬


‫‪ ‬أحسب المسافة الى ‪ V2‬النها لم تحسب سابقا‪.‬‬
‫مسررررافة )‪ = DT(2,1‬المسررررافة الررررى )‪( ..(V4‬متمثلررررة فرررري )‪+ ) DT(4,1‬‬
‫الرابط بين )‪7 = (V4, V2‬‬
‫‪ ‬سجل المسار‪DT(2,2) = V4 ,‬‬
‫‪ ‬خزن ‪ V2:7‬في الطابور‪.‬‬
‫وضع البابور سيكول‬
‫‪PQ: V1:6, V2:7, V6:19‬‬
‫‪ .II‬أقرا العقدة المجاورة الثانية }‪V6{7‬‬
‫‪ ‬المسافة الى ‪ V6‬هي ‪ .19‬وهي اكبر من المسافة الى ‪ V4‬مضراف لهرا وزن‬
‫الرابط )‪ ,(V4, V6‬ولذلك يجب ان تحدث (عندما تكون المسرافة المحسروبة‬
‫اكبرر مررن مسرافة العقرردة فيجررب ان يرتم تحررديثها‪ ,‬امررا اذا كانرت اصررغر فتتررر‬
‫بدون تحديث)‪.‬‬
‫مسرررافة )‪ = DT(6,1‬المسرررافة الرررى )‪ ( ..(V4‬متمثلرررة فررري )‪+ ) DT(4,1‬‬
‫الرابط بين )‪10 = (V4, V6‬‬
‫(المسافة )‪ DT(4,1‬تساوي ‪ ,3‬الح الجدول ‪.)10.2‬‬
‫‪ ‬سجل المسار‪DT(6,2) = V4 ,‬‬
‫‪ ‬حدث االفضلية للعقدة ‪ V6‬في طابور االفضرلية لتكرون قيمتهرا الجديردة هري‬
‫‪.10‬‬

‫‪493‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪PQ: V1:6, V2:7, V6:10‬‬ ‫وضع الطابور سيكون‬

‫دول ‪ :10.3‬دول المسافات ب د م الجة مجاورات ال قدة ‪.V4‬‬

‫دول المسافات‬ ‫ال قد‬

‫‪V3‬‬ ‫‪6‬‬ ‫‪V1‬‬

‫‪V4‬‬ ‫‪7‬‬ ‫‪V2‬‬

‫‪0‬‬ ‫‪V3‬‬

‫‪V3‬‬ ‫‪3‬‬ ‫‪V4‬‬

‫∞‬ ‫‪V5‬‬

‫‪V4‬‬ ‫‪10‬‬ ‫‪V6‬‬

‫∞‬ ‫‪V7‬‬
‫‪ .C‬يتم سحب وازالة عقدة من بدايرة الطرابور وسرتكون العقردة ( ‪ ,)V1:6‬مجراورات‬
‫هذل العقدة هي (}‪ .)V2{3}, V4{2‬لكل واحد من مجاورات العقدة ‪ V1‬اعمرل‬
‫ما يلي‪:‬‬
‫أقرأ العقدة المجاورة }‪V2{3‬‬ ‫‪.I‬‬
‫المسررافة الررى العقرردة ‪ V2‬تررم حسررابها سررابقا وهرري تسرراوي ‪ 7‬وهرري‬ ‫‪‬‬
‫اصغر مرن المسرافة ( الرى ‪ + V1‬وزن الررابط برين العقردتين = ‪(V1, V2‬‬
‫)‪ ,)6+3‬لذلك ال تعمل اي شيء‪.‬‬

‫أقرأ العقدة المجاورة االخرى }‪V4{2‬‬ ‫‪.II‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫المسررافة الررى العقرردة ‪ V4‬تررم حسررابها سررابقا وهرري تسرراوي ‪ ,3‬وهرري‬ ‫‪‬‬
‫اصغر من المسافة ( الى ‪ V1‬يضاف لها وزن الررابط برين العقردتين ‪(V1,‬‬
‫)‪ ,)V4 = 6+2‬لذلك ال تعمل اي شيء‪.‬‬

‫‪PQ: V2:7, V6:10‬‬ ‫وضع الطابور سيكون‬

‫‪ .D‬يتم سحب وازالة عقدة من بداية الطابور وسرتكون العقردة ( ‪ ,)V2:7‬مجراورات‬


‫هذل العقدة هي (}‪ .)V5{8‬لكل واحد من مجاورات العقدة ‪ V2‬تجرى االعمرال‬
‫التالية‪:‬‬
‫أقرأ العقدة المجاورة }‪V5{8‬‬ ‫‪.I‬‬
‫أحسب المسافة الى ‪ V5‬النها لم تحسب سابقا‪.‬‬ ‫‪‬‬
‫مسرررافة )‪ = DT(5,1‬المسرررافة الرررى )‪ ( ..(V2‬متمثلرررة فررري )‪+ ) DT(2,1‬‬
‫الرابط بين )‪15 = (V2, V5‬‬
‫(المسافة )‪ DT(2,1‬تساوي ‪ 7‬كما في الجول ‪.)10.3‬‬
‫سجل المسار‪DT(5,2) = V2 ,‬‬ ‫‪‬‬
‫خزن ‪ V5:15‬في طابور‪.‬‬ ‫‪‬‬
‫‪PQ: V6:10, V5:15‬‬ ‫وضع الطابور هو‬

‫دول ‪ :10.4‬دول المسافات ب د م الجة مجاورات ال قدة ‪.V2‬‬

‫دول المسافات‬ ‫ال قد‬

‫‪V3‬‬ ‫‪6‬‬ ‫‪V1‬‬

‫‪V4‬‬ ‫‪7‬‬ ‫‪V2‬‬

‫‪0‬‬ ‫‪V3‬‬

‫‪495‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪V3‬‬ ‫‪3‬‬ ‫‪V4‬‬

‫‪V2‬‬ ‫‪15‬‬ ‫‪V5‬‬

‫‪V4‬‬ ‫‪10‬‬ ‫‪V6‬‬

‫∞‬ ‫‪V7‬‬

‫‪PQ: V6:10, V5:15‬‬ ‫وضع البابور‬

‫‪ .E‬يررتم سررحب وازالررة عقرردة مررن بدايررة الطررابور وسررتكون العقرردة ( ‪,)V6:10‬‬
‫مجاورات هذل العقردة هري (}‪ .)V7{4‬لكرل واحرد مرن مجراورات العقردة ‪ V6‬قرم‬
‫باالعمال التالية‪:‬‬
‫أقرا العقدة المجاورة }‪V7{4‬‬ ‫‪.I‬‬
‫أحسب المسافة الى ‪ V7‬النها لم تحسب سابقا‪.‬‬ ‫‪‬‬
‫مسرررافة )‪ = DT(7,1‬المسرررافة الرررى )‪( .. (V6‬متمثلرررة فررري )‪+ ) DT(6,1‬‬
‫الرابط بين )‪14 = (V6, V7‬‬
‫سجل المسار‪DT(7,2) = V6 ,‬‬ ‫‪‬‬
‫خزن ‪ V7:14‬في طابور‪.‬‬ ‫‪‬‬
‫‪PQ: V7:14, V5:15‬‬ ‫وضع الطابور سيكون‬

‫دول ‪ :10.5‬دول المسافات ب د م الجة مجاورات ال قدة ‪.V6‬‬

‫دول المسافات‬ ‫ال قد‬

‫‪V3‬‬ ‫‪6‬‬ ‫‪V1‬‬

‫‪V4‬‬ ‫‪7‬‬ ‫‪V2‬‬


‫هياكل البيانات باستخدام ‪C++‬‬

‫‪0‬‬ ‫‪V3‬‬

‫‪V3‬‬ ‫‪3‬‬ ‫‪V4‬‬

‫‪V2‬‬ ‫‪15‬‬ ‫‪V5‬‬

‫‪V4‬‬ ‫‪10‬‬ ‫‪V6‬‬

‫‪V6‬‬ ‫‪14‬‬ ‫‪V7‬‬

‫‪PQ: V7:14, V5:15‬‬ ‫وضع البابور‬

‫‪ .F‬يررتم سررحب وازالررة عقرردة مررن بدايررة الطررابور وسررتكون العقرردة (‪,)V7:14‬‬
‫مجرراورات هررذل العقرردة هرري (}‪ .)V4{5‬لكررل واحررد مررن مجرراورات العقرردة ‪V7‬‬
‫تجرى االعمال التالية‪:‬‬
‫أقرا العقدة المجاورة }‪V4{5‬‬ ‫‪.I‬‬
‫المسرافة الرى العقردة ‪ V4‬ترم حسرابها سرابقا وهري تسراوي ‪ ,3‬وهري‬ ‫‪‬‬
‫اصغر من المسافة الى العقدة ‪ + V7‬وزن الرابط بين العقدتين‬
‫)‪ ,(V7, V4 = 14+5 = 19‬لذلك ال تعمل اي شيء‪.‬‬
‫‪ ‬الجدول سوف ال يتغير‬
‫‪PQ: V5:15‬‬ ‫وضع البابور سيكول‬

‫‪ .G‬يررتم سررحب وازالررة عقرردة مررن بدايررة الطررابور وسررتكون العقرردة (‪,)V5:15‬‬
‫مجاورات هذل العقدة هي (}‪ .)V4{1}, V7{2‬لكل واحد من مجاورات العقردة‬
‫‪ V5‬قم باالعمال التالية‪:‬‬
‫أقرأ العقدة المجاورة االولى }‪V4{1‬‬ ‫‪.I‬‬

‫‪497‬‬
‫هياكل البيانات باستخدام ‪C++‬‬

‫‪ ‬المسافة الى العقدة ‪ V4‬تم حسابها سابقا وهي تساوي ‪ ,3‬وهري اصرغر مرن‬
‫المسافة الرى ‪ + V5‬وزن الررابط برين العقردتين )‪,(V5, V4 = 15+1=16‬‬
‫لذلك ال تعمل اي شيء‪.‬‬

‫أقرأ العقدة المجاورة الثانية }‪V7{2‬‬ ‫‪.II‬‬


‫‪ ‬المسافة الى العقردة ‪ V7‬ترم حسرابها سرابقا وهري تسراوي ‪ ,14‬وهري اصرغر‬
‫من المسافة الى ‪ + V5‬وزن الرابط بين العقدتين‬
‫)‪ ,(V5, V7 = 15+2 = 17‬لذلك ال تعمل اي شيء‪.‬‬

‫‪ .3‬االن الطابور فار ‪ ,‬وهذل داللة على انتهاء عمليات المعالجة‪.‬‬

‫ان اقصر المسالك بين العقدة ‪ V3‬وباقي العقد في المخطط هي في الجدول ‪.10.6‬‬

‫دول ‪ :10.6‬دول المسافات بين ال قدة ‪ V3‬وك عقدة اورى في المالبط‪.‬‬

‫دول المسافات المسلو الكام‬ ‫ال قد‬

‫‪V3 V1‬‬ ‫‪V3‬‬ ‫‪6‬‬ ‫‪V1‬‬

‫‪V3 V4 V2‬‬ ‫‪V4‬‬ ‫‪7‬‬ ‫‪V2‬‬

‫‪0‬‬ ‫‪V3‬‬
C++ ‫هياكل البيانات باستخدام‬

V3 V4 V3 3 V4

V3 V4 V2 V5 V2 15 V5

V3 V4 V6 V4 10 V6

V3 V4 V6 V7 V6 14 V7

Dijkstra's ‫ برنامج خوارزمية‬

/* Dijkstra's Algorithm in C */

#include<stdio>

#include<conio>

#include<process>

#include<string>

#include<math>

#define IN 99

#define N 6

using namespace std ;

int dijkstra(int cost[][N], int source, int target);

int main()

int cost[N][N],i,j,w,ch,co;

int source, target,x,y;

for(i=1;i< N;i++)

499
C++ ‫هياكل البيانات باستخدام‬

for(j=1;j< N;j++)

cost[i][j] = IN;

for(x=1; x< N; x++)

for(y=x+1; y< N; y++)

cout<< "Enter the weight of the path between nodes "<< x<< y ;
cin>> w ;

cost [x][y] = cost[y][x] = w;

cout << endl ;

cout<< "\nEnter the source:" ;

cin>> source ;

cout<< "\nEnter the target" ;

cin>> target ;

co = dijsktra(cost,source,target);

cout<< "\nThe Shortest Path: " << co ;

int dijsktra(int cost[][N],int source,int target)

int dist[N],prev[N],selected[N]={0},i,m,min,start,d,j;
C++ ‫هياكل البيانات باستخدام‬

char path[N];

for(i=1;i< N;i++)

dist[i] = IN;

prev[i] = -1;

start = source;

selected[start]=1;

dist[start] = 0;

while(selected[target] ==0)

min = IN;

m = 0;

for(i=1;i< N;i++)

d = dist[start] +cost[start][i];

if(d< dist[i]&&selected[i]==0)

dist[i] = d;

prev[i] = start;

if(min>dist[i] && selected[i]==0)

501
C++ ‫هياكل البيانات باستخدام‬

min = dist[i];

m = i;

start = m;

selected[start] = 1;

}
start = target;

j = 0;

while(start != -1)

path[j++] = start+65;

start = prev[start];

path[j]='\0';

strrev(path);

cout<< path ;

return dist[target];

}
C++ ‫هياكل البيانات باستخدام‬

REFRENCES ‫المصا ر‬

1. Adam Drozdek, “Data Structures and Algorithms in


C++”, 4th edition, Published by Cengage Learning, USA,
2013.

503
C++ ‫هياكل البيانات باستخدام‬

2. Clifford A. Shaffer, “A Practical Introduction to Data


Structures and Algorithm Analysis”, 3rd edition,
Published by Dover Publications, 2012.

3. D.S. Malik, “Data Structures Using C++”, 2nd Edition,


Published by Cengage Learning, 2010.

4. Harry H. Chaudhary, “Data Structures Using C


Language 2014. Perfect Beginners guide”,
Createspace O-D Publishing LLC-USA, 2014.

5. James Robergé, Stefan Brandle, David Whittington, “A


Laboratory Course in C++ Data Structures”, 2nd
edition, Jones and Bartlett Publishers, 2003.

6. Jörg Arndt, “Matters Computational Ideas, Algorithms,


Source Code”, Springer-Verlag Berlin Heidelberg ,
2011, DOI: 10.1007/978-3-642-14764-7.

7. Mark Allen Weiss, “Data Structures and Algorithm


Analysis in C++”, 2nd edition, Pearson Education
International, 2014.
C++ ‫هياكل البيانات باستخدام‬

8. Michael T. Goodrich, Roberto Tamassia, David M.


Mount, “Data Structures and Algorithms in C++”,
2nd Edition, John Wiley & Sons, 2011.

9. Neel Dale, “C++ Plus Data Structure”, 4th edition,


Jones and Bartlett Publishers, 2007.

10. Radhika Raju Palagiri, Ananda Rao Akepogu, “Data


Structures and Algorithms Using C++”, Pearson India,
2010.

11. Robert Lafore, “Data Structures & Algorithms in


Java”, 2nd edition, Sams Publishing, 2003.

12. Robert Sedgewick and Kevin Wayne, “Algorithms”, 4th


edition, published by Addison-Wesley, 2011.

13. Vinu Das, “Principles of Data Structures Using C and


C++”, Published by New Age, 2006.

‫ مؤسسرة دار‬, ‫ مة الدااةة الةى الدرمجة الييانية‬C++ ,‫نضال العبرادي‬ .14


.2011 ,‫الصادق الثقافية باالشتراك مع دار الصفاء‬

505
1

You might also like