ערמה בינארית - מבנה הנתונים שמאחורי תור עדיפויות
איך ערמה מאחסנת תור עדיפויות במערך ומבצעת insert ו-extract ב-O(log n).
ערמה בינארית (Binary Heap) היא עץ בינארי שלם המקיים את 'תכונת הערמה': ב-max-heap, ערך כל צומת ≥ ערכי בניו; ב-min-heap, ערך כל צומת ≤ ערכי בניו. השורש תמיד מכיל את הערך המקסימלי (או המינימלי).
ייצוג חכם - מערך במקום עץ עם מצביעים
מכיוון שהעץ שלם, אפשר לאחסן אותו במערך פשוט בלי מצביעים: לצומת באינדקס i, הבנים נמצאים ב-2i+1 ו-2i+2, וההורה ב-(i-1)/2. זה חוסך זיכרון ומשפר את ניצול המטמון.
// Max-heap stored as array
const heap = [50, 30, 40, 10, 20, 35];
// 50
// / \
// 30 40
// / \ /
// 10 20 35פעולת Insert
- מוסיפים את הערך החדש בסוף המערך (התא הפנוי הבא)
- מבצעים sift-up: כל עוד הערך גדול מההורה, מחליפים איתו
- סיבוכיות: O(log n) - עומק העץ
פעולת Extract-Max
- שומרים את ערך השורש (זה המקסימום)
- מעבירים את האלמנט האחרון לראש
- מבצעים sift-down: מחליפים עם הבן הגדול יותר עד שהתכונה מתקיימת
- סיבוכיות: O(log n)
Heapify - בניית ערמה ממערך קיים
אפשר לבנות ערמה ממערך לא ממוין ב-O(n) (ולא O(n log n)!) על ידי הרצת sift-down מהאלמנט האמצעי לאחור. זה הבסיס של אלגוריתם Heap Sort.
ערמה היא הבחירה הטבעית בכל מקום שצריך להוציא שוב ושוב את הערך המקסימלי/מינימלי - Dijkstra, A*, מיזוג k רשימות ממוינות, top-k elements.
שאלות נפוצות
איך מאחסנים ערמה בינארית במערך?
ערמה בינארית היא עץ כמעט-מלא, ולכן ניתן לאחסן אותה במערך רציף ללא מצביעים כלל. עבור צומת באינדקס i, הילד השמאלי נמצא ב-2i+1, הילד הימני ב-2i+2 וההורה ב-(i-1)/2. החיסכון במצביעים והרציפות בזיכרון הופכים את הערמה ליעילה מאוד בפועל.
מה ההבדל בין ערמה לעץ חיפוש בינארי?
ערמה מקיימת תכונה חלשה יותר: כל הורה גדול (או קטן) מילדיו, אך אין יחס מוגדר בין אחים. לכן היא נותנת גישה ל-O(1) למינימום או למקסימום, אבל חיפוש ערך שרירותי בה הוא O(n). עץ חיפוש בינארי מקיים סדר מלא ולכן מאפשר חיפוש ב-O(log n) ומעבר ממוין, במחיר של מבנה רגיש יותר.
למה בניית ערמה היא O(n) ולא O(n log n)?
כי לא כל הצמתים צריכים לרדת את מלוא גובה העץ. בבנייה מלמטה למעלה, מחצית הצמתים הם עלים שאינם זזים כלל, רבע יורדים לכל היותר רמה אחת, וכן הלאה. סכום הסדרה הזו מתכנס ל-O(n), בניגוד להכנסה של n איברים אחד-אחד שאכן עולה O(n log n).