توفر وحدة heapq
في بايثون تنفيذاً عالي الكفاءة لكومة الحد الأدنى (min-heap). تحتفظ كومة الحد الأدنى، بحسب التعريف، بأصغر عنصر لها في الجذر (المؤشر 0). وبينما تُعد إضافة (heappush
) وإزالة (heappop
) العناصر عمليات شائعة، ستحتاج في كثير من الأحيان إلى فحص أصغر عنصر دون تغيير بنية الكومة – وهي عملية نسميها “التجسس”. يستعرض هذا الدليل الطرق المثلى والبديلة للتجسس على كومة بايثون.
جدول المحتويات
فهم كومات الحد الأدنى
كومة الحد الأدنى هي بنية بيانات شجرية حيث تكون قيمة كل عقدة أقل من أو تساوي قيمة أطفالها. يمثل heapq
هذا كقائمة، مع وجود الجذر (أصغر عنصر) في المؤشر 0 بشكل ملائم. وتشمل وظائف heapq
الرئيسية:
heappush(heap, item)
: يضيف عنصراً، مع الحفاظ على خاصية الكومة.heappop(heap)
: يزيل ويعيد أصغر عنصر، مع الحفاظ على خاصية الكومة.heapify(x)
: يحول قائمة إلى كومة في مكانها.
التجسس بكفاءة: طريقة heap[0]
الطريقة الأكثر كفاءة للتجسس على الحد الأدنى للقيمة هي من خلال الوصول مباشرة إلى heap[0]
. هذا يستفيد من خاصية كومة الحد الأدنى، مما يوفر عملية زمن ثابت (O(1)) دون تعديل الكومة.
import heapq
heap = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
heapq.heapify(heap)
smallest = heap[0]
print(f"أصغر عنصر: {smallest}") # الإخراج: أصغر عنصر: 1
print(f"الكومة لم تتغير: {heap}") # الإخراج: الكومة لم تتغير: [1, 3, 2, 4, 5, 9, 5, 6, 5, 3]
طرق التجسس البديلة
بينما توجد طرق بديلة أقل كفاءة، إلا أنها موجودة لسيناريوهات محددة:
استخدام heappop()
و heappush()
: يعمد هذا النهج إلى إزالة أصغر عنصر مؤقتاً، ثم إضافته مرة أخرى. وهو أبطأ بكثير (O(log n)) بسبب إعادة هيكلة الكومة المعنية. استخدم هذا فقط إذا كنت بحاجة إلى الجمع بين التجسس وإزالة الحد الأدنى للعنصر.
import heapq
heap = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
heapq.heapify(heap)
smallest = heapq.heappop(heap)
print(f"أصغر عنصر: {smallest}") # الإخراج: أصغر عنصر: 1
heapq.heappush(heap, smallest)
print(f"الكومة مُستعادة: {heap}") # الإخراج: الكومة مُستعادة: [1, 3, 2, 4, 5, 9, 5, 6, 5, 3]
استخدام nsmallest()
: heapq.nsmallest(n, iterable)
يعيد n
أصغر عناصر. يسمح طلب واحد فقط (nsmallest(1, heap)
) بالتجسس. ومع ذلك، فإن هذا أقل كفاءة من heap[0]
للتجسس على عنصر واحد (على الرغم من كفاءته لاسترجاع العديد من أصغر العناصر).
import heapq
heap = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
heapq.heapify(heap)
smallest = heapq.nsmallest(1, heap)[0]
print(f"أصغر عنصر: {smallest}") # الإخراج: أصغر عنصر: 1
print(f"الكومة لم تتغير: {heap}") # الإخراج: الكومة لم تتغير: [1, 3, 2, 4, 5, 9, 5, 6, 5, 3]
اختيار طريقة التجسس المناسبة
للتجسس البسيط، فإن الوصول مباشرة إلى heap[0]
هو الفائز الواضح نظرًا لسرعته وبساطته. الطرق البديلة مفيدة فقط في حالات محددة حيث تحتاج أيضًا إلى إجراء عمليات كومة أخرى.