الكومة هي شجرة ثنائية كاملة حيث يفي كل والد بخاصية الكومة - إما أصغر دائمًا (min-heap) أو دائمًا أكبر (max-heap) من أبنائها. "مكتمل" يعني أن كل مستوى ممتلئ باستثناء المستوى الأخير، الذي يتم ملؤه من اليسار إلى اليمين.
1 Min-heap
/ \
3 5
/ \
7 4
ولأنه مكتمل، نقوم بتخزينه في مصفوفة مسطحة - دون الحاجة إلى مؤشرات. بالنسبة للفهرس i: الطفل الأيسر = 2i + 1، الطفل الأيمن = 2i + 2، الأصل = (i - 1) // 2.
| عقار | مين كومة | ماكس الكومة | |----------|---------|----------| | الجذر | أصغر عنصر | العنصر الأكبر | | الوالدين ≥ الأطفال؟ | ✅ نعم | ❌ لا (≥) | | استخراج يعطي | الحد الأدنى | الحد الأقصى |
بايثون heapq هو min-heap بشكل افتراضي. بالنسبة إلى الكومة القصوى، قم بإلغاء القيم عند الإدراج ونفيها مرة أخرى عند الاستخراج.
إدراج - اضغط حتى النهاية، ثم فقاعة لأعلى (قم بالتبديل مع العنصر الرئيسي عندما تكون أصغر):
import heapq
h = [1, 3, 5, 7]
heapq.heappush(h, 2) # h becomes [1, 2, 5, 7, 3]
استخرج الحد الأدنى - قم بتبديل الجذر بالعنصر الأخير، ثم انتقل إلى العنصر الأخير، ثم غربل (قم بالتبديل مع العنصر الأصغر):
smallest = heapq.heappop(h) # returns 1
يتم تشغيل كلتا العمليتين في O(log n) لأن ارتفاع الشجرة هو log n.
يؤدي استدعاء heapq.heapify(arr) إلى تحويل القائمة إلى كومة في O(n)، وليس O(n log n). إنه يعمل من الأسفل إلى الأعلى، ويغربل كل عقدة غير ورقية. هذه واحدة من نتائج التعقيد الأكثر إثارة للدهشة في علوم الكمبيوتر.
تسجيل الدخول للانضمام إلى النقاش
تتيح لك قائمة الانتظار ذات الأولوية الوصول دائمًا إلى العنصر ذي الأولوية الأعلى أولاً. الأكوام هي طريقة التنفيذ لأن كلاً من الإدراج والاستخراج هما O(log n). استخدم واحدة في أي وقت تحتاج إليه "أعطني أفضل عنصر حتى الآن".
"ابحث عن أكبر عناصر K في مصفوفة غير مصنفة."
احتفظ بـ حد أدنى من الكومة بحجم K. لكل عنصر، ادفعه؛ إذا تجاوزت الكومة K، فقم بإخراج الأصغر. ما تبقى هو K الأكبر.
import heapq
def top_k(nums, k):
return heapq.nlargest(k, nums)
الوقت: O(n log k) - أفضل بكثير من الفرز عند k ≪ n.
أنت بحاجة إلى أكبر 5 نتائج من بين مليون إدخال. ما نوع وحجم الكومة؟
ادفع رأس كل قائمة إلى كومة صغيرة. افتح العنصر الأصغر، ثم ادفع العنصر التالي من نفس القائمة. كرر حتى يتم استنفاد جميع القوائم. الوقت: O(N log K) حيث N هو إجمالي العناصر.
احتفظ بكومتين: الكومة القصوى للنصف السفلي والكومة الدنيا للنصف العلوي. قم بموازنة أحجامها بحيث تختلف بمقدار 1 على الأكثر. يكون الوسيط دائمًا عند أحد الجذرين أو كليهما.
Lower half (max-heap): [1, 2, 3] ← max = 3
Upper half (min-heap): [4, 5, 6] ← min = 4
Median = (3 + 4) / 2 = 3.5
في النهج الوسيط ثنائي الكومة، أين يذهب العنصر الجديد أولاً؟
تتألق الأكوام في الجدولة: غرف الاجتماعات (تتبع أقرب وقت للانتهاء)، أو جدولة المهام من خلال فترات التباطؤ، أو قوائم انتظار مهام وحدة المعالجة المركزية. الفكرة الأساسية هي أن الكومة تتعقب بكفاءة "ما سينتهي بعد ذلك".
| بحاجة | الخيار الأفضل | لماذا | |------|------------|-----| | تكرار استخراج الحد الأدنى / الأقصى | كومة | O(log n) إدراج + استخراج | | بيانات ثابتة، فرز لمرة واحدة | مصفوفة مرتبة | O(n log n) مرة واحدة، O(1) الوصول | | استعلامات النطاق + إحصائيات الطلب | BST المتوازن | O(log n) لكل شيء | | توب-ك من تيار | كومة الحجم K | O(ن سجل ك) المجموع |
ما هي العملية التي تكون O(1) في الكومة الدقيقة؟
| عملية | الوقت | |-----------|------| | أدخل | يا(سجل ن) | | استخراج الحد الأدنى/الحد الأقصى | يا(سجل ن) | | نظرة خاطفة دقيقة / ماكس | يا(1) | | هيابيفي | يا(ن) | | Top-K من العناصر n | يا(ن سجل ك) |