القوائم المتصلة

35
ف ي ر ع ت ي ف ة ن ر خُ م د, قُ ع ل ا ن م وعة م ج م ن ع ارة ب ع لة ص ت م ل ا مة, ئ ا ق ل ا ر ر ب, حد ا, ا ا ل و هد س ل س مت ر ي ع ل و ص ت م ل ك; ش ب رة ك ا الد ات وف ف ص م ل و ا لة ص ت م ل م ا, ئ وا ف ل ا نH ي ب لاف خ ل ة ا وج, ا. م س ا ب لة ص ت م ل م ا, ئ وا ف ل ا رف عُ ت ت ن كاNSS memory ن ي بW ن س لل ا لا ح ها م ي م ص ت م ئ و1955 - 1956 ي; ث لا; ب ل ا رف ط ن م, Allen Newell, Cliff Shaw وHerbert Simon ة رعان ب; وت ح ب ل ل ة ي ك ب ر م, لا ا سة س, و م ل اRAND Corporation. م ه ت غ ل ي ف ة ي س , سالا ا ة يW نُ ب ل ا ي ه طة رات مي ل م ا, ئ وا ف ل ا ت ن كا

description

شرح كامل للقوائم المتصلة

Transcript of القوائم المتصلة

Page 1: القوائم المتصلة

تعريف القائمة المتصلة عبارة عن مجموعة من

الع!قد, م!خزنة في الذاكرة بشكل متصل و غير متسلسل و هذا أحد أبرز أوجه الخالف

.بين القوائم المتصلة و المصفوفات

!عرف القوائم المتصلة باسم NSS كانت تmemory و تم تصميمها خالل السنتين

, من طرف الثالثي1955-1956 Allen Newell, Cliff Shaw و Herbert Simon برعاية المؤسسة األمريكية

.RAND Corporation للبحوث!نية كانت القوائم المترابطة هي الب

Information األساسية في لغتهمProcessing Language (IPL) و كان

لتطوير IPL المخترعون الثالثة يستخدمون مجموعة من برامج الذكاء االصطناعي,

,Logic Theory Machine مثلGeneral Problem Solver باإلضافة إلى

Chess (لعبة الشطرنج).!شرت أعمال الفريق حول القوائم ن

IRE Transactions on المتصلة في الــInformation Theory و1956في سنة ع!قدت العديد من المؤتمرات خالل الفترة

Page 2: القوائم المتصلة

. أما التمثيل الحالي)1( 1959 – 1957 للقوائم المتصلة (حيث تتكون القائمة من مجموعة عقد م!رتبطة فيما بينها بواسطة

أسهم) فقد تم تنشره في شهر فبراير من Programming تحت عنوان1957عام

the Logic Theory Machine 2. Allen حصل الثنائي1975في عام

Newell و Herbert Simon على جائزة Turing لمساهمتهم الفعالة في علم

.الذكاء االصطناعي و التعامل مع القوائم 

Linked List قالوا عن الــ!مكن تعريف القوائم بطبيعة الحال, ي

المتصلة بأكثر من طريقة لذا اقتطفت لكم بعض التعريفات التي وردت في أهم الكتب

:المتعلقة بهياكل البيانات في كتابه Seymour Lipschutz يقول

The data structures (Courses and problems) : “القائمة عبارة عن

.”مجموعة خطية من عناصر البيانات في John Rast Hubbard بينما يرى

أن Java Data Structures كتابه “القائمة عبارة عن حاوية متسلسلة العناصر و قادرة على إدراج و إزالة

Page 3: القوائم المتصلة

العناصر بشكل مطرد محليا, أي بغض.”النظر عن حجم الحاوية

فيرى Alain-Bernard Fontaine أما The C++ Standard في كتابه

Template Library أن “القوائم عبارة عن حاويات م!خصصة للقيام بعمليات

معينة (مثل اإلدراج و اإلزالة) حيث تتم هذه العمليات في وقت ثابت مهما كان

.”موقع العنصر داخل الحاوية ,Thomas Cormen و يعتبر الثالثي

Charles Leiserson و Ronald Rivest في كتابهم Introduction to

Algorithms أن “القائمة المتصلة عبارة عن هيكل بيانات يتم فيه ترتيب الكائنات بشكل خطي ولكن بخالف المصفوفات

!حدد فيها العناصر عن طريق ترقيم التي ت الخانات, يتم تحديد عناصر القائمة

”المتصلة عن طريق مؤشر في كل كائن 

أيهما أفضل, المصفوفة الديناميكيةأم القائمة المتصلة ؟

عادة ما يكون السؤال الذي يطرح نفسه:عند المقارنة بين هياكل البيانات, هو ما مدى سهولة الوصول إلى عناصر

Page 4: القوائم المتصلة

المجموعة ؟ و كذا التنقل بين مختلفالعناصر و إجراء العمليات األكثر استعماال ؟

لإلجابة على هذا السؤال ق!منا بحساب:التعقيد الزمني للعمليات األكثر استعماال

من i إلضافة عنصر معين في الخانة رقم عنصر size-i يجب إزاحة X المصفوفة

هو طول المصفوفة و بالتالي size حيث عملية اإلضافة في المصفوفات تستغرق

!ستهان بها و يزداد األمر سوءا كلما � ال ي وقتا!رت العناصر. نفس الشيء يحدث مع كث

.عملية الحذف أما في القوائم المتصلة فعملية الحذف أو اإلضافة تأخذ نفس الوقت بغض النظر عن

طول القائمة أو المكان الـم!راد إضافة.(حذف) الع!قدة فيه (منه)

نالحظ أن القوائم المتصلة تكون أسرع في عمليتي اإلضافة و الحذف بينما تكون

المصفوفة الـم!رتبة أسرع في عملية البحث و يتساوى االثنان عند المرور على جميع

.العناصر 

Page 5: القوائم المتصلة

مفهوم القوائم المتصلة

ذكرنا آنفا أن طريقة تخزين عناصر المصفوفة تختلف عن طريقة تخزين

ن !خز¢ عناصر القائمة إذ£ أن عناصر األولى ت في أماكن متتابعة في الذاكرة أما القوائم

!شترط تتابع عناصرها ألن الوصول إلى فال ي أي ع!قدة من القائمة يتم عن طريق مؤشر

في الع!قدة السابقة أما المصفوفات فيتم الوصول إلى خاناتها عن طريق الترقيم لذا

.لزمها تتابع الخانات القوائم المتصلة تنتمي إلى عائلة الــ

Dynamic Data Structures لذا تجد أن عملية حجز الذاكرة تتم أثناء عمل البرنامج

.مثال malloc باستخدام قبل أن ننتقل إلى الجانب التطبيقي, تذكر

النقاط التالية جيدا ألنك ستحتاجها لفهم: العمليات األكثر استخداما في القوائم

تتكون القائمة المتصلة من مجموعة ع!قد.ترتبط فيما بينها عن طريق المؤشرات

كل ع!قدة تحتوي على جزئين, الجزء األول يحتوي على بيانات العقدة و الجزء

Page 6: القوائم المتصلة

!شير إلى العقدة الثاني عبارة عن مؤشر ي.الموالية

للوصول إلى ع!قدة معينة, يجب الذهاب� من أول ع!قدة. و يتم االنتقال من دائما

العقدة الموالية عن طريق المؤشر.الموجود في الع!قدة السابقة

!شير المؤشر الموجود في آخر دائما ما ي.NULL عقدة إلى

عندما تكون أول عقدة هي آخر ع!قدة,.نقول أن القائمة فارغة

Singly) في القوائم المتصلة البسيطةLinked List) تتم الحركة في اتجاه

واحد, انطالقا من الع!قدة األولى باتجاه.العقدة األخيرة

إذا كنتª تريد التحرك في كال االتجاهين,!مكنك استخدام القوائم المتصلة ي

.(Doubly Linked List) الـم!ضاعفةالجانب التطبيقي

مدخل في بقية هذه الفقرة, سنعتبر أن القائمة

التي نعمل عليها تحتوي على بيانات مجموعة من الموظفين في شبكة محلية تابعة لشركة مسابقات, كل م!وظف يملك

رقم دخول و بريد الكتروني, نفترض أن

Page 7: القوائم المتصلة

!ميز كل موظف عن اآلخر رقم الدخول ي£ن يملكان !مكن أن نجد م!وظفي بمعنى أنه ال ي

نفس رقم الدخول. كما أن أرقام الدخول� من الصفر .يجب أن تكون أكبر تماما

قامت الشركة بتنظيم المسابقة التالية:لموظفيها على النحول التالي

A كل م!وظف سيختار حرف عشوائي من يفوز الموظف إذا تطابق الحرف .Z إلى

فه (الجزء الـم!ختار مع أول حرف من م!عر¢ الموجود قبل @ من البريد االلكتروني) و

.يخسر في الحالة المعاكسة اإلعالن عن القائمة التي ستضم بيانات

:الموظفين سيكون هكذا

كلما في األمر أننا قمنا باإلعالن عن بنية4تحتوي على singlyLinkedList باسم

!مثل بيانات عناصر, العناصر الثالثة األولى ت الموظف و العنصر الرابع عبارة عن

!شير إلى الموظف الموالي .المؤشر الذي ي الخطوة التالية تتمثل في بناء القائمة عن!شير طريق اإلعالن عن المؤشر الذي سي الحقا إلى أول ع!قدة, ق!منا بإعطاء اسم

Page 8: القوائم المتصلة

مستعار لمؤشر القائمة من أجل تسهيل و:تنظيم الكتابة

تهيئة القائمة )إنشاء أول عقدة( نأتي اآلن إلى كيفية تهيئة قائمة الموظفين

من خالل إنشاء حساب لموظف جديد و:إسناد قيم ابتدائية لكافة البيانات

:مالحظات هامة �) P إذا كانت عبارة عن بنية تحوي (مثال فإن الوصول إلى عناصر y و x عنصرين

.P.x Or P.y البنية يكون هكذا فإن ,P مؤشر لبنية من نوع Q إذا كان : الوصول إلى عناصر البنية يكون هكذا

Q->x Or Q->y. Pass) ال تدعم التمرير بالمرجع C لغة

by reference) على عكس C++. تمرير المؤشرات الثابتة بدال C تستخدم

من تمرير المراجع لكنني أفضل دائما التمرير بالمرجع و لحسن الحظ, معظم (CPP الـم!حتكة بــ) الحالية C مترجمات

.تدعمه

Page 9: القوائم المتصلة

فتستقبل وسيط واحد init بالنسبة للدالة لقائمة (Reference) عبارة عن مرجع

الموظفين, في السطر األول قمنا بحجز!شير إلى أول عقدة ذاكرة للمؤشر الذي سي في القائمة, إذا فشلت عملية الحجز ستعيد

و ينتهي األمر, أما إذا مرت false الدالة عملية الحجز بسالم فهذا يدل على أن

!شير إلى منطقة من sll المؤشر أصبح ي عناصر (رقم الدخول,4الذاكرة تحوي

الحرف العشوائي, البريد االلكتروني و المؤشر) و في هذه الحالة سنقوم بإسناد

:قيمة ابتدائية لكل عنصر على النحو التالي و Login إلى المتغير0إسناد القيمة

تخزين المسافة البيضاء داخل المتغيرrandomCharacter و إسناد المؤشر

NULL إلى ptrNext أما المتغير email فله حالته الخاصة, ألنه عبارة عن نوع

,int, float) م!ركب و ليس نوع بسيط مثلchar, bool, ..).

األنواع الـم!ركبة (مثل المصفوفات و التراكيب ,..) يتم التعامل معها بصفة

memset مختلفة لذا ق!منا باستدعاء الدالة!شير إليها المؤشر لتصفير الذاكرة التي ي

email, الدالة memset 3تستقبل

Page 10: القوائم المتصلة

معامالت, المعامل األول هو المؤشر الـم!راد تصفير ذاكرته و المعامل الثاني هو القيمة المراد وضعها داخل المنطقة التي يشير إليها المؤشر و المعامل الثالث هو

عدد البايتات أو كمية البيانات الـم!ؤشر.عليها

بعد تهيئة العناصر األربعة تقوم الدالة.كإشارة إلى نجاح العملية true بإعادة نأتي اآلن إلى تضمين المكتبات الالزمة

باإلضافة إلى شرح مختصر لمحتوى الدالة: الرئيسية

stdio.h موجودة في المكبتة printf الدالة موجود في المكتبة NULL و الماكرو

stdlib.h و الدالة memset موجودة في لذا قمنا باستدعاء string.h المكتبة

� .المكتبات الثالثة معا في بداية الدالة الرئيسية قمنا باإلعالن عن

NULL قائمة جديدة و أسندنا لها العنوان وهذه الخطوة ضرورية جدا في تهيئة

.المؤشرات أيا كانت بعد ذلك, قمنا بتمرير القائمة

mySimpleList إلى الدالة init كوسيط

Page 11: القوائم المتصلة

ثم تحققنا من القيمة الـم!عادة من طرف سيتم إظهار رسالة false الدالة, إذا كانت

تنبيه على الشاشة و إال فسيتم إظهار.البيانات االبتدائية للموظف

: و هذه صورة لم!خرجات الكود

إضافة عقدة جديدة إلضافة عقدة جديدة إلى القائمة, يجب أن

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

.الجديدة تهيئة كافة عناصر العقدة بما في ذلك

.المؤشر .إضافة العقدة و تحديث القائمة

:و بالتالي, دالة اإلضافة ستكون هكذا

!عيد كالعادة, إذا لم تنجح عملية الحجز ست و إال فالقيمة الـم!عادة ستكون false الدالة

true, ,هذا من جهة. من جهة أخرى وسائط, األول عبارة عن3تستقبل الدالة

لقائمة الموظفين و (Reference) مرجع

Page 12: القوائم المتصلة

الوسيط الثاني عبارة عن رقم دخول الموظف الجديد و الوسيط الثالث عبارة عن البريد االلكتروني. بطبيعة الحال, من غير المنطقي أن نضع الحرف العشوائي

ضمن وسائط الدالة ألن قيمته تعتمد على.توليد عشوائي

إلى L في البداية, أسندنا قيمة الوسيط ثم قمنا باختيار حرف login المتغير

و aplphabet عشوائي من المصفوفة أسندناه إلى المتغير

randomCharacter. بعد ذلك, استخدمنا em لنسخ محتوى الوسيط strcpy الدالة ثم جعلنا المؤشر email داخل المصفوفة

!شير إلى أول ع!قدة في القائمة ثم الحالي ي قمنا بتحديث القائمة من خالل جعل الع!قدة الجديدة هي األولى. نأتي اآلن إلى تضمين

المكتبات الالزمة باإلضافة إلى تعليق موجز: main حول الــ

:تنويه قمت! بتقسيم الكود الكامل إلى مجموعة

Page 13: القوائم المتصلة

فقرات للتوضيح, فمثال لم أقم بتضمين المكتبات التي قمت! بتضمينها سابقا

لالختصار, لذا تجد أن كل جزء من الكود� بالجزء السابق .يكون م!رتبطا

time.h في البداية, قمنا بتضمين المكتبة ثم قمنا .srand و rand لوجود كال من

و mail باإلعالن عن بريد الكتروني باسم استدعينا دالة اإلضافة ثم تحققنا من القيمة

الـم!عادة كما فعلنا سابقا, إذا تمت إعادةfalse ظهر رسالة الخطأ و إال! ن

المسئولة عن display فسنستدعي الدالة إظهار بيانات الـم!وظفين (سنشرح هذه

(� .الدالة الحقا:م!خرجات الكود ستكون على هذا النحو

الحظ أنه تم إدراج الع!قدة الجديدة قبل!سمى باإلضافة في !عقدة األولى و هذا ما ي ال!ضيف الع!قدة !مكننا أيضا أن ن بداية القائمة, ي في نهاية القائمة أو في أي مكان آخر و هنا

تكمن أحد أبرز نقاط القوة لدى القوائم و!وضح مفهوم هي المرونة. الصورة التالية ت

:اإلضافة في بداية القائمة

Page 14: القوائم المتصلة

بالنسبة إلضافة الع!قدة في نهاية القائمة:فستكون هكذا

while ال شيء جديد, سوى إضافة الحلقة من أجل المرور على كافة العقد وصوال

إلى العقدة األخيرة ثم ربط العقدة الجديدة بنهاية القائمة. بشكل عام, الخطوات

الـم!تبعة عند إضافة ع!قدة في نهاية القائمة:تكون كاآلتي

حجز مساحة من الذاكرة للعقدة .الجديدة

تهيئة كافة عناصر العقدة بما في ذلك.المؤشر

.االنتقال إلى آخر ع!قدة من القائمة .ربط آخر ع!قدة بالعقدة الجديدة

Page 15: القوائم المتصلة

!مكننا أيضا إضافة عقدة جديدة في أي ي مكان من القائمة, لنفترض مثال أننا نريد إدراج م!وظف جديد بعد موظف آخر يتم

تحديد رقمه. في هذه الحالة ستكون:الخ!طوات الـم!تبعة هي

البحث عن الع!قدة الـم!رافقة لرقم الموظف, توجد حالتان:حجز مساحة من

.الذاكرة للعقدة الجديدة فهذا يعني أن رقم NULL إذا وصلنا إلى

الموظف غير موجود, حينها نقوم بإعادةfalse.

إذا وصلنا إلى الع!قدة المطلوبة نقوم:باآلتي

تهيئة كافة عناصر العقدة بما في ذلك.المؤشر

تخزين عنوان العقدة الموالية في متغير.مؤقت

!شير إلى الع!قدة جعل الع!قدة الحالية ت.الجديدة

ربط عنوان الع!قدة الجديدة بالمتغير.المؤقت

:و بالتالي دالة اإلضافة ستكون هكذا

Page 16: القوائم المتصلة

إذا لم تنجح عملية الحجز أو لم يتم العثور!عيد الدالة و false على رقم الموظف ست بعد أن تتم إضافة true إال فستعيد الدالة

اآلن الع!قدة الجديدة و تحديث القائمة. � كتابة دالة تقوم أصبح من السهل جدا

بتعديل بيانات م!وظف م!عين, فقط بدال من إدراج ع!قدة جديدة, نقوم بتغيير بيانات

while الع!قدة التي توقفت عندها الحلقة.ما لم تكن تلك العقدة فارغة

نأتي اآلن إلى شرح كيفية عمل دالة اإلظهار التي تقوم بعرض محتويات قائمة

:الـم!وظفين

� و هي كالتالي :الفكرة بسيطة جدا حتى ال نفقد بيانات الـم!وظفين نقوم بإنشاء

!سخة من القائمة الـم!رسلة كوسيط, ما ن دامت الع!قدة الحالية غير فارغة نقوم

!ظهر بالتقدم خطوة إلى األمام بعد أن ن.كافة بيانات الع!قدة. فقط هذا كل شيء

Page 17: القوائم المتصلة

!مكننا حساب طول القائمة بنفس الفكرة, ي فقط بدال من إظهار البيانات نقوم بزيادة!عيد قيمة العداد عند الوصول العداد ثم ن إلى آخر ع!قدة. توجد أيضا طريقة أخرى

إلظهار محتوى القائمة باستخدام التراجع,� .سنشرحها الحقا

حذف عقدة مFعينة

كما فعلنا سابقا مع عملية اإلضافة, يمكننا أيضا حذف ع!قدة من البداية, النهاية أو أي

.مكان آخر من القائمة فمثال, الدالة التالية تقوم بحذف آخر ع!قدة

: من القائمة

:الخ!طوات الـم!تبعة هي

Page 18: القوائم المتصلة

!سخة من القائمة حتى ال نفقد إنشاء ن.بيانات الموظفين

االنتقال إلى الع!قدة القبل األخيرة (نتقدم بخطوة واحدة إذا كانت العقدة الموالية

.للعقدة الموالية غير فارغة) تخزين عنوان العقدة األخيرة في متغير!شير مؤقت وجعل الع!قدة القبل األخيرة ت

.NULL إلى !شير إلى تحرير العنوان الذي كان ي

.الع!قدة األخيرة أما إذا أردنا حذف عقدة من بداية القائمة

:فستكون الخطوات كما يلي تخزين عنوان العقدة األولى داخل متغير

.مؤقت !شير إلى العقدة جعل مؤشر القائمة ي

.الثانية !شير إلى العقدة تحرير المؤشر الذي ي

.األولى و بالتالي دالة الحذف في هذه الحالة

:ستكون هكذا

Page 19: القوائم المتصلة

الحظ أنه تم التأكد أن القائمة غير فارغة قبل إجراء عملية الحذف و هذا م!هم جدا إذ£

يجب التأكد من مثل هذه الحاالت قبللم أتحقق من القدوم على تنفيذ العملية.

� ألنني أشياء كهذه في الدوال السابقة نظرا افترضت! أن استدعاء الدوال يجب أن يكون

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

.الوقت نأتي اآلن إلى كيفية حذف ع!قدة عن

:طريقة تحديد رقم الـم!وظف

إذا كان رقم الم!وظف موجود في الع!قدة األولى نقوم باستدعاء الدالة

removeTheFirst ألن االنتقال في while يكون بمقدار خطوتين إلى األمام و بالتالي سيتم تجاوز الع!قدة األولى, هذا من

جهة. من جهة أخرى, عند الخروج منwhile سنكون أمام خيارين, الخيار األول

هو عدم وجود رقم الـم!وظف حينها سنقوم

Page 20: القوائم المتصلة

و تنتهي المهمة, إذا تجاوزنا false بإعادة بسالم فهذا يعني أن رقم الـم!وظف if الــ موجود داخل القائمة, لذا سنقوم بتخزين العقدة التي يوجد فيها الرقم في المتغير

delNode حرر عنوان تلك الع!قدة بعد! ثم ن.أن نتقدم خطوة واحدة إلى األمام

حساب طول القائمة� وهي كاآلتي :الفكرة بسيطة جدا

إذا وصلنا إلى العقدة األخيرة نقوم بإعادة الصفر و إال فهذا يعني أنه توجد عقدة

أخرى (و هي الع!قدة الحالية) باإلضافة إلى!عقد الموجودة في بقية القائمة (إن ال

و!جدت). و بالتالي دالة حساب الطول:ستكون هكذا

قبل أن ننتقل إلى الفقرة الم!والية, ستقوم بكتابة الدالة التي من خاللها نستطيع:معرفة فوز أو خسارة م!وظف م!عين

ينجح الـم!وظف إذا تساوى أول حرف من بريده االلكتروني مع الحرف العشوائي

.الخاص به و يخسر في الحالة الـم!عاكسة 

Page 21: القوائم المتصلة

دمج قائمتين في قائمة واحدة!مثالن دالة الدمج تستقبل وسيطين ي

القائمتين الـم!راد دمجهما

إذا كانت القائمة األولى فارغة, فهذا يعني!عطي القائمة الثانية لذا أن دمج القائمتين ي تمت إعادتها. في الحالة الـم!عاكسة نقوم

باالنتقال إلى آخر ع!قدة من القائمة األولى.ثم نربطها بأول ع!قدة من القائمة الثانية

 القائمة حذف

. , فقط : األولى العقدة بحذف نقوم فارغة غير القائمة دامت ما كاآلتي فكرتها الحذف ! دالة