Menu
Coddy logo textTech

AVL Tree (עץ AVL)

עודכן לאחרונה

עץ AVL הוא עץ חיפוש בינארי שמאזן את עצמו. הוא עובד כמו BST רגיל, אבל אחרי כל הכנסה הוא בודק את מקדם האיזון של כל אב קדמון, כלומר את הפרש הגבהים בין תת העץ השמאלי לתת העץ הימני שלו. אם צומת כלשהו יוצא מאיזון (הפרש גדול מ-1), העץ מבצע רוטציות כדי להחזיר את האיזון. לחצו על הפעלה למעלה כדי לראות את הערכים נכנסים ואת העץ מסתובב בחזרה לצורתו.

מכיוון שעץ AVL לעולם לא נותן לעצמו להיות עקום יותר מקצת, הוא מבטיח גובה של O(log n), ולכן חיפוש, הכנסה ומחיקה הם תמיד O(log n), גם עבור קלט ממוין שהיה הורס BST רגיל. המחיר הוא הרוטציות הנוספות ותחזוקת הגובה בכל הכנסה.

סיבוכיות זמן וזיכרון

פעולהסיבוכיותהערות
חיפושO(log n)הגובה הוא תמיד בערך 1.44 log n
הכנסהO(log n)ועוד O(1) רוטציות
מחיקהO(log n)ועוד O(log n) רוטציות
זיכרוןO(n)שדה גובה אחד לכל צומת

ארבעת מקרי הרוטציה

מקרהחוסר איזוןתיקון
שמאל-שמאלכבד בצד שמאל של הבן השמאלירוטציה ימינה אחת
ימין-ימיןכבד בצד ימין של הבן הימנירוטציה שמאלה אחת
שמאל-ימיןכבד בצד ימין של הבן השמאלירוטציה שמאלה ואז רוטציה ימינה
ימין-שמאלכבד בצד שמאל של הבן הימנירוטציה ימינה ואז רוטציה שמאלה

דוגמה מפורטת

הכנסת [10, 20, 30, 40, 50, 25] ערך אחד בכל פעם:

צעדמבנהפעולה
הכנסת 1010הצומת הראשון הופך לשורש; העץ מאוזן
הכנסת 2010(_, 20)נכנס מימין ל-10; עדיין מאוזן
הכנסת 3020(10, 30)ימין-ימין ב-10, ולכן רוטציה שמאלה אחת מעלה את 20 לשורש
הכנסת 4020(10, 30(_, 40))נכנס מימין ל-30; כל מקדמי האיזון נשארים בטווח ±1
הכנסת 5020(10, 40(30, 50))ימין-ימין ב-30, ולכן רוטציה שמאלה ב-30 מעלה את 40
הכנסת 2530(20(10, 25), 40(_, 50))ימין-שמאל ב-20: רוטציה ימינה לתת העץ של 40, ואז רוטציה שמאלה ל-20

מתי להשתמש בעץ AVL

השתמשו בו כאשרהימנעו ממנו כאשר
יש הרבה יותר חיפושים מהכנסות ואתם רוצים את הגובה הנמוך ביותר האפשריהכנסות ומחיקות הן רוב העבודה: הרוטציות והאיזון הנוספים עולים יותר מאשר בעץ אדום-שחור
אתם צריכים מקרה גרוע מובטח של O(log n), גם עבור קלט עוין או ממויןטבלת גיבוב פשוטה תספיק: אין לכם צורך במעבר מסודר או בשאילתות טווח
אתם צריכים פעולות מסודרות: מעבר in-order, קודם ועוקב, שאילתות טווחכמות הנתונים זעירה: BST רגיל או מערך ממוין פשוטים יותר ומהירים מספיק
הנתונים עשויים להגיע כבר ממוינים, מה שהיה הופך BST לא מאוזן לרשימה מקושרתאין לכם מקום לזיכרון הנוסף של שדה הגובה בכל צומת בסביבה מוגבלת מאוד

קוד AVL Tree

מימוש נקי של AVL Tree שאפשר להריץ, ב-Python, JavaScript, Java, C++, C. בחרו שפה, העתיקו את הקוד, או פתחו אותו טעון מראש בעורך האונליין של Coddy.

קוד AVL Tree ב-Python

Python
1class Node:2    def __init__(self, key):3        self.key = key4        self.left = None5        self.right = None6        self.height = 17
8
9def height(node):10    return node.height if node else 011
12
13def update(node):14    node.height = 1 + max(height(node.left), height(node.right))15
16
17def rotate_right(y):18    x = y.left19    y.left = x.right20    x.right = y21    update(y)22    update(x)23    return x24
25
26def rotate_left(x):27    y = x.right28    x.right = y.left29    y.left = x30    update(x)31    update(y)32    return y33
34
35def insert(node, key):36    if node is None:37        return Node(key)38    if key < node.key:39        node.left = insert(node.left, key)40    else:41        node.right = insert(node.right, key)42    update(node)43    balance = height(node.left) - height(node.right)44    # Four imbalance cases: LL, RR, LR, RL45    if balance > 1 and key < node.left.key:46        return rotate_right(node)47    if balance < -1 and key > node.right.key:48        return rotate_left(node)49    if balance > 1:50        node.left = rotate_left(node.left)51        return rotate_right(node)52    if balance < -1:53        node.right = rotate_right(node.right)54        return rotate_left(node)55    return node56
57
58def inorder(node):59    if node is None:60        return []61    return inorder(node.left) + [node.key] + inorder(node.right)62
63
64root = None65for key in [10, 20, 30, 40, 50, 25]:66    root = insert(root, key)67
68print("Inorder:", inorder(root))69print("Root:", root.key, "| tree height:", root.height)
להריץ את הקוד הזה בעורך ה-Python אונליין

שאלות נפוצות על עץ AVL

מהו מקדם איזון בעץ AVL?
מקדם האיזון של צומת הוא גובה תת העץ השמאלי שלו פחות גובה תת העץ הימני שלו. עץ AVL שומר על מקדם האיזון של כל צומת בערכים -1, 0 או +1; אם הכנסה מוציאה אותו מהטווח הזה, רוטציה מחזירה את האיזון.
מה ההבדל בין עץ AVL לעץ אדום-שחור?
שניהם עצי BST שמאזנים את עצמם עם פעולות O(log n). עצי AVL מאוזנים בצורה קפדנית יותר, ולכן חיפושים בהם מהירים מעט יותר, אבל הם עשויים לבצע יותר רוטציות בהכנסה ובמחיקה. עצים אדומים-שחורים מאוזנים בצורה רופפת יותר ומעדיפים פחות רוטציות, ולכן ספריות סטנדרטיות רבות משתמשות בהם עבור מפות וקבוצות.
למה להשתמש בעץ AVL ולא בעץ חיפוש בינארי רגיל?
BST רגיל יכול להידרדר לפעולות O(n) אם הערכים מגיעים בסדר ממוין ויוצרים שרשרת עקומה. עץ AVL מבצע רוטציות כדי להישאר מאוזן, ומבטיח גובה ופעולות של O(log n) בלי קשר לסדר ההכנסה.
האם עץ AVL עדיף על עץ אדום-שחור עבור אינדקס של מסד נתונים?
זה תלוי בעומס העבודה. עצי AVL מאוזנים בצורה נוקשה יותר, ולכן הם מנצחים כשקריאות הן רוב העבודה ורוצים את מסלולי החיפוש הקצרים ביותר. אבל רוב מסדי הנתונים וספריות השפות בוחרים בעצים אדומים-שחורים (או בעצי B), כי הם מתאזנים עם פחות רוטציות בעומסים עתירי כתיבה, וזה חשוב יותר כשהכנסות ומחיקות תכופות.
כמה רוטציות צריכה הכנסה אחת לעץ AVL?
לכל היותר רוטציה אחת, פשוטה או כפולה (בשני שלבים), מספיקה כדי לאזן את העץ אחרי הכנסת ערך אחד. הסיבה היא שהכנסה מגדילה את גובה תת העץ באחד לכל היותר, ולכן תיקון אחד באב הקדמון הנמוך ביותר שיצא מאיזון מספיק. מחיקה שונה: היא יכולה לדרוש עד O(log n) רוטציות כשהאיזון מתפשט כלפי השורש.
האם צריך לעדכן את גובהי הצמתים אחרי כל רוטציה?
כן. באג נפוץ הוא לסובב את המצביעים נכון אבל לשכוח לחשב מחדש את הגובה של שני הצמתים המעורבים. אחרי כל רוטציה צריך לעדכן קודם את הגובה של הצומת שירד, ואז את הגובה של הצומת שעלה, כי הגובה של הצומת שעלה תלוי בילדיו החדשים. דילוג על זה משאיר מקדמי איזון מיושנים ששוברים את החלטות האיזון הבאות.
איור של שפות התכנות ב-Coddy

לשלוט באלגוריתמים עם Coddy

להתחיל