المكدس في بايثون: التعريف، والتطبيقات، والأمثلة

آخر تحديث: 02/04/2026
نبذة عن الكاتب: ج مصدر تريل
  • تتبع المكدسات في بايثون نموذج Last-In, First-Out، مع عمليات أساسية مثل push و pop و peek و size و empty checks.
  • يمكن تنفيذ مكدسات بايثون باستخدام القوائم، أو collections.deque، أو queue.LifoQueue، أو قوائم مرتبطة أحادية مخصصة، ولكل منها مزايا وعيوب مختلفة.
  • تُعد القوائم و deque مثالية للتعليمات البرمجية أحادية الخيوط، بينما يعتبر queue.LifoQueue الخيار الأكثر أمانًا في البيئات متعددة الخيوط.
  • يعتمد اختيار التنفيذ الصحيح للمكدس على احتياجات الأداء وسلوك الذاكرة وما إذا كان مطلوبًا أمان الخيوط.

بنية بيانات المكدس في بايثون

تُعدّ المكدسات في بايثون أحد المفاهيم الأساسية التي تظهر باستمرار في كل مكان بمجرد البدء في البحث في بنية البرامج الحقيقية. – بدءًا من استدعاءات الدوال، مرورًا بميزات التراجع في المحررات، وصولًا إلى كيفية تعامل المتصفحات مع سجل التصفح. حتى لو كنت تكتب في الغالب أكواد تطبيقات عالية المستوى، فإن فهم كيفية عمل المكدسات (وكيفية تنفيذها بشكل صحيح في بايثون) يمنحك ميزة كبيرة عند الحاجة إلى تصحيح الأخطاء المعقدة أو تصميم خوارزميات فعالة.

سنشرح في هذا الدليل ماهية المكدس، وماذا يعني مبدأ "آخر ما يدخل، أول ما يخرج" عمليًا، وما هي العمليات التي يجب أن يدعمها كل مكدس، وكيفية تنفيذ المكدسات في بايثون باستخدام أدوات مختلفة مثل القوائم، وcollections.deque، وqueue.LifoQueue، والقوائم المرتبطة بشكل فردي.سنتحدث أيضًا عن الأداء، وسلوك الذاكرة، وسلامة الخيوط، وسيناريوهات العالم الحقيقي حيث يكون المكدس هو بنية البيانات المناسبة تمامًا للوصول إليها.

ما هو المكدس في لغة بايثون؟

المكدس هو بنية بيانات خطية تتبع قاعدة "آخر ما يدخل، أول ما يخرج" (LIFO): آخر عنصر يتم دفعه إلى المكدس هو أول عنصر يخرج منه.من الناحية المفاهيمية، يمكنك تخيل كومة من الأطباق، أو كومة من الكتب، أو كومة من الملابس: لا يمكنك إضافة أو إزالة العناصر إلا من الأعلى، وليس من المنتصف أو الأسفل.

يعني سلوك LIFO هذا أنه عند إدراج (دفع) العناصر، يوضع كل عنصر جديد فوق العناصر السابقة، وعند إزالة (سحب)، يتم دائمًا أخذ العنصر الذي تمت إضافته مؤخرًالا يمكنك أبدًا "القفز للأمام" للوصول إلى العنصر الثالث أو الرابع دون إزالة العناصر التي تعلوه.

في لغة بايثون، لا يُعتبر المكدس نوعًا مسمىً مدمجًا بحد ذاته؛ بل نقوم بتنفيذ المكدسات فوق هياكل البيانات الموجودة مثل القوائم، وقوائم الانتظار المزدوجة، وقوائم الانتظار LIFO، أو القوائم المرتبطة المخصصة.لكل خيار مزاياه وعيوبه الخاصة من حيث الأداء واستخدام الذاكرة وسلامة الخيوط.

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

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

مفهوم المكدس في بايثون

عمليات وسلوكيات المكدس الأساسي

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

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

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

تُتيح معظم تطبيقات المكدس أيضًا عملية إلقاء نظرة سريعة أو عملية أعلى، والتي تسمح لك بالنظر إلى العنصر الموجود حاليًا في الأعلى دون إزالته من المكدس.وهذا مفيد بشكل خاص في الخوارزميات التي تحتاج إلى فحص القيمة التالية ولكنها لا تزال ترغب في الاحتفاظ بها لوقت لاحق.

هناك عمليتان مساعدتان إضافيتان ستجدهما بشكل متكرر وهما isempty (أو isEmpty) و size، اللتان تتحققان مما إذا كان المكدس يحتوي على أي عناصر وعدد العناصر التي يحتويها.في لغة بايثون، يمكن إعادة استخدام كل من الدالة المضمنة len() والفحوصات المنطقية داخليًا لتنفيذ هذه الأدوات المساعدة بأقل قدر من التعليمات البرمجية.

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

متى ولماذا يتم استخدام المكدس

تتألق تقنية Stacks عندما تتعامل مع عمليات ستحتاج لاحقًا إلى "إعادتها" أو اجتيازها بالترتيب العكسي تمامًا للخطوات التي تم اتخاذها.أي موقف تفكر فيه بشكل طبيعي "سأحتاج إلى التراجع عن هذا من الأخير إلى الأول" هو مرشح قوي لـ stack.

من الأمثلة الكلاسيكية في الحياة الواقعية تفكيك آلة: تقوم بإزالة البراغي والأجزاء بترتيب معين، وإذا أردت إعادة تجميعها بشكل صحيح، فيجب عليك إعادتها بترتيب معاكس تمامًا.يتوافق تخزين هذه الأجزاء على كومة بشكل مثالي مع سير العمل هذا.

في مجال البرمجيات، يُعد مكدس استدعاء الدوال أحد أهم استخدامات المكدسات: ففي كل مرة تستدعي فيها دالة دالة أخرى، يتم دفع المعاملات والمتغيرات المحلية وعناوين الإرجاع إلى مكدس في الذاكرة.عندما تعود الدالة، يتم إزالة إطارها، مما يؤدي إلى استعادة حالة الدالة المستدعِية.

تعتمد آليات التراجع والإعادة في محررات النصوص وأدوات الرسم وبيئات التطوير المتكاملة والعديد من التطبيقات الأخرى عادةً على مجموعات من الإجراءات أو الحالاتيتم دفع كل إجراء يقوم به المستخدم إلى مكدس التراجع؛ فعند الضغط على Ctrl+Z، يقوم التطبيق بإزالة آخر إجراء وعكسه.

تُستخدم المكدسات بكثرة في خوارزميات مثل البحث العميق أولاً (DFS) في الرسوم البيانية، وتقييم التعبيرات (تحليل الأقواس والمعاملات والمتغيرات)، والتراجع، ولتنفيذ سجل المتصفح حيث يتم دفع كل صفحة تمت زيارتها، ويؤدي الضغط على زر "رجوع" إلى إزالة الصفحة الأخيرة.تستفيد هذه السيناريوهات من نظام LIFO الطبيعي الذي تفرضه المجموعات وترتبط بالأساسيات منطق البرمجة.

تنفيذ مكدس باستخدام قوائم بايثون

أبسط طريقة لإنشاء مكدس في بايثون هي استخدام نوع القائمة المدمج، مع الاستفادة من طريقة append() لإضافة عنصر جديد و pop() لإزالة العنصر الأخير.. القوائم عبارة عن مصفوفات ديناميكية في جوهرها وتوفر جميع الوظائف الأساسية التي يحتاجها المكدس.

قد توفر بنية مكدس بسيطة تعتمد على القوائم وظائف مساعدة مثل create_stack و push و pop و isempty و show (أو top و size وما إلى ذلك)، وكلها تعالج داخليًا مثيل قائمة بايثون عادي.على سبيل المثال، يمكن لـ create_stack أن تُرجع قائمة فارغة، ويمكن تعريف isempty على أنها len(stack) == 0.

يتمثل أحد الأنماط الشائعة في اعتبار نهاية القائمة بمثابة قمة المكدس، لذا فإن stack.append(item) يقوم بعملية دفع (push) و stack.pop() يقوم بعملية إزالة (pop).وهذا يحافظ على كلا العمليتين في متوسط ​​وقت ثابت، ويبقى الكود قابلاً للقراءة وقصيرًا للغاية.

إذا كنت تفضل كتابة كود أكثر تنظيمًا، يمكنك تغليف هذا السلوك في فئة Stack مخصصة تغلف القائمة وتوفر طرقًا واضحة مثل push() و pop() و peek() و is_empty() و size(). يسهل التغليف توسيع المكدس بإجراء فحوصات إضافية أو تسجيل لاحقًا.

تتميز القوائم بكفاءة نسبية في استخدام الذاكرة لأن كل عنصر يخزن قيمته مباشرةً دون الحاجة إلى مؤشر إلى العقدة التالية، كما هو الحال في القوائم المتصلة.علاوة على ذلك، فإن العديد من مطوري بايثون مرتاحون بالفعل لدلالات القوائم، مما يجعل هذا النهج سهل التعليم والصيانة.

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

من عيوبها الأخرى أن قوائم بايثون غير آمنة للاستخدام المتزامن مع التعديلات من عدة خيوط، وهو ما قد يُشكل مشكلة إذا كنت ترغب في استخدام مكدس في البرامج متعددة الخيوط.في مثل هذه الحالات، يجب عليك التفكير في بدائل مثل queue.LifoQueue بدلاً من القوائم العادية.

استخدام collections.deque كمكدس

توفر وحدة المجموعات في بايثون قائمة انتظار مزدوجة الأطراف (deque)، والتي غالبًا ما تكون أنسب من القوائم عندما تحتاج إلى عمليات دفع وسحب متكررة.. تم تحسين قائمة الانتظار المزدوجة (deque) لعمليات الإضافة والحذف السريعة من كلا الطرفين.

عند استخدام قائمة انتظار مزدوجة (deque) كمكدس، عادةً ما يتم دفع العناصر باستخدام الدالة append() وإزالتها باستخدام الدالة pop()، مع اعتبار الطرف الأيمن هو أعلى المكدس.داخليًا، يتم تنفيذ deque كقائمة مرتبطة بشكل مزدوج من الكتل، مما يتجنب عمليات إعادة التخصيص الكبيرة التي تحتاجها القوائم أحيانًا.

إنشاء مكدس باستخدام قائمة الانتظار المزدوجة (deque) أمر بسيط: استدعِ الدالة deque() للحصول على حاوية فارغة، ثم حدد عمليات مثل push(stack, item) التي تستدعي stack.append(item) و pop(stack) التي تتحقق مما إذا كان المكدس غير فارغ ثم تستدعي stack.pop(). يمكن للمساعدات الإضافية مثل show(stack) ببساطة طباعة المحتويات الحالية.

نظرًا لأن deque مُصممة خصيصًا للإدخال والحذف بكفاءة من كلا الطرفين، فإن عمليات الدفع والسحب تحافظ على أداء ثابت O(1) حتى مع نمو البنية.وهذا قد يجعل قوائم الانتظار المزدوجة (deque) مفضلة على القوائم (lists) بالنسبة للمكدسات الكبيرة أو المستخدمة بكثرة.

في التعليمات البرمجية أحادية الخيوط، تُعد قائمة الانتظار المزدوجة (deque) عادةً واحدة من أفضل الخيارات الافتراضية لتنفيذ المكدسات في بايثون، لأنها تجمع بين الأداء الجيد وواجهة برمجة التطبيقات النظيفة وعدم وجود مفاجآت فيما يتعلق بحدود السعة.كما أنه يتصرف بشكل أكثر قابلية للتنبؤ من حيث التوقيت عندما يصبح حجم المكدس كبيرًا جدًا.

تنفيذ المكدسات باستخدام queue.LifoQueue

عندما يصبح أمان الخيوط أمرًا بالغ الأهمية، فإن فئة LifoQueue التابعة لوحدة الطابور هي الخيار الأمثل لتنفيذ مكدس في بايثون. إن LifoQueue عبارة عن مكدس آمن للخيوط مع آليات قفل مدمجة.

لإنشاء مكدس جديد قائم على LifoQueue، يمكنك إنشاء مثيل لـ LifoQueue باستخدام مُعامل maxsize الاختياري، والذي يُمثل الحد الأقصى لعدد العناصر التي يمكن أن يحتويها المكدس.. داخليًا، ستتعامل قائمة الانتظار مع الانتظار والحظر والإشارة عبر الخيوط إذا كانت المكدسة ممتلئة أو فارغة.

يتم دفع عنصر إلى مكدس LifoQueue باستخدام put(item)، والذي قد يتسبب في حظر العملية إذا كان المكدس قد وصل بالفعل إلى سعته القصوى.. يتم استخدام get() لإزالة العناصر، والتي يمكن أن تحجب أيضًا إذا كانت المكدسة فارغة حتى يتوفر عنصر جديد.

تتيح لك طرق المساعدة الإضافية مثل qsize() و full() و empty() فحص الحالة الحالية للمكدس بطريقة آمنة للخيوطعلى سبيل المثال، تخبرك الدالة full() ما إذا كان لا يمكن إضافة المزيد من العناصر، بينما تشير الدالة empty() إلى ما إذا كان هناك أي شيء يمكن إزالته.

تتمثل المقايضة الرئيسية عند استخدام LifoQueue في الأداء: فجميع عمليات التزامن اللازمة لجعلها آمنة للاستخدام المتزامن تُضيف عبئًا إضافيًا، مما يجعل العمليات أبطأ من تلك التي تُجرى على القوائم أو قوائم الانتظار المزدوجة.في سيناريوهات الأداء العالي التي تعتمد على وحدة المعالجة المركزية، قد يكون لهذا العبء الإضافي أهمية، ولكن بالنسبة للعديد من التطبيقات متعددة الخيوط، فإن السلامة والصحة أكثر أهمية بكثير.

تجدر الإشارة إلى أن خاصية تعدد الخيوط في بايثون لا تعني أن الخيوط ستعمل تلقائيًا على أنوية معالجة مركزية مختلفة بسبب قفل المفسر العام (GIL)، ولكن LifoQueue لا يزال يحمي مكدسك المشترك من حالات التزامن المتنافس والحالة غير المتناسقة. لتحقيق التوازي الحقيقي عبر النوى، ستحتاج إلى المعالجة المتعددة أو أساليب أخرى، ومع ذلك يظل مفهوم المكدسات الآمنة للخيوط ذا صلة بأحمال العمل المقيدة بالإدخال/الإخراج أو التعاونية.

تنفيذ المكدس باستخدام قائمة مرتبطة أحادية

تتمثل إحدى الطرق "الكلاسيكية" لبناء مكدس في بايثون في استخدام قائمة مرتبطة أحادية، حيث تخزن كل عقدة قيمة ومؤشرًا (مرجعًا) إلى العقدة التالية.يمنحك هذا الأسلوب مكدسًا ديناميكي الحجم لا يعتمد على الذاكرة المتجاورة.

عادةً ما تقوم بتعريف فئة Node بسمات للقيمة والمرجع التالي، ثم تقوم بتنفيذ فئة Stack التي تتعقب عقدة الرأس وعداد الحجم. في كثير من الأحيان، يتم استخدام عقدة رأس وهمية لتبسيط الحالات الشاذة عندما تكون المكدسة فارغة.

في هذا التصميم، يتم تمثيل الجزء العلوي من المكدس بالعقدة التي تلي الرأس مباشرةًلدفع قيمة، تقوم بإنشاء عقدة جديدة، وتعيين مرجعها التالي إلى head.next الحالي، ثم تحديث head.next للإشارة إلى العقدة الجديدة، مع زيادة الحجم أثناء تقدمك.

تتضمن عملية إزالة عنصر التحقق مما إذا كانت المكدسة فارغة، ثم أخذ العقدة التي يشير إليها head.next، ونقل head.next إلى العقدة التالية، وإنقاص الحجم، وإرجاع القيمة التي تمت إزالتها.تتميز هذه العملية بتعقيد زمني ثابت لأنه لا يلزم سوى تحديثين للمؤشر.

يسهل تنفيذ طرق إضافية مثل getSize() و isEmpty() و peek() باستخدام هذا الهيكل: يتم تتبع الحجم كعدد صحيح، ويمكن لـ isEmpty التحقق مما إذا كان الحجم يساوي صفرًا، وتعيد peek قيمة head.next.value إذا لم يكن المكدس فارغًا.يمكنك أيضًا تعريف طريقة __str__ لإنشاء سلسلة نصية قابلة للقراءة تحتوي على جميع عناصر المكدس.

تشمل مزايا المكدس القائم على القوائم المرتبطة النمو الديناميكي دون إعادة تخصيص الذاكرة وأداء O(1) المتوقع لعمليتي الدفع والسحب حتى عندما يصبح الهيكل كبيرًايتم تخصيص الذاكرة عقدة تلو الأخرى، وهو ما يمكن أن يكون مفيدًا في الأنظمة ذات الذاكرة المجزأة.

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

خصائص وكفاءة وقيود المكدسات

من الناحية المفاهيمية، تتصرف المكدسة مثل كومة من الأشياء حيث لا يمكن الوصول إلا إلى الجزء العلوي: تتفاعل دائمًا مع العنصر الذي تمت إضافته مؤخرًا أولاًهذا القيد يمنح المكدسات قوتها وحدودها في آن واحد.

عند التنفيذ الصحيح، فإن قراءة العنصر العلوي، وإدراج عنصر جديد، وإزالة العنصر العلوي، كلها عمليات زمنية ثابتة O(1).. هذا الأداء المتسق مفيد للغاية عند تصميم الخوارزميات التي قد تحتاج إلى دفع وسحب آلاف أو ملايين المرات.

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

تعتمد أنماط استخدام الذاكرة وتخصيصها بشكل كبير على طريقة التنفيذ المختارة: تستخدم المصفوفات (القوائم) ذاكرة متجاورة وقد تحتاج أحيانًا إلى إعادة تخصيصها، وتدير قوائم الانتظار المزدوجة كتلًا من الذاكرة لتجنب النسخ الكبيرة، بينما توزع القوائم المرتبطة العقد على مواقع الذاكرة المتاحة.. كل نهج يوازن بين التكاليف العامة والموقع وسلوك القدرة بشكل مختلف.

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

اعتبارات حزم البيانات والخيوط في بايثون

عندما يكون برنامج بايثون الخاص بك أحادي الخيوط، يمكنك الاختيار بأمان بين القوائم وقوائم الانتظار المزدوجة لتنفيذ المكدسات بناءً على الأداء والراحة.يوفر كلاهما إمكانيات الدفع والسحب، ويسهل دمجهما في التعليمات البرمجية العادية.

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

تُعتبر قوائم الانتظار المزدوجة آمنة نسبيًا إذا كنت شديد الانضباط واقتصرت على استخدام دالتي append() و pop() فقط من طرف واحد بطريقة مُحكمة.ومع ذلك، حتى في هذه الحالة، يمكن أن تظهر مشكلات دقيقة وحالات تنافس إذا قامت خيوط متعددة بالقراءة والكتابة في نفس الوقت دون تزامن خارجي.

بالنسبة للسيناريوهات متعددة الخيوط القوية حيث قد تقوم عدة خيوط بعمليات دفع وسحب متزامنة، فإن queue.LifoQueue هو تطبيق المكدس الموصى بهتضمن أقفالها المدمجة ودلالاتها المانعة عدم إتلاف الوصول المتزامن للمكدس.

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

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

اختيار تطبيق بايثون المناسب

مع الأخذ في الاعتبار كل هذه الخيارات، فإن أفضل تطبيق لبنية المكدس في بايثون يعتمد بشكل كبير على سياقك: فاستخدام خيط واحد أو عدة خيوط، وحساسية الأداء، وسلوك الذاكرة، ووضوح الكود، كلها عوامل مؤثرة.لا يوجد خيار واحد مثالي لكل موقف.

في البرامج النصية البسيطة غير متعددة الخيوط أو بيئات التعلم، غالبًا ما يكون استخدام قائمة ككدس أكثر من كافٍ: فعمليتا append() و pop() بديهيتان وسريعتان لمعظم أحمال العمل، ولا تتطلبان تقريبًا أي كود نمطي.ولأغراض تعليمية، تسهل القوائم أيضًا طباعة المحتويات وفحصها.

عندما يتم استخدام مكدس البيانات الخاص بك بكثافة، مع احتمال تخزين العديد من العناصر، وترغب في عمليات دفع/سحب سريعة باستمرار مع تقليل المفاجآت المتعلقة بإعادة تخصيص الذاكرة، فإن استخدام collections.deque يميل إلى أن يكون الخيار الأكثر عملية.. تعكس واجهة برمجة التطبيقات الخاصة بها القوائم بشكل وثيق، لذا فإن عملية الترحيل عادة ما تكون سهلة.

إذا كنت تعلم منذ البداية أنه سيتم الوصول إلى المكدس من عدة سلاسل عمليات، وخاصة مع حدوث عمليات الدفع والسحب بشكل متزامن، فإن queue.LifoQueue هو الخيار الأكثر أمانًاقد يكون الأمر أبطأ، ولكنه يوفر عليك عناء تطبيق بروتوكول القفل الخاص بك ويساعد على تجنب حالات التزامن المعقدة.

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

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

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

منطق البرمجة لكتابة أفضل الكود
المادة ذات الصلة:
منطق البرمجة لكتابة أفضل الكود
الوظائف ذات الصلة: