150 likes | 693 Views
עצים בינאריים - תזכורת. 1. 2. 3. 4. 5. 6. דרגת צומת: מספר הבנים של הצומת שורש: ראש העץ עלה: צומת שאין לו בנים צומת פנימי: צומת שאינו עלה מרחק בין שני צמתים: מספר הקשתות במסלול (היחיד) שמחבר בין שתי הצמתים. עומק של צומת: מרחק הצומת מהשורש גובה של עץ: העומק המקסימלי של צומת בעץ
E N D
עצים בינאריים - תזכורת 1 2 3 4 5 6 דרגת צומת: מספר הבנים של הצומת שורש: ראש העץ עלה: צומת שאין לו בנים צומת פנימי: צומת שאינו עלה מרחק בין שני צמתים: מספר הקשתות במסלול (היחיד) שמחבר בין שתי הצמתים. עומק של צומת: מרחק הצומת מהשורש גובה של עץ: העומק המקסימלי של צומת בעץ תת עץ של צומת : אוסף כל הצמתים כך שהמסלול בין לשורש עובר דרך . גובה של צומת : גובה תת העץ של .
עץ בינארי שלם (complete) עץ בינארי מלא (full) עץ בינארי מלא שבו כל העלים באותו העומק. לכל צומת פנימי 2 בנים. הערה: אנו עוד לא עוסקים בעצי חיפוש בינאריים. • עץ חיפוש בינארי הינו עץ בינארי המקיים את התכונה הבאה: • בהינתן צומת עם מפתח : • כל הצמתים בתת העץ הימני הם בעלי מפתחות גדולים יותר • כל הצמתים בתת העץ השמאלי הם בעלי מפתחות קטנים יותר
מימוש עצים בינאריים struct node { int key; void* info; struct node* left_son; struct node* right_son; } left_son right_son הערות: 1. לכל צומת מפתח ייחודי keyשמבדיל בינו לבין שאר הצמתים. 2. אם לא קיים בן שמאלי או בן ימני, ערך המצביע יהיה NULL. 3. ניתן לשמור בכל צומת גם מצביע לצומת האב.
סיורים בעצים סיור Preorder:טיפול בשורש, סיור Preorder בתת העץ השמאלי, סיורPreorderבתת העץ הימני. סיור Inorder: סיור Inorder בתת העץ השמאלי, טיפול בשורש, סיור Inorder בתת העץ הימני. סיור Postorder: סיור Postorder בתת העץ השמאלי, סיור Postorder בתת העץ הימני, טיפול בשורש. http://nova.umuc.edu/~jarc/idsv/ הדגמה:
מימוש סיור Inorder ללא רקורסיה: בעזרת רקורסיה: ptr = root; while (1) { while (ptr != NULL) { push(ptr); ptr = ptr->left; } if (is_empty()) break; ptr = pop(); do_something(ptr); ptr = ptr->right; } inorder(node* p) { if (p == NULL) return; inorder(p->left); do_something(p); inorder(p->right); } הפונקציה נקראת תחילה עם שורש העץ: inorder(root) • ניתוח סיבוכיות עבור שני המימושים: • זמן: (בהנחה ש do_something לוקחת ) • זיכרון: (כאשר הוא גובה העץ)
שאלה על מנת לגבות עץ בינארי , הוחלט לשמור תוצאות של סריקות על העץ, כך שבמקרה והעץ ימחק, ניתן יהיה לשחזר את העץ. לכל אחת מההצעות הבאות קבעו האם ניתן לשחזר את העץ או לא, בהינתן המידע שנשמר. 2 2 1 2 א. סיור Preorder לא. נתבונן בשני עצים שסריקת ה Preorder שלהם היא זהה: 1 2 1 1 Preorder: 1,2 ב. סיור Postorder לא. עבור אותה דוגמא, סריקת ה Postorder היא . ג. סיור Inorder לא. נסתכל על שני העצים הבאים: Inorder: 1,2
שאלה ד. סיור Preorder וסיור Inorder כן. נראה ע"י דוגמא כיצד משחזרים את העץ משני סיורים אלו: Inorder Preorder שורש העץ הוא האיבר הראשון בסיור ה Preorder. נחלק כל סיור לשני תתי סיורים שמתאימים לתת העץ השמאלי והימני של השורש: 1 נפעיל את הפתרון שהוצע בצורה רקורסיבית על שני תתי העצים ונקבל את העץ המקורי.
מימוש סיור Inorder בסיבוכיות זיכרון O(1) • נחזיק שני מצביעים: • - שיצביע על הצומת הנוכחי בו אנחנו נמצאים. • - שיצביע על הצומת הקודם בו היינו. • נבצע סיורInorder בדומה לקוד הלא רקורסיבי שהוצג קודם, אך במקום לשמור מחסנית, נקבע בכל שלב את הצעד הבא לפי המיקום של ביחס ל . • למשל, בכל פעם שנעלה להורה , נבדוק אם עלינו מבנו השמאלי או מבנו הימני. • אם עלינו מהבן השמאלי של : • 1. נבצע את do_something().2. נמשיך בתת העץ הימני של . • אם עלינו מהבן הימני של , סימן שסיימנולסייר בתת העץ של , לכן:1. נקבע את להיות ההורה של 2. נקבע את להיות . v v v v
דוגמאות לשימוש בסיורים • 1. חישוב מספר הצמתים בעץ בינארי: • intcount(node *p) { • if (p == NULL) return0; • return (1 + count(p->left) + count(p->right)); • } • 2. מציאת המסלול הכבד ביותר בעץ • נתון עץ בעל צמתים, בו כל צומת מכיל מפתח ושני מצביעים לבנים. הציעו אלגוריתם לחישוב ערכו של המסלול הכבד ביותר משורש לעלה כלשהו (המסלול שסכום המפתחות של צמתיו הוא מקסימלי) שרץ בזמן . על האלגוריתם להדפיס מסלול זה. • מותר להוסיף שדות נוספים לצמתים לצורך הפתרון.
דוגמאות לשימוש בסיורים פתרון שאלה 2
עצי חיפוש בינאריים • עץ חיפוש בינארי הינו עץ בינארי המקיים את התכונה הבאה: • בהינתן צומת בעל מפתח : • כל הצמתים בתת העץ הימני הם בעלי מפתחות גדולים יותר • כל הצמתים בתת העץ השמאלי הם בעלי מפתחות קטנים יותר • באמצעות עץ חיפוש בינארי ניתן לממש את מבנה הנתונים מילון. • מבנה הנתונים מילון תומך בשלושת הפעולות הבאות: • Find() חפש האם נמצא במילון. • Insert()הכנס את למילון. • Delete()הוצא את מהמילון.
חיפוש בעץ חיפוש בינארי • נרצה למצוא האם קיים צומת בעל מפתח בעץ. נתחיל משורש העץ (נסמנו ). • אם , נחפש בצורה רקורסיבית את בתת העץ הימני של . • אם , נחפש בצורה רקורסיבית את בתת העץ השמאלי של . • אם , מצאנו את . • אם הגענו לסוף מסלול החיפוש מבלי שמצאנו את , אז לא נמצא בעץ. 13 15 3 1 7 20 5 10 17 • במקרה הגרוע, נצטרך לעבור על צמתים, כאשר גובה העץ. לכן, סיבוכיות הזמן של פעולת החיפוש היא . • במקרה הגרוע: , למשל כאשר העץ הוא שרוך. • במקרה הטוב: , למשל עבור עץ שלם. • במקרה הממוצע: .
הכנסה לעץ חיפוש בינארי נרצה להכניס צומת בעל מפתח לעץ. נחפש את . אם מצאנו אותו, נסיים. אחרת, נוסיף בן חדש (ימני או שמאלי בהתאמה) לצומת האחרון במסלול החיפוש. הצומת החדש שמתווסף לעץ תמיד יהיה עלה. Insert(14) 13 15 3 14 1 7 20 5 10 17 סיבוכיות: סיבוכיות הזמן של פעולת ההכנסה הינה , כפי שהראנו עבור פעולת החיפוש.
הוצאה מעץ חיפוש בינארי נרצה למחוק צומת בעל מפתח מהעץ. נסמן ב את אביו. נפריד ל מקרים: 1. הוא עלה: נמחק את מהעץ ונסיים. 2. ל בן יחיד: נחבר את הבן של ל באופן הבא: v v x x v v x x
הוצאה מעץ חיפוש בינארי • 3. ל שני בנים: נחליף בין לבין האיבר העוקב של (נסמנו ב ): • האיבר העוקב של : האיבר הקטן ביותר בעץ שגדול מ . • אם ל שני בנים, הוא האיבר המינימלי בתת העץ הימני של . • כעת ל יש בן אחד לכל היותר (חשבו למה). נמחק את כפי שתיארנו קודם. v v v y y x x y סיבוכיות הזמן של שלושת הפעולות Find, Insert, Deleteבעץ חיפוש בינארי הוא . לכן, כל אחת מפעולות אלה לוקחות במקרה הגרוע, אך בממוצע על הקלט.