מבני נתונים עצים קרן כליף.

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 מגישים : עיד מוחמד טיבי פיראס.
תכנות תרגול 2 שבוע : שבוע שעבר כתבו תוכנית המגדירה שלושה משתנים מאתחלת אותם ל 1 2 ו 3 ומדפיסה את המכפלה שלהם את ההפרש שלהם ואת הסכום שלהם.
חורף - תשס " ג 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 תרגול
תכנות תרגול 14 שבוע:
תרגול 7 עצי B
2-3 trees עצי 3-2 ועצי דרגות Chapter 19: B trees (381 – 397) Chapter 15: Augmenting data structures (281 – 290) חומר קריאה לשיעור זה Lecture5 of Geiger.
מבוא כללי למדעי המחשב תרגול 3. לולאות while לולאות while while (condition) { loop body } במקרה של קיום התנאי מתבצע גוף הלולאה ברגע שהתנאי לא מתקיים נצא.
שאלה 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
תכנות בשפת C תרגול 15 תרגול חזרה 2 תרגילים ממבחנים
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.
תרגול 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.
הרצאה 10 פונקציות עם מספר משתנה של פרמטרים
ערמות make-heap Operation insert find-min delete-min union decrease-key delete 1 Binary Heap log n n Binomial Heap Fibonacci Heap † Relaxed Heap Linked.
מבוא למדעי המחשב סיבוכיות.
אינדקסינג והשינג (indexing & hashing)
מיונים וחיפושים קרן כליף.
מצביעים קרן כליף.
תירגול 14: מבני נתונים דינאמיים
הרצאה 06 רשימות מקושרות קרן כליף.
תרגול מס' 7: Memoization Quicksort תרגילים מתקדמים ברקורסיה
הרצאה 07 עצים קרן כליף.
תכנות מכוון עצמים בשפת JAVA
בעיות נוספות ב-NPC.
Marina Kogan Sadetsky –
Randomized Search Trees
תרגול 8 תחומי הכרה פונקציות
תכנות מכוון עצמים ושפת JAVA
שיעור עשירי: מיונים, חיפושים, וקצת סיבוכיות חישוב
איתור נתונים מתקדם, בעזרת vlookup וחברים
מבוא לתכנות ב- Java תרגול 10 - רשימות מקושרות.
Presentation transcript:

מבני נתונים עצים קרן כליף

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

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

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

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

אנחנו נתמקד בעצים בינאריים עץ בינארי עץ בינארי הוא עץ שלכל צומת יש מקסימום 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; אנחנו נתמקד בעצים בינאריים

פונקציה היוצרת צומת חדשה 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

וכדי לייצר את העץ שלנו: 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

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

פונקציה המחזירה את מספר הצמתים בעץ 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

פונקציה המחשבת גובה העץ תזכורת:: 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.

אבל... הבעייתיות: גובה של עץ המכיל רק שורש הוא 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- גורם לתיקון התוצאה כך שאם יש רק שורש, התוצאה תהיה 0, ואם קיבלנו 1- משמע השורש ריק

פתרון נוסף – החזרת ERROR: תיקון במעטפת 3 3 3 3 תת עץ תת עץ תת עץ תת עץ int height(const Tree* t) { if (t->root == NULL) return ERROR; return heightRec(t->root); } int heightRec(const TNode* root) if (root == NULL) return 0; if (root->left== NULL && root->right==NULL) return 0; return 1 + max(heightRec(root->left), heightRec(root->right));

פתרון נוסף 3 3 3 3 תת עץ תת עץ תת עץ תת עץ int heightRec(const TNode* root) { if (root == NULL) return ERROR; 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) ); }

הדפסת ערכי העץ כמו כל מעבר על עצים, נעשה זאת ברקורסיה: 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

הדפסת ערכי העץ - 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

הדפסת ערכי העץ - 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

הדפסת ערכי העץ - 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

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

הדפסת העץ לפי רמות רמה 1 2 3 1 3 2 4 9 6 8 7 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); }

חיפוש בעץ 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 אם הערך אינו קיים בעץ

העתקת עץ 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));

מציאת הערכים המינימלי והמקסימלי בעץ (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); } … אם יש רק שורש, אז הוא המינימום והמקסימום אם יש רק בן ימני, נחפש בו את המינימום והמקסימום ונשווה אותם מול השורש אם יש רק בן שמאלי, נחפש בו את המינימום והמקסימום ונשווה אותם מול השורש

מציאת הערכים המינימלי והמקסימלי בעץ (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)); } נמצא את המינימום והמקסימום של כל אחד מתתי-העצים, ונחזיר את המינימום והמקסימום בינהם לבין הערך שבשורש

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

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים תחזיר את אורך המסלול הארוך ביותר תחזיר כפרמטר פלט את אורך המסלול הארוך ביותר המתחיל מהשורש int longestSequenceRec(TNode* root, int* longestFromRoot); int longestSequence(Tree tr) { int temp; if (tr.root == NULL) return ERROR; return longestSequenceRec(tr.root, &temp); } 1 3 2 4 9 6 8 7

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים (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 1 2 6 8

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים (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); } 1 3 4 9 7

מציאת אורך המסלול הארוך ביותר שאיבריו עוקבים (3) 1 3 2 4 9 6 8 7 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)); }

יצירת רשימה מעץ ע"י מעבר 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;

יצירת רשימה מעץ ע"י מעבר 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) בכל קריאה רקורסיבית יש פעולות קבועות לכן היעילות הכוללת של הפונקציה היא כמספר הקריאות הרקורסיביות, כלומר כמספר הצמתים בעץ

מילוי עץ מנתוני מערכים בהינתן מערך המייצג נתוני עץ במעבר InOrder ומערך המייצג נתוני אותו עץ במעבר PreOrder יש לבנות את העץ. ידוע כי כל ערך מופיע מקסימום פעם אחת בלבד. למשל, בהינתן המערכים הבאים וגודלם יש לייצר את העץ המתאים: 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

מילוי עץ מנתוני מערכים - הרעיון 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

הקוד InOrder: 4 3 9 7 1 6 2 8 PreOrder: 1 3 4 9 7 2 6 8 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* preArr, int* inArr, int size) TNode* root; int index; if (size == 0) return NULL; root = createNewTNode(preArr[0], NULL, NULL); index = findIndex(inArr, size, preArr[0]); root->left = createTreeFromPreOrderAndInOrder(preArr+1, inArr, index); root->right = createTreeFromPreOrderAndInOrder(preArr+index+1, inArr+index+1, size-index-1); return root; InOrder: 4 3 9 7 1 6 2 8 PreOrder: 1 3 4 9 7 2 6 8 L R

פונקציה המדפיסה את כל הצמתים שלהם בן אחד בלבד 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

פונקציה המחזירה את מספר תתי-העצים מגובה מסויים (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 ERROR; return countSubTreesOfHeightRec(tr.root, h, &treeHeight); } פונקציית העזר תצטרך בכל שלב לדעת מה גובה תת-העץ, על מנת לדעת האם הוא מתאים לתנאי

פונקציה המחזירה את מספר תתי-העצים מגובה מסויים (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

המשך... 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 הבנים, נבקש את הנתונים עבור שניהם נעדכן את גובה העץ ונחזיר את הערך שחישבנו

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

הקוד... 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; ….

המשך... 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);

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

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

תרגיל 1 כתוב פונקציה המקבלת עץ בינארי, ומחזירה את מספר הקודקודים שההפרש בין סכום הצמתים בתת-עץ שמאל שלו לסכום הצמתים בתת-עץ ימין שלו קטן מערך הקודקוד קישור לקובץ הסטרטר: http://www.kerenkalif.com/ProgrammingLectures/Advanced%20C/labs/trees/isBalanced - starter.c

פתרון http://www.kerenkalif.com/ProgrammingLectures/Advanced%20C/labs/trees/isBalanced.c