הרצאה 07 עצים קרן כליף.

Slides:



Advertisements
Similar presentations
Completeness and Expressiveness. תזכורת למערכת ההוכחה של לוגיקה מסדר ראשון : אקסיומות 1. ) ) (( 2. )) ) (( )) ( ) ((( 3. ))) F( F( ( 4. ) v) ( ) v ((
Advertisements

1 Data Structures, CS, TAU, RB-Tree1 עץ אדום-שחור  עץ חיפוש בינארי  בכל צומת ביט אינפורמציה נוסף - צבע  עץ “כמעט מאוזן”  (O(log n במקרה גרוע ביותר.
מבוא למדעי המחשב לתעשייה וניהול
מבוא למדעי המחשב לתעשייה וניהול דוגמאות ותרגול נוסף במערך חד ממדי הרצאה 12.
1 Trees CLRS: chapter A hierarchical combinatorial structure הגדרה רקורסיבית: 1. צומת בודד. זהו גם שורש העץ. 2. אם n הוא צומת ו T 1 ….T K הינם עצים,
Recitation #9. Q1 גרף מכוון מורכב מקבוצה של צמתים (nodes) ומקשתות מכוונות (arcs) המחברות ביניהם. כל קשת מכוונת יוצאת מצומת אחד ונכנסת לצומת אחר. ( בגרפים.
רקורסיות נושאי השיעור פתרון משוואות רקורסיביות שיטת ההצבה
עצים ועצי חיפוש חומר קריאה לשיעור זה Chapter 5.5– Trees (91 – 97)
תכנות תרגול 6 שבוע : חישוב e זוהי הנוסחא לחישוב e נראה כיצד לתרגם אותה לפונקציה n n.
תרגול 5 רקורסיות. רקורסיה קריאה של פונקציה לעצמה –באופן ישיר או באופן עקיף היתרון : תכנות של דברים מסובכים נעשה ברור ונוח יותר, מכיוון שזו למעשה צורת.
עבודה סמינריונית Prelude to Ukkonen algorithm ON-LINE CONSTRUCTION OF SUFFIX TREES מגישים : עיד מוחמד טיבי פיראס.
חורף - תשס " ג DBMS, צורות נורמליות 1 צורה נורמלית שלישית - 3NF הגדרה : תהי R סכמה רלציונית ותהי F קבוצת תלויות פונקציונליות מעל R. R היא ב -3NF.
1 Trees CLRS: chapter A hierarchical combinatorial structure הגדרה רקורסיבית: 1. צומת בודד. זהו גם שורש העץ. 2. אם n הוא צומת ו T 1 ….T K הינם עצים,
2 Suffix Tree: Definition Suffix tree T על מחרוזת S שגודלה n, הוא עץ מכוון עם בדיוק n עלים ממוספרים מ -1 עד n. לכל צומת פנימית ( חוץ מהשורש ) יש לפחות.
1 Data Structures, CS, TAU, Splay Tree Splay Tree  מימוש של עץ חיפוש בינארי  מטרה לדאוג ל- Amortized Time  פעולה בודדת יכולה לקחת O(N)  אבל כל רצף.
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
תכנות תרגול 6 שבוע : תרגיל שורש של מספר מחושב לפי הסדרה הבאה : root 0 = 1 root n = root n-1 + a / root n-1 2 כאשר האיבר ה n של הסדרה הוא קירוב.
11 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
ערמות ; מבני נתונים 09 מבוסס על מצגות של ליאור שפירא, חיים קפלן, דני פלדמן וחברים.
תכנות תרגול 6 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
1 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
תרגול 7 עצי B
שאלה 1 נתון כביש ישר עם תחנות דלק בנקודות , בנקודת המוצא נתונה מכונית עם תא דלק שמספיק ל-100 ק"מ. מחיר מילוי תא הדלק בתחנה.
1 ייצוג באמצעות עצים שונים מתוחכם רק לקבוצות גדולות (תקורה בפעולות ובתכנות!!!) עצי חיפוש בינאריים BINARY SEARCH TREES תחום סדור (> < =) תחום איברים גדול.
תכנות תרגול 5 שבוע : הגדרת פונקציות return-value-type function-name(parameter1, parameter2, …) הגדרת סוג הערכים שהפונקציה מחזירה שם הפונקציהרשימת.
גרפים - Graphs גרף G(V,E) מורכב מקבוצת צמתים V וקבוצת קשתות E.
עצים מאוזנים הגדרה: משפחת עצים תקרא מאוזנת אם ,h(T) = O(log n) באשר T הוא עץ במשפחה, n הוא מספר הצמתים ב-T ו-h(T) הוא הגובה של T עצי (Adelson-Velsky,
מערכים עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר עד היום כדי לייצג 20 סטודנטים נאלצנו להגדיר int grade1, grade2, …, grade20; int grade1, grade2, …, grade20;
עקרון ההכלה וההדחה.
מבוא למדעי המחשב תרגול 3 שעת קבלה : יום שני 11:00-12:00 דוא " ל :
Data Structures, CS, TAU, RB-Tree 1 עץ אדום-שחור - עץ חיפוש בינארי - בכל צומת ביט אינפורמציה נוסף - צבע « עץ “ כמעט מאוזן ” « (O(log n במקרה גרוע ביותר.
1 Data Structures, CS, TAU, RB-Tree1 עץ אדום-שחור  עץ חיפוש בינארי  בכל צומת ביט אינפורמציה נוסף - צבע  עץ “כמעט מאוזן”  (O(log n במקרה גרוע ביותר.
Tirgul 13: Trees 1. הגדרות עץ – מודל מופשט של מבנה היררכי. עץ מורכב מאוסף של צמתים (קודקודים) עם יחס אבא-בן. שורש בעץ – צומת ללא אבא. בכל עץ יש בדיוק.
מבוא מורחב למדעי המחשב בשפת Scheme תרגול 10. אג'נדה שאלות מבחינות חזרה על מימוש stream אפשרי 2.
עצים בינאריים - תזכורת דרגת צומת שורש עלה צומת פנימי מרחק בין 2 צמתים
1 - גמישות בבינאריות גמישות בעומק - עץ חיפוש בינארי: ממוצע O(log n) גרוע ביותר (O(n - היינו רוצים לשמור את העץ מאוזן תמיד Data Structures, CS, TAU
1 מבוא למדעי המחשב סיבוכיות. 2 סיבוכיות - מוטיבציה סידרת פיבונאצ'י: long fibonacci (int n) { if (n == 1 || n == 2) return 1; else return (fibonacci(n-1)
Lecture 13 Maximal Accurate Forests From Distance Matrix.
(C) סיון טל גילוי מידע וזיהוי תבניות תרגול מס. 9 גילוי מידע וזיהוי תבניות תרגול מס. 9 דחיסת נתונים מהו קידוד תכונות של קידודים אי - שוויון קרפט.
תרגול 4 21/3/2007 מבני נתונים 07b ליאור שפירא. תזכורת – B-trees  לכל צומת x יש השדות הבאים n[x] מס ' מפתחות ב -x המפתחות עצמם בסדר לא יורד כל צומת פנימי.
1 Trees CLRS: chapter A hierarchical combinatorial structure הגדרה רקורסיבית: 1. צומת בודד. זהו גם שורש העץ. 2. אם n הוא צומת ו T 1 ….T K הינם עצים,
Data Structures Hanoch Levi and Uri Zwick March 2011 Lecture 3 Dynamic Sets / Dictionaries Binary Search Trees.
1 Introduction to Programming in C - Fall 2010 – Erez Sharvit, Amir Menczel 1 Introduction to Programming in C תרגול
מספרים אקראיים ניתן לייצר מספרים אקראיים ע"י הפונקציה int rand(void);
Programming Arrays.
מבני נתונים רשימה מקושרת, מחסנית ותור
Tirgul 12 Trees 1.
Formal Specifications for Complex Systems (236368) Tutorial #1
הרצאה 10 פונקציות עם מספר משתנה של פרמטרים
מבוא למדעי המחשב סיבוכיות.
הקצאות דינאמיות בשילוב מבנים
אינדקסינג והשינג (indexing & hashing)
מיונים וחיפושים קרן כליף.
מצביעים קרן כליף.
SQL בסיסי – הגדרה אינדוקטיבית
תירגול 14: מבני נתונים דינאמיים
הרצאה 06 רשימות מקושרות קרן כליף.
תרגול מס' 7: Memoization Quicksort תרגילים מתקדמים ברקורסיה
הקצאות דינאמיות קרן כליף.
מבני נתונים עצים קרן כליף.
תכנות מכוון עצמים בשפת JAVA
ממשקים - interfaces איך לאפשר "הורשה מרובה".
בעיות נוספות ב-NPC.
Marina Kogan Sadetsky –
Randomized Search Trees
תרגול 8 תחומי הכרה פונקציות
תכנות מכוון עצמים ושפת JAVA
שיעור עשירי: מיונים, חיפושים, וקצת סיבוכיות חישוב
איתור נתונים מתקדם, בעזרת vlookup וחברים
מבוא לתכנות ב- Java תרגול 10 - רשימות מקושרות.
Presentation transcript:

הרצאה 07 עצים קרן כליף

ביחידה זו נלמד: הגדרות יצירת עץ מעברים על עצים חיפוש בעץ ממערכים לעץ מעץ לרשימה © Keren Kalif

הגדרות עץ הוא מבנה נתונים המכיל נתונים היררכיים למשל: אילן יוחסין, מבנה אירגוני מבנה-נתונים זה מורכב מצמתים (העיגולים הירוקים) ומקשתות (החצים) "שורש" הוא הצומת העליון, אף צומת אחר אינו מכיל קשת אליו "אבא": צומת שיש ממנו קשת לצומת אחר "בן" (או: ילד, או: צומת פנימי): צומת שיש לו אבא כל הצמתים הם בנים פרט לשורש "עלה": צומת שאין לו בנים 1  שורש 3 8 2  בן  אבא 4 9 6 1  בן 5 5 7  עלה © Keren Kalif

הגדרות (2) רמה: המרחק של צומת מהשורש מסלול: רצף של צמתים שמתחיל בשורש השורש נמצא ברמה 0 מסלול: רצף של צמתים שמתחיל בשורש למשל: 1 39 אורך מסלול: מס' הקשתות במסלול שקול לרמה של הצומת שבסוף המסלול אורך המסלול 1 39 הוא 2 גובה העץ: אורך המסלול הארוך ביותר, הרמה המקסימלית גובה עץ זה הוא 3 רמה 1 2 3 1 3 8 2 4 9 6 5 7 © Keren Kalif

הגדרות (3) תת-עץ הינו עץ הנפרש מצומת מסויים X אב קדמון של Y אם: תת-העץ הנ"ל נפרש מהצומת עם הערך 3 X אב קדמון של Y אם: Y נפרש בתת-העץ שיוצא מ- X. כלומר, במסלול מהשורש אל Y עוברים דרך X למשל, 3 הוא אב קדמון של 4, 9, 5 ו- 7 1 3 8 2 4 9 6 5 7 © Keren Kalif

אנחנו נתמקד בעצים בינאריים עץ בינארי עץ בינארי הוא עץ שלכל צומת יש מקסימום 2 ילדים 1 3 2 4 9 6 8 7 typedef int type; typedef struct TreeNode { type data; struct TreeNode* left; struct TreeNode* right; } TNode; typedef struct TNode* root; } Tree; אנחנו נתמקד בעצים בינאריים © Keren Kalif

פונקציה היוצרת צומת חדשה TNode* createNewTNode(type data, TNode* left, TNode* right) { TNode* newNode = (TNode*)calloc(1, sizeof(TNode)); newNode->data = data; newNode->left = left; newNode->right = right; return newNode; } void main() Tree tr; TNode* left = createNewTNode(1, NULL, NULL); TNode* right = createNewTNode(2, NULL, NULL); TNode* root = createNewTNode(3, left, right); tr.root = root; root tr 3 root 1 left 2 right © Keren Kalif

וכדי לייצר את העץ שלנו: root tr 1 3 2 4 9 6 8 7 Tree buildTree () { Tree t; t.root = (TNode*)calloc(1, sizeof(TNode)); t.root->data = 1; t.root->left = (TNode*)calloc(1, sizeof(TNode)); t.root->left->data = 3; t.root->left->left = (TNode*)calloc(1, sizeof(TNode)); t.root->left->left->data = 4; t.root->left->right = (TNode*)calloc (1, sizeof(TNode)); t.root->left->right->data = 9; t.root->left->right->right = (TNode*)calloc (1, sizeof(TNode)); t.root->left->right->right->data = 7; t.root->right = (TNode*)calloc(1, sizeof(TNode)); t.root->right->data = 2; t.root->right->left = (TNode*)calloc(1, sizeof(TNode)); t.root->right->left->data = 6; t.root->right->right = (TNode*)calloc(1, sizeof(TNode)); t.root->right->right->data = 8; return t; } וכדי לייצר את העץ שלנו: root tr 1 3 2 4 9 6 8 7 © Keren Kalif

עצים ורקורסיות הרעיון מאחורי כל הפונקציות הקשורות לעצים הוא לבצע את העבודה עבור כל אחד מתתי-העצים של צומת, וכנ"ל עבור תתי- העצים שלו, ולכן יהיה שימוש רב ברקורסיות © Keren Kalif

פונקציה המחזירה את מספר הצמתים בעץ 1 3 2 int numOfNodes(const Tree* t) { return numOfNodesRec(t->root); } int numOfNodesRec(const TNode* root) if (root == NULL) return 0; return 1 + numOfNodesRec(root->left) + numOfNodesRec(root->right); 4 9 6 8 7 4 3 8 © Keren Kalif

פונקציה המחשבת גובה העץ תזכורת:: root root עפ"י ההגדרה זהו עץ בגובה 0, מאחר ואורך המסלול הארוך ביותר הוא 0... 3 עפ"י ההגדרה גובהו של עץ שהוא NULL אינו מוגדר... int height(const Tree* t) { return heightRec(t->root); } int heightRec(const TNode* root) if (root == NULL) return 0; return 1 + max(heightRec(root->left), heightRec(root->right)); עבור עץ עם שורש בלבד הפונקציה תחזיר 1, ועבור עץ ריק הפונקציה תחזיר 0. © Keren Kalif

הערך 1- אינו באמת גובה העץ אלא מהווה אינדיקציה שהעץ ריק. אבל... הבעייתיות: גובה של עץ המכיל רק שורש הוא 0 יחד עם זאת, תנאי העצירה של הרקורסיה הוא כאשר הצומת הוא NULL, ואם נחזיר גם במקרה זה 0, למעשה גם עץ עם שורש בלבד וגם עץ ללא צמתים בלבד מחזירים תוצאה זהה.. int height(const Tree* t) { return heightRec(t->root); } int heightRec(const TNode* root) if (root == NULL) return 1-; return 1 + max(heightRec(root->left), heightRec(root->right)); הערך 1- אינו באמת גובה העץ אלא מהווה אינדיקציה שהעץ ריק. ערך זה נבחר שרירותית ויכל להיות כל ערך אחר, אבל אז כמובן הפונקציה לא הייתה מחזירה את הערך האמיתי.. © Keren Kalif

פתרון שאינו מגביל את הערך המוחזר עבור עץ ריק להיות 1- 3 3 3 3 תת עץ תת עץ תת עץ תת עץ int heightRec(const TNode* root) { if (root == NULL) return -700; // can be any other value else if (root->left == NULL && root->right == NULL) return 0; else if (root->right == NULL) // only left son return 1 + heightRec(root->left); else if (root->left == NULL) // only right son return 1 + heightRec(root->right); else // has both sons return 1 + max( heightRec(root->left), heightRec(root->right) ); } © Keren Kalif

הדפסת ערכי העץ כמו כל מעבר על עצים, נעשה זאת ברקורסיה: InOrder: תת-עץ שמאלי, שורש, תת-עץ ימני (LDR) PreOrder: שורש, תת-עץ שמאלי, תת-עץ ימני (DLR) PostOrder: תת-עץ שמאלי, תת-עץ ימני, שורש (LRD) 1 3 2 4 9 6 8 7 InOrder: 4 3 9 7 1 6 2 8 PreOrder: 1 3 4 9 7 2 6 8 PostOrder: 4 7 9 3 6 8 2 1 © Keren Kalif

הדפסת ערכי העץ - InOrder InOrder: תת-עץ שמאלי, שורש, תת-עץ ימני (LDR) 1 3 2 4 9 6 8 7 void printInOrder(Tree t) { printInOrderRec(t.root); } void printInOrderRec(TNode *t) if (t == NULL) return; printInOrderRec(t->left); printf ("%d ",t->data); printInOrderRec(t->right); InOrder: 4 3 9 7 1 6 2 8 L D D R L D R R L R D © Keren Kalif

הדפסת ערכי העץ - PreOrder PreOrder: שורש, תת-עץ שמאלי, תת-עץ ימני (DLR) 1 3 2 4 9 6 8 7 void printPreOrder(Tree t) { printPreOrderRec(t.root); } void printPreOrderRec(TNode *t) if (t == NULL) return; printf ("%d ",t->data); printPreOrderRec(t->left); printPreOrderRec(t->right); PreOrder: 1 3 4 9 7 2 6 8 D R D L R D L R D L R © Keren Kalif

הדפסת ערכי העץ - PostOrder PostOrder: תת-עץ שמאלי, תת-עץ ימני, שורש (LRD) 1 3 2 4 9 6 8 7 void printPostOrder(Tree t) { printPostOrderRec(t.root); } void printPostOrderRec(TNode *t) if (t == NULL) return; printPostOrderRec(t->left); printPostOrderRec(t->right); printf ("%d ",t->data); PostOrder: 4 7 9 3 6 8 2 1 R D L R D L D R L R D © Keren Kalif

שחרור הזכרון של עץ ניתן לראות כי איברי העץ משוחררים בסדר PostOrder השורש חייב להשתחרר בסוף מאחר והוא זה שמכיל את ההצבעות לתתי-העצים שתחתיו... void freeTree(Tree t) { freeTreeRec(t.root); } void freeTreeRec(TNode *t) if (t == NULL) return; freeTreeRec(t->left); freeTreeRec(t->right); free (t); © Keren Kalif

הדפסת העץ לפי רמות רמה 1 2 3 void main() { int i; Tree tr = buildTree(); for (i=0 ; i < 6 ; i++) { printf("\nLevel %d: ", i); printLevel(tr.root, i); } printf("\n"); freeTree(tr); הדפסת העץ לפי רמות רמה 1 2 3 1 3 2 4 9 6 8 7 void printLevel(TNode* root, int level) { if (root == NULL) return; if (level == 0) printf("%d ", root->data); else { printLevel(root->left, level-1); printLevel(root->right, level-1); } © Keren Kalif

חיפוש בעץ TNode* find(Tree t, type val) { return findRec(t.root, val); } TNode* findRec(TNode* root, type val) TNode* item; if (root == NULL) return NULL; if (root->data == val) return root; item = findRec(root->left, val); if (item != NULL) return item; else return findRec(root->right, val); הפונקציה מחפשת ערך מסויים בעץ, ומחזירה את הצומת שבו הוא נמצא, או NULL אם הערך אינו קיים בעץ © Keren Kalif

העתקת עץ TNode* copyTree(TNode* root) { TNode* newRoot; if (root == NULL) return NULL; newRoot = createNewTNode(root->data, NULL, NULL); newRoot->left = copyTree(root->left); newRoot->right = copyTree(root->right); return newRoot; } newRoot = createNewTNode(root->data, copyTree(root->left), copyTree(root->right)); © Keren Kalif

מציאת הערכים המינימלי והמקסימלי בעץ (1) void getMinAndMaxFromTree(TNode* root, int* minimum, int* maximum) { if (root->left == NULL && root->right == NULL) *minimum = *maximum = root->data; else if (root->left == NULL) // has only right son getMinAndMaxFromTree(root->right, minimum, maximum); if (root->data < *minimum) *minimum = root->data; if (root->data > *maximum) *maximum = root->data; } else if (root->right == NULL) // has only left son getMinAndMaxFromTree(root->left, minimum, maximum); … אם יש רק שורש, אז הוא המינימום והמקסימום אם יש רק בן ימני, נחפש בו את המינימום והמקסימום ונשווה אותם מול השורש אם יש רק בן שמאלי, נחפש בו את המינימום והמקסימום ונשווה אותם מול השורש © Keren Kalif

מציאת הערכים המינימלי והמקסימלי בעץ (2) מציאת הערכים המינימלי והמקסימלי בעץ (2) void getMinAndMaxFromTree(TNode* root, int* minimum, int* maximum) { … else // has both sons int leftMin, rightMin, leftMax, rightMax; getMinAndMaxFromTree(root->left, &leftMin, &leftMax); getMinAndMaxFromTree(root->right, &rightMin, &rightMax); *minimum = min(root->data, min(leftMin, rightMin)); *maximum = max(root->data, max(leftMax, rightMax)); } נמצא את המינימום והמקסימום של כל אחד מתתי-העצים, ונחזיר את המינימום והמקסימום בינהם לבין הערך שבשורש © Keren Kalif

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים הרעיון: לבדוק בכל תת-עץ מה אורך המסלול הארוך ביותר שאיבריו עוקבים לבדוק מה המסלול הארוך ביותר המתחיל מהשורש שאיבריו עוקבים להחזיר את המקסימום מבין 2 הערכים שנמצאו המסלול הרציף הארוך ביותר הוא באורך 2 1 3 2 4 9 6 8 7 1 3 2 4 9 6 8 7 5 המסלול הרציף הארוך ביותר הוא באורך 1 © Keren Kalif

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים תחזיר את אורך המסלול הארוך ביותר שאינו מתחיל מהשורש תחזיר כפרמטר פלט את אורך המסלול הארוך ביותר המתחיל מהשורש Int longestSequenceRec(TNode* root, int* longestFromRoot); int longestSequence(Tree tr) { int temp; if (tr.root == NULL) return ERROR; return longestSequenceRec(tr.root, &temp); } © Keren Kalif

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים (1) int longestSequenceRec(TNode* root, int* longestFromRoot) { if (root->left == NULL && root->right == NULL) *longestFromRoot = 0; return 0; } else if (root->left == NULL) // only right son int innerPathLen, pathFromRootLen; innerPathLen = longestSequenceRec(root->right, &pathFromRootLen); // check if the root contains a longer sequence if (root->data + 1 == root->right->data) *longestFromRoot = 1 + pathFromRootLen; else return max(innerPathLen, *longestFromRoot); ... אם לשורש אין בנים, אז גם אורך המסלול הרציף הארוך ביותר המתחיל מהשורש הוא 0, וגם המסלול הפנימי הוא 0 © Keren Kalif

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים (2) int longestSequenceRec(TNode* root, int* longestFromRoot) { ... else if (root->right == NULL) // only left son int innerPathLen, pathFromRootLen; innerPathLen = longestSequenceRec(root->left, &pathFromRootLen); // check if the root contains a longer sequence if (root->data + 1 == root->left->data) *longestFromRoot = 1 + pathFromRootLen; else *longestFromRoot = 0; return max(innerPathLen, *longestFromRoot); } © Keren Kalif

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים (3) int longestSequenceRec(TNode* root, int* longestFromRoot) { ... else // has the 2 sons int leftRootLen, rightRootLen; int innerFromLeft = longestSequenceRec(root->left, &leftRootLen); int innerFromRight = longestSequenceRec(root->right, &rightRootLen); if (root->data + 1 == root->left->data) leftRootLen++; else leftRootLen = 0; if (root->data + 1 == root->right->data) rightRootLen++; else rightRootLen = 0; *longestFromRoot = max(leftRootLen, rightRootLen); return max(*longestFromRoot, max(innerFromLeft, innerFromRight)); } © Keren Kalif

יצירת רשימה מעץ ע"י מעבר InOrder (1) נשתמש בפונקצית העזר המקבלת 2 רשימות ומשרשרת את הרשימה השניה לסוף הרשימה הראשונה void concatLists(List* l1, List* l2) { if (isEmpty(l1)) *l1 = *l2; //l1->head = l2->head; //l1->tail = l2->tail; } else if (!isEmpty(l2)) l1->tail->next = l2->head; l1->tail = l2->tail; © Keren Kalif

יצירת רשימה מעץ ע"י מעבר InOrder (2) List treeToListInOrder(TNode* root) { if (root == NULL) return makeEmptyList(); else List left = treeToListInOrder(root->left); List right = treeToListInOrder(root->right); insertValueToTail(&left, root->data); concatLists(&left, &right); return left; } ניתוח יעילות: insertValueToTail ו- concatLists ממומשות ביעילות של O(1) בכל קריאה רקורסיבית יש פעולות קבועות לכן היעילות הכוללת של הפונקציה היא כמספר הקריאות הרקורסיביות, כלומר כמספר הצמתים בעץ © Keren Kalif

מילוי עץ מנתוני מערכים בהינתן מערך המייצג נתוני עץ במעבר InOrder ומערך המייצג נתוני אותו עץ במעבר PreOrder יש לבנות את העץ. ידוע כי כל ערך מופיע מקסימום פעם אחת בלבד. למשל, בהינתן המערכים הבאים וגודלם יש לייצר את העץ המתאים: InOrder: 4 3 9 7 1 6 2 8 PreOrder: 1 3 4 9 7 2 6 8 1 3 2 4 9 6 8 7 © Keren Kalif

מילוי עץ מנתוני מערכים - הרעיון 1 3 2 4 9 6 8 7 הרעיון: ידוע כי השורש הוא האיבר הראשון במערך ה- preorder נמצא את מיקומו במערך ה- InOrder : מכך נדע מהי חלוקת האיברים בין 2 תתי-העצים וכן את כמות האיברים בכל תת-עץ (עבור תת-העץ השמאלי זה הגודל הכולל פחות האינדקס של השורש) (עבור תת-העץ הימני זה הגודל הכללי פחות 1, פחות האינדקס של השורש) InOrder: 4 3 9 7 1 6 2 8 PreOrder: 1 3 4 9 7 2 6 8 L R © Keren Kalif

הקוד int findIndex(int* arr, int size, int value) { int i; for (i=0 ; i < size ; i++) if (arr[i] == value) return i; return -1; // should never get here.. } TNode* createTreeFromPreOrderAndInOrder(int* pre, int* in, int size) TNode* root; int index; if (size == 0) return NULL; root = createNewTNode(pre[0], NULL, NULL); index = findIndex(in, size, pre[0]); root->left = createTreeFromPreOrderAndInOrder(pre+1, in, index); root->right = createTreeFromPreOrderAndInOrder(pre+1+index, in+1+index, size-index-1); return root; הקוד © Keren Kalif

פונקציה המדפיסה את כל הצמתים שלהם בן אחד בלבד void printOneSonRec(TNode* root) { if (root->left == NULL && root->right == NULL) return; else if (root->left == NULL) // only right son printf("%d ", root->data); printOneSonRec(root->right); } else if (root->right == NULL) // only left son printOneSonRec(root->left); else // has both sons 1 3 2 4 9 6 8 7 1 3 2 9 6 8 7 © Keren Kalif

פונקציה המחזירה את כמות תתי-העצים מגובה מסויים (1) void main() { int i; Tree tr = buildTree(); printf("Count sub trees of height:\n"); for (i=0 ; i < 6 ; i++) printf("sub trees of height %d: %d\n", i, countSubTreesOfHeight(tr, i)); freeTree(tr); } 1 3 2 4 9 6 8 7 שימו לב: לפעמים פונקציית העזר תזדקק לפרמטר נוסף כדי לבצע את העבודה.. int countSubTreesOfHeight (Tree tr, int h) { int treeHeight; if (tr.root == NULL) return -700; // error! return countSubTreesOfHeightRec(tr.root, h, &treeHeight); } פונקציית העזר תצטרך בכל שלב לדעת מה גובה תת-העץ, על מנת לדעת האם הוא מתאים לתנאי © Keren Kalif

פונקציה המחזירה את כמות תתי-העצים מגובה מסויים (2) int countSubTreesOfHeightRec(TNode* root, int h, int* treeHeight) { int leftHeight, rightHeight, countLeft, countRight; if (root->left == NULL && root->right == NULL) *treeHeight = 0; return h == 0 ? 1 : 0; } else if (root->right == NULL) // only left child countLeft = countSubTreesOfHeightRec(root->left, h, &leftHeight); rightHeight = 0; countRight = 0; … אם אין בנים, אזי גובה העץ הוא 0. במידה והגובה המבוקש הוא 0, נחזיר שיש עץ 1 כזה, אחרת נחזיר 0 אם יש רק בן שמאלי, נבדוק מה גובהו וכמה בנים שלו עונים לתנאי, ונאתחל את נתוני צד ימין ב- 0 © Keren Kalif

המשך... int countSubTreesOfHeightRec(TNode* root, int h, int* treeHeight) { int leftHeight, rightHeight, countLeft, countRight; … else if (root->left == NULL) // only right child countRight = countSubTreesOfHeightRec(root->right, h, &rightHeight); leftHeight = 0; countLeft = 0; } else // has both sons countLeft = countSubTreesOfHeightRec(root->left, h, &leftHeight); *treeHeight = max(leftHeight, rightHeight) + 1; if (*treeHeight == h) return 1; else return countLeft + countRight; אם יש רק בן ימני, נבדוק מה גובהו וכמה בנים שלו עונים לתנאי, ונאתחל את נתוני צד שמאל ב- 0 אם יש את 2 הבנים, נבקש את הנתונים עבור שניהם נעדכן את גובה העץ ונחזיר את הירך שחישבנו © Keren Kalif

האם הערך בכל צומת גדול מכל הערכים שבתתי-העצים שלו sum=20√ 21 sum=6√ sum=3√ 7 4 2 3 1 2 √ 1 פונקציית העזר תצטרך בכל שלב לדעת מה סכום הצמתים בעץ, על מנת שהאב יוכל לבדוק התאמה לתנאי, וכן האם תת-העץ בפני עצמו עומד בקריטריון הבדיקה © Keren Kalif

הקוד... int isNodeValueBiggerThanSubTrees(Tree tr) { int sum; return isNodeValueBiggerThanSubTreesRec(tr.root, &sum); } int isNodeValueBiggerThanSubTreesRec(TNode* root, int* subTreesSum) int leftSum, rightSum, leftRes, rightRes; if (root == NULL) *subTreesSum = 0; return 1; if (root->left == NULL && root->right == NULL) *subTreesSum = root->data; …. הקוד... © Keren Kalif

int isNodeValueBiggerThanSubTreesRec(TNode* root, int* subTreesSum) { int leftSum, rightSum, leftRes, rightRes; … // here means has at least one son if (root->right) // has right son rightRes = isNodeValueBiggerThanSubTreesRec(root->right, &rightSum); else rightSum = 0; rightRes = 1; } if (root->left) // has left son leftRes = isNodeValueBiggerThanSubTreesRec(root->left, &leftSum); leftSum = 0; leftRes = 1; *subTreesSum = root->data + leftSum + rightSum; return rightRes && leftRes && (root->data > leftSum + rightSum); המשך... © Keren Kalif

נשים לב.. 2 הדוגמאות האחרונות הן מאותו סגנון: הפונקציה הרקורסיבית מקבלת עוד נתון שעוזר לה לבצע את העבודה הראשונה עדכנה כפרמטר את גובה העץ השניה עדכנה כפרמטר את סכום הצמתים בעץ יחד עם זאת, שתיהן כתובות בסגנונות כתיבה שונים: בראשונה טיפלנו בנפרד בכל אחד מן המקרים בהם יש בנים אם יש רק תת-עץ שמאלי אם יש רק תת-עץ ימני אם יש שני תתי-עצים בשניה טיפלנו ביחד ב- 3 המקרים הנ"ל: חישבנו את התוצאה כאשר יש תת-עץ שמאלי חישבנו את התוצאה כאשר יש תת-עץ ימני איחדנו בין התוצאות 2 הצורות תקינות, לבחירתכם... © Keren Kalif

ביחידה זו למדנו: הגדרות יצירת עץ מעברים על עצים חיפוש בעץ ממערכים לעץ מעץ לרשימה © Keren Kalif