380 likes | 638 Views
בתרגול הקודם. רשימה מקושרת – Linked List המחלקה LinkedList המחלקה Link באיזו מחלקה ממומשת הפונקציונליות? השוואה Array vs. LinkedList Iterator הממשק Iterable הממשק Iterator Queue isEmpty , dequeue , enqueue FIFO Stack isEmpty , push , pop LIFO. Tirgul 13: Trees. הגדרות.
E N D
בתרגול הקודם • רשימה מקושרת – Linked List • המחלקה LinkedList • המחלקה Link • באיזו מחלקה ממומשת הפונקציונליות? • השוואה Array vs. LinkedList • Iterator • הממשק Iterable • הממשק Iterator • Queue • isEmpty, dequeue, enqueue • FIFO • Stack • isEmpty, push, pop • LIFO
הגדרות • עץ – מודל מופשט של מבנה היררכי. עץ מורכב מאוסף של צמתים (קודקודים) עם יחס אבא-בן. • שורש בעץ – צומת ללא אבא. בכל עץ יש בדיוק שורש אחד. לכל הצמתים פרט לשורש יש בדיוק אב אחד.
הגדרות X • צומת X הינו אב קדמון של צומת Y, ו Y הנו צאצא של X אם המסלול מהשורש אל Y עובר דרך X. • צומת X הנו האבא של W, ו W הנו בן של X אם X הנו אב קדמון של W ויש ביניהם צלע. W Y אב קדמון צאצא אבא בן
הגדרות • עלה – צומת אשר אין לו בנים. • עומקשל צומת בעץ= מרחק הצומת מהשורש.
הגדרות • גובהשל עץ – עומק מקסימאלי של צומת בעץ (וגובה של עץ ריק הוא -1). • עץ בינארי - עץ אשר בומספרהבנים של כל צומתאינועולה על 2.
הגדרות עץ חיפוש בינארי - BST עץ בינארי אשר בו עבור כל צומת, הערכים של כל האיברים בתת העץ השמאלי שלו קטנים (או שווים) ממנו, וכל האיברים בתת העץ הימני שלו גדולים ממנו. 7 3 10 6 1 14 4 7 13
1 6 3 5 8 2 9 שלוש שיטות לסריקת עץ pre-order, in-order, post-order. בביצוע הסריקות בעץ הנתון יתקבל סדר האיברים הבא: • תחילי (pre-order): • תוכי (in-order): • סופי (post-order): מה הייתה התוצאה אם העץ היה binary search tree? 1,6,8,5,2,9,3 8,6,2,5,9,1,3 8,2,9,5,6,3,1
הגדרות: עוקב וקודם העוקב לצומת x: הצומת בעל המפתח הקטן ביותר, הגדול מהערך של x הקודם לצומת x: הצומת בעל המפתח הגדול ביותר, הקטן מהערך שלx דוגמה: הקודם של W הוא העוקב של W הוא הקודם של C הוא העוקב של C הוא ב- BST, לפי סריקת inOrder: R Y B E
BinaryTree public String inOrder() { if (isEmpty()) return""; else returnroot.inOrder(); } // inOrder public String preOrder() { if (isEmpty()) return""; elsereturnroot.preOrder(); } // preOrder public String postOrder() { if (isEmpty()) return""; else returnroot.postOrder(); } // postOrder } publicclassBinaryTree { protectedBinaryNoderoot; publicBinaryTree() { root = null; } // BinaryTree publicbooleanisEmpty() { returnroot == null; } // isEmpty publicvoid insert(Object toAdd) { if (isEmpty()) root = newBinaryNode(toAdd); else root.insert(toAdd); } // insert
BinaryNode publicvoid insert(Object toAdd) { double select = Math.random(); if (select > 0.5) { if (left == null) left = newBinaryNode(toAdd); else left.insert(toAdd); } else { if (right == null) right = newBinaryNode(toAdd); else right.insert(toAdd); } } // insert publicclassBinaryNode { protected Object data; protectedBinaryNodeleft; protectedBinaryNoderight; publicBinaryNode(Object data) { this.data = data; left = null; right = null; } // BinaryNode … }
BinaryNode public String preOrder() { String res = ""; res = res + " " + data + " "; if (left != null) res = res + left.preOrder(); if (right != null) res = res + right.preOrder(); return res; } // preOrder public String inOrder() { String res = ""; if (left != null) res = res + left.inOrder(); res = res + " " + data + " "; if (right != null) res = res + right.inOrder(); return res; } // inOrder
BinaryNode public String postOrder() { String res = ""; if (left != null) res = res + left.postOrder(); if (right != null) res = res + right.postOrder(); res = res + " " + data + " "; return res; } // postOrder
דוגמה לשיטות של עצים: חישוב גובה בעץ בינארי כללי במחלקה BinaryNode: publicint height() { int resLeft = -1; int resRight = -1; if (left != null) { resLeft = left.height(); } if (right != null) { resRight = right.height(); } return Math.max(resLeft, resRight) + 1; } // height במחלקה BinaryTree: publicint height() { if (isEmpty()) return -1; else returnroot.height(); } // height
מימוש:עץחיפוש בינארי -BST BinaryTree BinaryNode הורשה BST BSN
כיצד נשווה בין איברי העץ? על מנת להחזיק את האיברים בעץ באופן ממוין עלינו לדאוג שאיברים יהיו בני השוואה, לכן נשתמש בממשק – Comparable.תזכורת לממשק: public interface Comparable { public intcompareTo(Object other); } איזו בעייה יכולה להיווצר כאשר אנו משווים שני איברים ע"י compareTo?
Comparatorinterface: • לעיתים אנו מעוניינים להשוות בין שני אובייקטים לפי כמה השוואות נפרדות, לדוגמה נרצה להשוות בין סטודנטים על פי: • מספר זהות • שם משפחה מה נעשה? נייצר "שופט חיצוני" שיידע להכריע מי מבין שני עצמים מאותה מחלקהיותר "גדול"
Comparatorinterface: publicinterface Comparator { int compare(Object obj1, Object obj2); } // comparator
IntegerComparator publicclassIntegerComparatorimplements Comparator { publicint compare(Object o1, Object o2) { if (((Integer)o1).intValue() > ((Integer)o2).intValue()) return 1; elseif (((Integer)o1).intValue() == ((Integer)o2).intValue()) return 0; else return -1; } }
CharacterComparator publicclassCharacterComparatorimplements Comparator { publicint compare(Object o1, Object o2) { if (((Character)o1).charValue() > ((Character)o2).charValue()) return 1; elseif (((Character)o1).charValue() == ((Character)o2).charValue()) return 0; else return -1; } }
BST import java.util.Comparator; publicclass BST extends BinaryTree { private Comparator comp; public BST(Comparator comp) { super(); this.comp = comp; } // BST … // (override insert only) } // class BST publicclass BSN extends BinaryNode { private Comparator comp; public BSN(Object data, Comparator comp) { super(data); this.comp = comp; } // BSN … // (override insert, remove, etc.) } // class BSN
Step 1 Step 2 Step 3 Step 4 Step 5 Step 6 Step 7 importjava.util.Comparator; publicclass Main { publicstaticvoid main(String[] args) { Comparator comp = newIntegerComparator(); BST tree1 = new BST(comp); tree1.insert(new Integer(50)); // Step 1 tree1.insert(new Integer(60)); // Step 2 tree1.insert(new Integer(40)); // Step 3 tree1.insert(new Integer(30)); // Step 4 tree1.insert(new Integer(20)); // Step 5 tree1.insert(new Integer(45)); // Step 6 tree1.insert(new Integer(65)); // Step 7 System.out.println("InOrder: " + tree1.inOrder()); System.out.println("PreOrder: " + tree1.preOrder()); System.out.println("PostOrder: " + tree1.postOrder()); System.out.println("Find Minimum: " + tree1.findMin()); System.out.println("Height: " + tree1.height()); } } 50 60 40 30 20 45 65
F B H A D K BST Insert: Example • Example: Insert C C
הכנסה איבר חדש לעץ • במחלקה BST: • publicvoid insert(Object toAdd) • { • if (isEmpty()) { • root = new BSN(toAdd, this.comp); • } • else { • root.insert(toAdd); • } • } // insert במחלקה BSN: publicvoid insert(Object toAdd) { if (comp.compare(toAdd, this.data) < 0) { if (left == null) left = new BSN(toAdd,this.comp); else left.insert(toAdd); } if (comp.compare(toAdd, this.data) > 0) { if (right == null) right = new BSN(toAdd,this.comp); else right.insert(toAdd); } } // insert מה יקרה אם ננסה להכניס לעץ איבר שכבר קיים בתוכו?
מציאת קודקוד בעל מפתח מינימאליבעץ חיפוש בינארי. במחלקה BST: public Object findMin() { if (isEmpty()) { returnnull; // Exceptions are needed... } return ((BSN)root).findMin(); } // findMin במחלקה BSN: public Object findMin() { BinaryNode t=this; while( t.left != null ) t = t.left; returnt.data; } // findMin מה היינו צריכים לעשות אם העץ לא היה BST?
עץ בינארי מלא עץ בינארי מלא ( FULL ) עץ בינארי אשר בו לכל צומת פנימי יש (בדיוק) שני בנים.
עץ בינארי מושלם עץ בינארי מושלם ( PERFECT ) עץ בינארי מלא שבו לכל העלים יש אותו עומק.
לכל הקדקודים שלו עד שכבה h-2 יש בדיוק 2 בנים כל הקדקודים ברמה ה h מרוכזים לשמאל עץ בינארי שגובהו hומתקיים: עץ בינארי שלם עץ בינארי שלם ( COMPLETE )
עץ בינארי מושלם בדיקה האם עץ בינארי הוא עץ בינארי מושלם במחלקה BinaryTree: publicboolean isPerfect() { returnroot.isPerfect(); } במחלקה BinaryNode: publicboolean isPerfect() { int h = height(); //class method if (h==0) returntrue; if (h==1) return ((left != null) && (right != null)); return ((left != null) && (left.height() == h - 1) && left.isPerfect() && (right != null) &&(right.height() == h - 1) && right.isPerfect()); }
ראינו את ההגדרות הבאות: עץ מושלם (perfect)- עץ בינארי מלא שבו לכל העלים אותו עומק עץ בינארי שלם (complete)עץ בינארי שגובהו h ומתקיים לכל הקדקודים שלו עד שכבה h-2 יש בדיוק 2 בנים כל הקדקודים ברמה ה h מרוכזים לשמאל בדיקה האם עץ בינארי הוא "שלם" עץ בינארי שלם
הוא ריק או הבן השמאלי שלו הוא שורש של עץ שלם בגובה h-1 והבן הימני שלו הוא שורש של עץ מושלם בגובה h-2 או הבן השמאלי שלו הוא שורש של עץ מושלם בגובה h-1 והבן הימני שלו הוא שורש של עץ שלם בגובה h-1 עץ בינארי בגובה h הוא שלם אם ורק אם: בהגדרה רקורסיבית
עץ בינארי שלם אנחנו נבדוק כמה מקרי קצה כי אם גובה העץ הוא 0 או 1 נקבל שדרוש לבדוק אם גובה תת העץ הוא 0 או –1 במחלקה BinaryTree : publicboolean isComplete() { return root.isComplete(); } במחלקה BinaryNode : publicboolean isComplete() { int h = height(); //class method if (h==0) returntrue; if (h==1) return ((left != null)); //the height is 2 and up: boolean has2Sons = ((left != null) && (right != null)); boolean case1=false, case2=false; if (has2Sons) { int leftH = left.height(); int rightH = right.height(); case1 = (((leftH == h-1) && left.isComplete()) && (rightH == h-2) && right.isPerfect()); case2 = (((leftH == h-1) && left.isPerfect ()) && (rightH == h-1) && right.isComplete()); } return case1 || case2; }