The words you are searching are inside this book. To get more targeted content, please make full-text search by clicking here.

ترجمة لدرس تعلّم البرمجة بلغة السي الخاص بموقع OpenClassrooms

Discover the best professional documents and content resources in AnyFlip Document Base.
Search
Published by Hamza Abbad, 2017-08-03 11:01:25

تعلّم البرمجة بلغة C

ترجمة لدرس تعلّم البرمجة بلغة السي الخاص بموقع OpenClassrooms

‫الطوابير )‪(Queues‬‬

‫إنشاء نظام طابور‬

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

‫سننشئ هيكل ‪ Element‬و هيكل تحكّم ‪: Queue‬‬

‫;‪1 typedef struct Element Element‬‬

‫‪2 struct Element‬‬

‫{‪3‬‬

‫;‪4 int number‬‬

‫‪5‬‬ ‫;‪Element *next‬‬
‫;} ‪6‬‬

‫;‪7 typedef struct Queue Queue‬‬

‫‪8 struct Queue‬‬

‫{‪9‬‬

‫‪10‬‬ ‫;‪Element *first‬‬
‫;} ‪11‬‬

‫تماما كالمكدّسات‪ ،‬كل عنصر من الطابور سيكون من نوع ‪ . Element‬بالإستعانة بالمؤش ّر ‪first‬‬
‫سنتوف ّر دائما ًعلى العنصر الأول و يمكننا من خلاله الصعود إلى آخر عنصر‪.‬‬

‫إضافة عنصر إلى الطابور )‪(enqueuing‬‬
‫الدالة التي تضيف عُنص ُرا ً إلى الطابور تسمّى دالة ”الإلحاق” )‪ .(enqueuing‬توجد حالتان ‪:‬‬

‫• إما أن الطابور فارغ‪ ،‬في هذه الحالة يجب أن ننشئ الطابور بجعل المؤش ّر ‪ first‬يؤش ّر نحو العنصر الجديد‬
‫الذي نحن بصدد انشائه‪.‬‬

‫• إما أن الطابور غير فارغ‪ ،‬في هذه الحالة يجب أن نتق ّدم في الطابور إنطلاقا ًمن العنصر الأول حتى نصل‬
‫إلى آخر عنصر‪ .‬نضيف العنصر الجديد بعد آخر عنصر‪.‬‬

‫إليك ما يمكننا فعله عمليا ً‪:‬‬

‫)‪1 void enqueue(Queue *q, int newNumber‬‬
‫{‪2‬‬

‫‪3‬‬ ‫;))‪Element *new = malloc(sizeof(*new‬‬
‫‪4‬‬
‫)‪if (new == NULL || new== NULL‬‬

‫{‪5‬‬

‫;)‪6 exit(EXIT_FAILURE‬‬

‫}‪7‬‬

‫;‪8 new−>number = newNumber‬‬

‫;‪9 new−>next = NULL‬‬

‫‪501‬‬

10 (Stacks and Queues) ‫ المكدّسات و الطوابير‬.2.‫الفصل د‬
11
12 if (q−>first != NULL) // The queue is not empty
13 {
14
15 // We move to the end of the queue
16
17 Element *currentElement = q−>first;
18
19 while (currentElement−>next != NULL)
20 {
21
22 currentElement= currentElement−>next;
23 }
24 } currentElement−>next = new;
}

else /* The queue is empty, it’s our first element */

{
q−>first = new;

}

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

.‫ هذا ما يمكنك ملاحظته‬،‫ كافية للقيام باللازم‬while ‫ لـكن لابأس فحلقة‬.‫الجديد‬

(dequeuing) ‫إزالة عنصر من الطابور‬

،‫ بامتلاكنا مؤش ّرا نحو أول عنصر من الطابور‬.‫( تشابه كثيرا ًعملية إلغاء التكديس‬dequeuing) ‫عملية إلغاء الإلحاق‬
.‫يكفي أن ننزعه و أن ن ُرجع قيمته‬

1 dequeue(Queue *queue)
2{

3 if (queue == NULL)

4{

5 exit(EXIT_FAILURE);

6}

7 int dequeuedNumber = 0;

8 // We verify if there’s something to dequeue

9 if (queue−>first != NULL)

10 {

11 Element *dequeuedElement = queue−>first;
12
dequeuedNumber = dequeuedElement−>number;

13 queue−>first = dequeuedElement−>next;

14 free(dequeuedElement);

15 }

16 return dequeuedNumber;

17 }

502

‫مل ّخص‬

‫حان دورك !‬

‫تبقى دالة إظهار محتوى الطابور ‪ displayQueue‬و عملها مشابه لما قمنا به مع المكدّسات‪ .‬سيسمح لك هذا‬
‫بالتأكد من سلامة عمل الطابور‪.‬‬

‫قم بعد ذلك بكتابة ‪ main‬من أجل تجريب البرنامج‪ .‬يجدر بنتيجة البرنامج أن تشبه هذه ‪:‬‬

‫‪Queue’s state :‬‬
‫‪4 8 15 16 23 42‬‬

‫‪I dequeue 4‬‬
‫‪I dequeue 8‬‬

‫‪Queue’s state :‬‬
‫‪15 16 23 42‬‬

‫يجدر أن تكون قادرا ً على إنشاء مكتبة الطوابير الخاصة بك‪ ،‬بملفات ‪ queue.h‬و ‪ queue.c‬مثلا ً‪.‬‬
‫أقترح عليك تنز يل مشروع التحكّم في الطوابير كاملا ًإن أردت‪ .‬إنه يتضمّن الدالة ‪: displayQueue‬‬

‫‪http://www.siteduzero.com/uploads/fr/ftp/mateo21/c/files.zip‬‬

‫مل ّخص‬

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

‫• في حالة المكدّسات‪ ،‬تتم إضافة المعطيات الواحدة فوق الأخرى‪ .‬و إن أردنا استخراج بيانة‪ ،‬فسنستخرج‬
‫آخر واحدة و التي كنا بصدد إضافتها )الأحدث(‪ .‬نت ّكلم هنا عن خوارزمية ‪.(Last In First Out) LIFO‬‬
‫• في حالة الطوابير‪ ،‬تتم إضافة المعطيات الواحدة بعد الأخرى‪ .‬نقوم باستخراج البيانة الأولى و التي قمنا‬

‫بإضافتها أولا للطابور )الأقدم(‪ .‬نتكل ّم عن خوارزمية ‪.(First In First Out) FIFO‬‬

‫‪503‬‬

‫الفصل د‪ .2.‬المكدّسات و الطوابير )‪(Stacks and Queues‬‬
‫‪504‬‬

‫الفصل د‪3.‬‬

‫جداول التجزئة )‪(Hash tables‬‬

‫للقوائم المتسلسلة نقطة ضعف كبيرة في حال أردنا قراءة محتواها ‪ :‬يستحيل الوصول إلى عنصر معي ّن مباشرة‪.‬‬
‫يجب التق ّدم في القائمة عنصرا ً بعنصر حتى نجد العنصر الذي نريد‪ .‬هذا يطرح مشاكل من ناحية الأداء ما إن‬
‫يكون حجم القائمة المتسلسلة ضخما ً‪ .‬تخي ّل قائمة متسلسلة ٺتكوّن من ‪ 1000‬عنصر بينما العنصر الذي نبحث عنه‬

‫موجود في آخرها !‬
‫تمث ّل جداول التجزئة طر يقة أخرى لتخزين البيانات‪ .‬حيث أنها تستند على مبدأ الجداول في لغة الـ‪ C‬و التي‬
‫نعرف التعامل معها جي ّدا ً‪ .‬ماهي فائدتها الـكُبرى ؟ هي تسمح بإيجاد سر يع لعنصر محدد‪ ،‬سواء كان الجدول‬

‫يحتوي ‪ 10000 ،1000 ،100‬خانة أو حتى أكثر !‬

‫د‪ 1.3.‬لماذا نستعمل جدول تجزئة ؟‬

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

‫لـكن‪ ،‬كما قل ُت لك في المق ّدمة‪ ،‬للقوائم المتسلسلة عيب كبير ‪ :‬إذا أردنا استرجاع عنصر محدد من القائمة‪،‬‬
‫يجب تص ّفح هذه الأخيرة حتى نجد ذلك العنصر !‬

‫تخي ّل قائمة متسلسلة تحتوي معلومات حول التلاميذ ‪ :‬الإسم‪ ،‬الع ُمر و المع ّدل‪ .‬سيتم تمثيل ك ّل تلميذ بهيكل‬
‫نسميه ‪. Student‬‬

‫عملنا سابقا ًعلى القوائم المتسلسلة التي تحتوي على ‪ . int‬كما قل ُت لك‪ ،‬من الممكن تخزين أي شيء نريد‬
‫في قائمة‪ ،‬حتى مؤشّرا ً نحو هيكل آخر كما سأقترحه لك الآن‪.‬‬

‫إذا أرد ُت الوصول إلى المعلومات الخاصة بالشخص ‪ Luc Doncieux‬في الصورة الموالية‪ ،‬يجب عليّ التق ّدم‬
‫في ك ّل القائمة كي أكتشف بأنه العنصر الأخير فيها !‬

‫‪505‬‬

‫الفصل د‪ .3.‬جداول التجزئة )‪(Hash tables‬‬

‫بالفعل‪ ،‬لو أننا بحثنا عن الشخص ‪ ،Julien Lefebvre‬كان البحث ليكون أسرع بما أنه متواجد في بداية‬
‫القائمة‪ .‬و مع ذلك‪ ،‬لتقييم كفاءة الخوارزمية‪ ،‬يجب أن نفكّر دائما ًفي أسوء الحالات‪ .‬و الأسوء هو ‪Luc‬‬

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

‫‪ 9‬عناصر‪ ،‬يجب أن يتم تشغيل ‪ 9‬دورات للحلقة كحد أقصى لإيجاد العنصر‪.‬‬

‫في هذا المثال‪ ،‬لا تحتوي القائمة المتسلسلة سوى على أربعة عناصر‪ .‬سيجد الحاسوب الشخص ‪Luc Doncieux‬‬
‫بسرعة كبيرة لا تسمح لنا حتى بأن نقول كلمة ”أووه”‪ .‬لـكن تخي ّل أن هذا الشخص يتواجد في آخر قائمة متسلسلة‬
‫من ‪ 10000‬عنصر ! ليس مقبولا أن يتم البحث في ‪ 10000‬عنصر لإيجاد المعلومة‪ .‬هنا ٺتدخّل جداول التجزئة‪.‬‬

‫د‪ 2.3.‬ماهي جداول التجزئة ؟‬

‫إذا كنت ٺتذكر جيدا ً‪ ،‬لا تعرف الجداول هذا النوع من المشاكل‪ .‬لهذا‪ ،‬كي نصل إلى العنصر في الوضعية‬
‫‪ 2‬من الجدول تكفيني كتابة التالي ‪:‬‬

‫;}‪1 int table[4] = {12, 7, 14, 33‬‬
‫;)]‪2 printf(”%d”, table[2‬‬

‫لو نعطي للحاسوب ]‪ ، table[2‬فسيتوجّه مباشرة إلى المكان في الذاكرة أين هو مخز ّن العدد ‪ .14‬أي أنه‬
‫لن يتق ّدم في الجدول خانة بخانة‪.‬‬

‫هل أنت بصدد القول أن الجداول ليست ”بذلك القدر من السوء” ؟ لـكن في هذه الحالة سنخسر الميزات‬
‫التي توف ّرها القوائم المتسلسلة التي تسمح لنا بإضافة و إزالة خانات في أي لحظة !‬

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

‫يوجد عيب في استعمال الجداول لم نتكل ّم عنه سابقا ً ‪ :‬يتم تعر يف خانات الجدول عن طر يق أرقام نسمّيها‬
‫الر ّتب أو الدلالات )‪ .(indices‬لا يمكن أن نطلب من الحاسوب ‪” :‬ماهي المعلومات المتواجدة في الخانة التي‬

‫تسمّى ”‪ .”Luc Doncieux‬أي أننا لإيجاد الع ُمر و المع ّدل لن نتم ّكن من كتابة ‪:‬‬

‫‪506‬‬

‫ماهي جداول التجزئة ؟‬
‫;]”‪1 table[”Luc Doncieux‬‬

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

‫كما رأينا مؤ ّخرا ً‪ .‬لا تش ّكل جداول التجزئة ”جزء ً” من لغة الـ‪ .C‬نتح ّدث هنا عن مبدأ‪ .‬سنعيد استعمال‬
‫أساسيات لغة الـ‪ C‬التي نعرفها من قبل لأجل إنشاء نظام ذكي جديد‪ .‬و كأنه في لغة الـ‪ ،C‬باستعمال‬

‫بعض الأدوات القاعدية‪ ،‬يمكننا إنشاء الـكثير من الأشياء !‬
‫بما أنه من الواجب أن يتم ترقيم الجدول بال ُر ّتب‪ ،‬كيف سنجد رقم الخانة لو أننا نعرف الاسم ”‪Luc‬‬

‫‪ ”Doncieux‬فقط ؟‬
‫ملاحظة جيدة‪ .‬في الواقع‪ ،‬يبقى الجدول جدولا ًو لن يعمل إلا بالر ّتب المرق ّمة‪ .‬تخي ّل جدولا ًيوافق الصورة‬
‫الموالية ‪ :‬كل خانة لها رتبة و ٺتوفر على مؤش ّر نحو هيكل من نوع ‪ . Student‬أنت تعرف القيام بهذا الآن ‪:‬‬

‫لو أردنا إيجاد الخانة التي توافق ‪ ،Luc Doncieux‬يجب أن نجيد تحو يل الإسم إلى رُتبة في الجدول‪ .‬و بهذا‪،‬‬
‫يجب أن نتم ّكن من ربط ك ّل اسم برقم من خانة في الجدول ‪:‬‬
‫• ‪.0 = Julien Lefebvre‬‬
‫‪507‬‬

‫الفصل د‪ .3.‬جداول التجزئة )‪(Hash tables‬‬
‫• ‪.1 = Aurélie Bassoli‬‬
‫• ‪.2 = Yann Martinez‬‬
‫• ‪.3 = Luc Doncieux‬‬

‫لا يمكننا أن نكتب ]”‪ table[”Luc Doncieux‬كما فعل ُت سابقا ً‪ .‬لأن هذا غير مسموح به في لغة‬
‫الـ‪.C‬‬

‫السؤال الذي ي ُطرح هو ‪ :‬كيف نحوّل سلسلة محارف إلى عدد ؟ هذا هو سحر التجزئة‪ .‬تجب كتابة دالة تأخذ‬
‫كمعامل سلسلة محارف‪ ،‬تطب ّق حسابات عليها‪ ،‬ثم ت ُرجع لنا عددا ً يوافق تلك السلسلة‪ .‬سيكون هذا العدد هو‬

‫رتبة الخانة في الجدول ‪:‬‬

‫د‪ 3.3.‬كتابة دالة تجزئة‬

‫تكمن ك ّل الصعوبة في كتابة دالة تجزئة صحيحة‪ .‬كيف نحوّل سلسلة ً محرفي ّة إلى عدد وحيد ؟‬
‫أولا و قبل ك ّل شيء‪ ،‬لنوضح الأمور ‪ :‬جدول التجزئة لا يحتوي ‪ 4‬خانات كما أضع في الأمثلة‪ ،‬لـكن ‪100‬‬

‫أو ‪ 1000‬أو أكثر‪ .‬لا يهم حجم الجدول‪ ،‬لأن البحث سيكون سر يعا ًجدا ً دائما‪.‬‬
‫نقول أن هذا تعقيد بـدرجة )‪ O(1‬لأننا نجد مباشرة عنصر البحث‪ .‬في الواقع‪ ،‬دالة التجزئة سترجع لنا‬

‫رُتبة ‪ :‬يكفي ”القفز” مباشرة إلى الخانة الموافقة للجدول‪ .‬لسنا بحاجة إلى تص ّفح ك ّل الخانات !‬
‫تخي ّل إذا ً جدولا ًمن ‪ 100‬خانة‪ ،‬تقوم فيه بتخزين مؤش ّرات نحو هياكل من نوع ‪. Student‬‬
‫;]‪1 Student* table[100‬‬

‫‪508‬‬

‫كتابة دالة تجزئة‬

‫يجب علينا أن نكتب دالة‪ ،‬انطلاقا ًمن اسم‪ ،‬تول ّد عددا ً محصورا ً بين ‪ 0‬و ‪) 99‬رُتب الجدول(‪ .‬هنا يتطل ّب‬
‫منا الأمر الحذاقة‪ .‬توجد ُطرق ر ياضية ج ّد مع ّقدة كي ”نجز ّء” البيانات‪ ،‬أي أن نحوّلها إلى أعداد‪.‬‬

‫الخوارزميتان ‪ MD5‬و ‪ SHA1‬هما دالتا تجزئة مشهورتان‪ ،‬لـكنهما متق ّدمتان كثيرا بالنسبة لنا حاليا ً‪.‬‬

‫يمكنك اختراع دالة التجزئة الخاصة بك‪ .‬هنا‪ ،‬لـكي نب ّسط الأمور‪ ،‬أقترح عليك ببساطة أن تجمع القيم ‪ASCII‬‬
‫لك ّل حرف من الاسم‪ ،‬أي من أجل الاسم ‪ Luc Doncieux‬ستكون لدينا عملية الجمع التالية ‪:‬‬

‫’‪1 ’L’ + ’u’ + ’c’ + ’ ’ + ’D’ + ’o’ + ’n’ + ’c’ + ’i’ + ’e’ + ’u’ + ’x‬‬

‫سيكون لدينا مشكل ‪ :‬هذا المجموع يتخ ّطى الـ‪ ! 100‬بما أن الجدول الذي أنشأناه لا يحتوي سوى على ‪100‬‬
‫خانة‪ ،‬فإن أخذنا بهذه القيمة فسنخاطر بالخروج من حدود الجدول‪.‬‬

‫أذكّرك بأن ك ّل محرف في جدول ‪ ASCII‬يمكن أن يكون مرق ّما حت ّى ‪ .255‬و بهذا سنتجاوز بسرعة حاجز الـ‪.100‬‬

‫لح ّل هذا المشكل‪ ،‬يمكننا استعمال عامل الترديد ‪ . %‬هل ٺتذكره ؟ إن ّه يعطي باقي القسمة ! لو نقوم بهذا‬
‫الحساب ‪:‬‬

‫‪1 lettersSum % 100‬‬

‫سنتح ّصل قطعا ًعلى عدد محصور بين ‪ 0‬و ‪ .99‬مثلا ً‪ ،‬لو أن المجموع يساوي ‪ ،4315‬باقي القسمة على ‪100‬‬
‫هو ‪ .15‬ست ُرجع إذا دالة التجزئة القيمة ‪.15‬‬

‫إليك ما يمكن أن تكون عليه الدالة ‪:‬‬
‫)‪1 int hash(char *string‬‬
‫{‪2‬‬
‫;‪3 int i = 0, hashNumber= 0‬‬
‫)‪4 for (i = 0 ; string[i] != ’\0’ ; i++‬‬
‫{‪5‬‬
‫;]‪6 hashNumber += string[i‬‬
‫}‪7‬‬
‫;‪8 hashNumber %= 100‬‬
‫;‪9 return hashNumber‬‬
‫} ‪10‬‬

‫لو نعطيها )”‪ ، hash(”Luc Doncieux‬ست ُرجع لنا القيمة ‪ .55‬و بـ )”‪، hash(”Yann Martinez‬‬
‫نتح ّصل على ‪.80‬‬

‫بفضل دالة التجزئة هذه‪ ،‬يمكنك أن تعرف في أي خانة من الجدول يجب أن تضع المعلومات ! إذا أردت‬
‫الوصول إلى هذه الخانات لاحقا ًلاسترجاع المعلومة‪ ،‬تكفي ”تجزئة” اسم الشخص من جديد لـكي نجد رُتبة الخانة‬

‫في الجدول أين تخز ّن المعلومات !‬

‫أنصحك بإنشاء دالة بحث ٺتك ّفل بتجزئة المفتاح )الاسم( و ت ُرجع لنا مؤشّرا ً نحو المعلومات التي نبح ُث عنها‪.‬‬
‫هذا سيعطينا مثلا ‪:‬‬

‫‪509‬‬

‫الفصل د‪ .3.‬جداول التجزئة )‪(Hash tables‬‬

‫;)”‪1 infoAboutLuc = findHashTable(table, ”Luc Doncieux‬‬

‫د‪ 4.3.‬معالجة التصادمات )‪(Collisions management‬‬

‫حينما ت ُرجع دالة التجزئة نفس العدد من أجل مفتاحين مختلفين‪ ،‬نقول أن ّه حدث تصادم‪ .‬مثلا في دالتنا‪،‬‬
‫لو أننا نملك شخصا ً اسمه تحر يك أحرف لـ‪ ،Luc Doncieux‬مثلا ً ‪ ،Luc Doncueix‬سيكون مجموع الأحرف هو‬

‫نفسه‪ ،‬و بهذا فإن نتيجة دالة التجزئة ستكون نفسها !‬
‫يمكن لسببين أن يشرحا التصادم ‪:‬‬

‫• دالة التجزئة لا تعمل بكفاءة عالية‪ .‬هذا يمث ّل حالتنا‪ .‬لقد كتبنا دالة سهلة جدا ً )لـكن نوعا ًما كافية( من‬
‫أجل الأمثلة‪ .‬الدالتان ‪ MD5‬و ‪ SHA1‬المذكورتان أعلاه هما ذات جودة عالية لأنهما تنتجان نسبة قليلة‬
‫من التصادُمات‪ .‬و لتعلم أن ‪ SHA1‬مف ّضلة في أيامنا هذه أكثر من ‪ MD5‬لأنها تننج نسبة تصادمات أقل‬

‫مقارنة بنظيرتها‪.‬‬
‫• الجدول الذي نخزن به المعلومات صغير الحجم كثيرا ً‪ .‬لو أننا ننشئ جدولا من ‪ 4‬خانات و نريد تخزين ‪5‬‬
‫أشخاص‪ ،‬فسيحدث تصادم بالتأكيد‪ ،‬أي ان دالة التجزئة ست ُعطي نفس الر ُتبة من أجل اسمين مختلفين‪.‬‬

‫إذا حصل تصادم فلا داعي للخوف ! هناك حلان يمكنك الاختيار بينهما ‪ :‬العـ َنو َنـ َة المفتوحة و السَل ْسَل َة‪.‬‬

‫العنونة المفتوحة )‪(Open addressing‬‬

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

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

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

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

‫‪510‬‬

‫مل ّخص‬

‫السَل ْسَل َة )‪(Chaining‬‬

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

‫بالفعل‪ ،‬سنعود لمشكل القوائم المتسلسلة ‪ :‬إذا كان هناك ‪ 300‬عنصرٍ في هذا الموقع من الجدول‪ ،‬يجب‬
‫تص ّفح القائمة المتسلسلة إلى حين إيجاد العنصر الصحيح‪.‬‬

‫هنا‪ ،‬كما ترى‪ .‬ليست القوائم المتسلسلة دائما ًالأمثل‪ ،‬لـكن لجداول التجزئة حدودها أيضا ً‪ .‬يمكننا المزج بين‬
‫الإثنين من أجل الحصول على الجانب الأفضل من ك ّل بنية‪.‬‬

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

‫مل ّخص‬

‫• القوائم المتسلسلة مرنة‪ ،‬لـكن عملية إيجاد عنصر محدد تستغرق وقتا ًطو يلا ًلأنه يجب تص ّفح القائمة عنصرا ً‬
‫بعنصر‪.‬‬

‫• جداول التجزئة هي جداول نخز ّن فيها المعلومات في مكان محدد بواسطة دالة التجزئة‪.‬‬
‫• تأخذ دالة التجزئة مفتاحا ًكمعامل )مثلا ً‪ :‬سلسلة محرفي ّة( و تعيد عددا كمخرج‪.‬‬
‫• يتم استعمال هذا العدد لمعرفة أي رتبة من الجدول يجب تخزين البيانات‪.‬‬

‫• دالة التجزئة الأكثر كفاءة هي التي لا تول ّد عددا ً كبيرا ً من التصادُمات‪ ،‬أي أنها تتجنب قدر المستطاع‬
‫إرجاع نفس العدد من أجل مفتاحين مختلفين‪.‬‬

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

‫‪511‬‬

‫الفصل د‪ .3.‬جداول التجزئة )‪(Hash tables‬‬
‫‪512‬‬

‫خاتمة‬

‫هل تريد المزيد ؟‬
‫لماذا لا ٺتعلّم لغة الـ‪ C++‬؟‬

‫‪http://www.siteduzero.com/tuto-3-5395-0-apprenez-a-programmer-en-c.‬‬
‫‪html‬‬

‫هذا درس آخر كتبت ُه حول هذه اللغة قريبة الـ‪ .C‬إذا كنت تعرف الـ‪ ،C‬فلن تكون ضائعا ًبل ستفهم بسرعة‬
‫فائقة الفصول الأولى !‬

‫فليكن في علمك أنني كتبت درسا ًقصيرا يسمّى ”من الـ‪ C‬إلى الـ‪ ”C++‬الذي يبې ّن جزء ً من الاختلاف بين الـ‪C‬‬
‫و الـ‪.C++‬‬

‫‪http://www.siteduzero.com/tutoriel-3-430167-du-c-au-c.html‬‬

‫بلغة الـ‪ ،C++‬يمكنك البدء في البرمجة غرضية التوجّه )أو البرمجة الكائنية )‪ .((OOP‬قد يكون هذا المبدأ‬
‫مع ّقدا قليلا في البداية‪ ،‬لـكن ستجد بأن هذه الطر يقة في البرمجة ناجعة جدا ً ! ستكتشف أيضا ًمعها المكتبة ‪Qt‬‬

‫التي تسمح بإنجاز واجهات رسومية كاملة ج ّدا‪.‬‬
‫أشكر كثيرا ‪ Taurre‬و ‪ Pouet_forever‬لمساعدتهم الـكبيرة في القيام بالمراجعات الأخيرة لهذه الدروس‪.‬‬

‫‪513‬‬


Click to View FlipBook Version