محتويات الدورة

هياكل البيانات والخوارزميات / البنى المرتبة والاستدلال على الرسوم / الدرس 9

الأكوام والأولويات واختيار أكبر k أثناء التدفق

استخدم ثابت الكومة للوصول إلى القيمة الدنيا أو القصوى، واجعل كسر التعادل والاستبدال والإدخالات المتقادمة أمورا صريحة.

وقت القراءة التقريبي: 5 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • ترتب الكومة علاقة الآباء بالأبناء، وليس المصفوفة كلها
  • اجعل أضعف مرشح محتفظ به في الجذر
  • استخدم فاصلا محددا لكسر التعادل بين السجلات المعتمة

ترتب الكومة علاقة الآباء بالأبناء، وليس المصفوفة كلها

تحافظ الكومة الثنائية الدنيا على ألا تزيد قيمة أي أب على قيم أبنائه، فيكون الجذر أصغر العناصر. وهي لا ترتب الأشقاء أو مواضع المصفوفة الاعتباطية ترتيبا عاما. وفي التخزين ذي الفهرسة الصفرية، يقع ابنا i عند 2*i+1 و2*i+2 إذا وُجد الموضعان. تعمل heapq في Python 3.12 على قوائم عادية وفقا لعقد الكومة الدنيا هذا. اقرأ heap[0] للحصول على الأصغر، واستخدم السحب لإزالته مع استعادة الثابت. المرور في القائمة الأساسية ليس مرورا مرتبا. وإذا طُلب ناتج مرتب، فإن السحب المتكرر أو الفرز المستقل يضيف عملا يجب إدراجه في العقد.

اجعل أضعف مرشح محتفظ به في الجذر

للاحتفاظ بأكبر k قيم ظهرت حتى الآن، استخدم كومة دنيا لا تتجاوز k قيمة. عندما تمتلئ يكون جذرها أصغر المرشحين المحتفظ بهم. ولا تستطيع قيمة جديدة لا تزيد على الجذر تحسين مجموعة القيم المختارة مع تعددها؛ أما الأكبر فتستبدل أضعف مرشح. يعيد البرنامج الأول القيم المحتفظ بها مرتبة تنازليا للعرض، مضيفا فرزا نهائيا O(k log k). وتكلف معالجة n مدخلات O(n log k) وفقا للنموذج المعتاد للمقارنة المحدودة عند k>=2، مع مساحة احتفاظ O(k). وعند k=0 تكون النتيجة الصريحة فارغة، ويُرفض k السالب.

python مثال مستقل لخوارزمية بلغة Python 3، يستخدم بيانات محلية مصطنعة.
import heapq

def largest_k(values, k):
    if k < 0:
        raise ValueError("k must be nonnegative")
    if k == 0:
        return []
    heap = []
    for value in values:
        if len(heap) < k:
            heapq.heappush(heap, value)
        elif value > heap[0]:
            heapq.heapreplace(heap, value)
    return sorted(heap, reverse=True)

print(largest_k([4, 1, 9, 9, 3], 3))
print(largest_k([4, 1], 0))
الناتج المتوقع
[9, 9, 4]
[]

تُعد القيم المكررة مرات ظهور مستقلة في المدخل. ولا تُستخدم heapreplace إلا بعد إثبات أن المرشح أفضل من الجذر الحالي.

استخدم فاصلا محددا لكسر التعادل بين السجلات المعتمة

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

python مثال مستقل لخوارزمية بلغة Python 3، يستخدم بيانات محلية مصطنعة.
import heapq
from itertools import count

arrivals = count()
heap = []
for priority, name in [(2, "Maps"), (1, "Rivers"), (2, "Atlas")]:
    heapq.heappush(heap, (priority, next(arrivals), {"name": name}))
order = []
while heap:
    _, _, payload = heapq.heappop(heap)
    order.append(payload["name"])
print(order)
الناتج المتوقع
['Rivers', 'Maps', 'Atlas']

تخرج الأولوية 1 قبل الأولوية 2؛ وتسبق Maps نظيرتها Atlas لأن عداد كسر التعادل الخاص بها أصغر.

تختلف دلالة عمليات الاستبدال

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

تحتاج تغييرات الأولوية إلى سياسة اتساق

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

قارن المختار بمرجع صغير موثوق

لمدخلات صغيرة، قارن largest_k مع sorted(values,reverse=True)[:k] لكل k بدءا من الصفر، ووصولا إلى قيم أكبر من طول التسلسل. أدرج تكرار القيم الكبرى والأعداد السالبة والمدخل الفارغ. تحقّق من حفظ قائمة المصدر دون تعديل ومن حفظ تعدد القيم في الناتج. ولسجلات الأولوية اختبر التعادل بحمولات غير قابلة للترتيب، وأكد سياسة الوصول المعلنة. لا تقارن ترتيب مصفوفة الكومة الداخلية بقائمة مرتبة؛ افحص خاصية الكومة أو تسلسل القيم المسحوبة. لا تحتاج هذه الاختبارات المحلية إلى مجدول حقيقي أو خدمة متزامنة أو مولد تحميل.

الأخطاء الشائعة وإصلاحها

عرض مصفوفة الكومة على أنها ناتج مرتب

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

إثارة TypeError عند تعادل الأولويات

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

طرد مرشح أصغر لقيمة مفيدة من أكبر k

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

اختبر فهمك

1. لماذا تحفظ كومة أكبر k أصغر قيمة محتفظ بها عند جذرها؟

اعرض الحل المشروح

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

2. هل تجعل إضافة عداد لكسر التعادل الأولويات عادلة تلقائيا؟

اعرض الحل المشروح

يثبت العداد ترتيب الوصول بين الأولويات المتساوية فقط في هذا التنفيذ. وقد يظل تدفق مستمر من وظائف ذات أولوية أفضل يؤخر غيرها. تحتاج العدالة إلى سياسة جدولة تخص المجال؛ ولا يستطيع مفتاح مقارنة محدد وحده إثباتها.

أهم ما تعلمته

  • ترتب الكومة علاقة الآباء بالأبناء، وليس المصفوفة كلها
  • قارن المختار بمرجع صغير موثوق

المراجع الرسمية