תרגול 13 עצים

‫תרגול ‪13‬‬
‫עצים‬
‫‪U‬‬
‫‪U‬‬
‫‪U‬‬
‫הגדרות‪:‬‬
‫עץ – מבנה נתונים של קודקודים )צמתים( וקשתות כך שלכל קודקוד יש אב יחיד‪ ,‬פרט לקודקוד השורש )שלו‬
‫אין אבא(‪.‬‬
‫‪U‬‬
‫צומת ‪ X‬הוא אב קדמון של צומת ‪ ,Y‬ו ‪ Y‬הנו צאצא של ‪ X‬אם המסלול מהשורש אל ‪ Y‬עובר דרך ‪.X‬‬
‫צומת ‪ X‬הוא האבא של ‪ ,Y‬ו ‪ Y‬הנו הבן של ‪ X‬אם ‪ X‬הנו אב קדמון של ‪ Y‬ויש ביניהם צלע‪.‬‬
‫עלה – צומת אשר אין לו בנים‪.‬‬
‫צומת פנימי – צומת אשר אינו עלה‪.‬‬
‫עומק – מרחק הצומת מהשורש‪.‬‬
‫גובה – המרחק המקסימאלי של צומת מעלה )בתת העץ שלו(‪.‬‬
‫עץ בינארי‬
‫עץ אשר בו מספר הבנים של כל צומת אינו עולה על ‪.2‬‬
‫עץ חיפוש בינארי‬
‫עץ בינארי אשר בו עבור כל צומת הערכים של כל האיברים‬
‫בתת העץ השמאלי שלו קטנים )או שווים( ממנו‪,‬‬
‫וכל האיברים בתת העץ הימני שלו גדולים ממנו‪.‬‬
‫שלוש שיטות לסריקת עץ )‪.(pre, in & post‬‬
‫עקוב אחר שלוש הסריקות בעץ הנתון ורשום מהו סדר‬
‫האיברים הנסרקים בכל אחת מהן‪.‬‬
‫תשובה‪:‬‬
‫תחילי )‪:(pre-order‬‬
‫תוכי )‪:(in-order‬‬
‫סופי )‪:(post-order‬‬
‫‪U‬‬
‫‪U‬‬
‫‪1,6,8,5,2,9,3‬‬
‫‪8,6,2,5,9,1,3‬‬
‫‪8,2,9,5,6,3,1‬‬
:‫מימוש‬
U
public class BinaryTree {
U
U
protected BinaryNode root;
U
U
public BinaryTree() {
root = null;
} // BinaryTree
U
U
public boolean isEmpty() {
return root == null;
} // isEmpty
U
U
public void insert(Object toAdd) {
if (isEmpty())
root = new BinaryNode(toAdd);
else
root.insert(toAdd);
} // insert
U
U
U
U
U
U
public String inOrder() {
if (isEmpty())
return "";
else
return root.inOrder();
} // inOrder
U
U
public String preOrder() {
if (isEmpty())
return "";
else return root.preOrder();
} // preOrder
U
U
public String postOrder() {
if (isEmpty())
return "";
else
return root.postOrder();
} // postOrder
} // class BinaryTree
U
U
public class BinaryNode {
protected Object data;
protected BinaryNode left;
protected BinaryNode right;
public BinaryNode(Object data)
{
this.data = data;
left = null;
right = null;
} // BinaryNode
public void insert(Object toAdd) {
double select = Math.random();
if (select > 0.5) {
if (left == null)
left = new BinaryNode(toAdd);
else
left.insert(toAdd);
}
else {
if (right == null)
right = new BinaryNode(toAdd);
else
right.insert(toAdd);
}
} // insert
public String inOrder() {
String res = "";
if (left != null)
res = res + left.inOrder();
if (data == null)
res = res + " <null> ";
else
res = res + " " + data.toString() + " ";
if (right != null)
res = res + right.inOrder();
return res;
} // inOrder
public String preOrder() {
String res = "";
if (data == null)
res = res + " <null> ";
else
res = res + " " + data.toString() + " ";
if (left != null)
res = res + left.preOrder();
if (right != null)
res = res + right.preOrder();
return res;
} // preOrder
public String postOrder() {
String res = "";
if (left != null)
res = res + left.postOrder();
if (right != null)
res = res + right.postOrder();
if (data == null)
res = res + " <null> ";
else
res = res + " " + data.toString() + " ";
return res;
} // postOrder
} // class BinaryNode
import java.util.Comparator;
public class BST extends BinaryTree
{
private Comparator comp;
public BST(Comparator comp) {
super();
this.comp = comp;
} // BST
…
// (override insert, remove, etc.)
} // class BST
public class BSN extends BinaryNode
{
private Comparator comp;
public BSN(Object data, Comparator comp)
{
super(data);
this.comp = comp;
} // BSN
…
// (override insert, remove, etc.)
} // class BSN
public class IntegerComparator implements Comparator
{
public int compare(Object o1, Object o2)
{
if (((Integer)o1).intValue() > ((Integer)o2).intValue())
return 1;
else if (((Integer)o1).intValue() == ((Integer)o2).intValue())
return 0;
else
return -1;
}
}
import java.util.Comparator;
public class Main {
public static void main(String[] args) {
Comparator comp = new IntegerComparator();
BST tree1 = new BST(comp);
tree1.insert(new
tree1.insert(new
tree1.insert(new
tree1.insert(new
tree1.insert(new
tree1.insert(new
tree1.insert(new
Integer(50));
Integer(60));
Integer(40));
Integer(30));
Integer(20));
Integer(45));
Integer(65));
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());
System.out.println("Is Perfect?: " + tree1.isPerfect());
System.out.println("Is Complete? " + tree1.isComplete());
}
}
.‫חישוב גובה בעץ חיפוש בינארי‬
:BinaryTree ‫במחלקה‬
public int height() {
if (isEmpty()) {
return -1;
}
else {
return root.height();
}
} // height
:BinaryNode ‫במחלקה‬
public int 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
.‫מציאת קודקוד בעל מפתח מינימאלי בעץ חיפוש בינארי‬
:BST ‫במחלקה‬
public Object findMin() {
if (isEmpty()) {
return null; // Exceptions are needed...
}
return ((BSN)root).findMin();
} // findMin
:BSN ‫במחלקה‬
public Object findMin() {
BinaryNode t=this;
while( t.left != null )
t = t.left;
return t.data;
} // findMin
:‫הכנסת איבר חדש לעץ‬
:BST ‫במחלקה‬
public void insert(Object toAdd)
{
if (isEmpty()) {
root = new BSN(toAdd, this.comp);
}
else {
root.insert(toAdd);
}
} // insert
:BSN ‫במחלקה‬
public void 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
‫עוקב וקודם‬
‫העוקב לצומת ‪ X‬הוא הצומת בעל מפתח הקטן ביותר הגדול מהערך של ‪X‬‬
‫הקודם לצומת הוא הצומת בעל מפתח הגדול ביותר הקטן מערך של ‪X‬‬
‫הקודם של ‪ ,R – W‬העוקב של ‪.Y – W‬‬
‫הקודם של ‪ ,B – C‬העוקב של ‪.E – C‬‬
‫עץ בינארי מלא )‪(FULL‬‬
‫עץ בינארי אשר בו לכל צומת פנימי יש )בדיוק( שני בנים‪.‬‬
‫דוגמא‬
(COMPLETE) ‫עץ בינארי שלם‬
:‫ ומתקיים‬h ‫עץ בינארי שגובהו‬
.‫ בנים‬2 ‫ יש בדיוק‬h-2 ‫• לכל הקודקודים שלו עד שכבה‬
.‫ מרוכזים לשמאל‬h-‫• כל הקודקודים ברמה ה‬
(PERFECT) ‫עץ בינארי מושלם‬
.‫עץ בינארי מלא שבו לכל העלים יש אותו עומק‬
‫ בדיקה האם עץ בינארי הוא עץ בינארי מושלם‬:‫דוגמא‬
:BST :‫במחלקה‬
public boolean isPerfect(){
return ((BSN)root).isPerfect();
}
:BSN ‫במחלקה‬
public boolean isPerfect(){
int h = height();
//class method
if (h==0) return true;
if (h==1) return (!(left==null) && !(right==null));
return
(!(left==null) && (left.height() == h - 1) &&
((BSN)left).isPerfect() &&
!(right==null) &&(right.height() == h - 1) &&
((BSN)right).isPerfect());
}
U
‫‪U‬‬
‫בדיקה האם עץ בינארי הוא עץ בינארי שלם‬
‫ראינו את ההגדרות הבאות‪:‬‬
‫עץ מושלם )‪ :(perfect‬עץ בינארי מלא שבו לכל העלים אותו עומק‬
‫עץ בינארי שלם )‪ :(complete‬עץ בינארי שגובהו ‪ h‬ומתקיים‬
‫• כל הקדקודים שלו עד שכבה ‪ h-2‬יש בדיוק ‪ 2‬בנים‪.‬‬
‫• כל הקודקודים ברמה ה‪ h-‬מרוכזים לשמאל‪.‬‬
‫בהגדרה רקורסיבית‪:‬‬
‫עץ בינארי הוא שלם אם ורק אם )‪ h‬הוא גובה העץ(‬
‫‪ .1‬הוא ריק‬
‫או‬
‫‪ .2‬הבן השמאלי שלו הוא שורש של עץ שלם בגובה ‪ h-1‬והבן הימני שלו הוא שורש של עץ מושלם בגובה‬
‫‪h-2‬‬
‫או‬
‫‪ .3‬הבן השמאלי שלו הוא שורש של עץ מושלם בגובה ‪ h-1‬והבן הימני שלו הוא שורש של עץ שלם‬
‫בגובה ‪h-1‬‬
‫אנחנו נבדוק כמה מקרי קצה כי אם גובה העץ הוא ‪ 0‬או ‪ 1‬נקבל שדרוש לבדוק אם גובה תת העץ הוא ‪ 0‬או ‪:1‬‬
‫במחלקה ‪:BST‬‬
‫)(‪public boolean isComplete‬‬
‫{‬
‫;)(‪return ((BSN)root).isComplete‬‬
‫}‬
‫במחלקה ‪:BSN‬‬
‫)(‪public boolean isComplete‬‬
‫{‬
‫;)(‪int h = height‬‬
‫‪//class method‬‬
‫;‪if (h==0) return true‬‬
‫;))‪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) && ((BSN)left).isComplete‬‬
‫&& )‪(rightH == h-2‬‬
‫;))(‪((BSN)right).isPerfect‬‬
‫&& )‪case2 = (((leftH == h-1‬‬
‫&& ))( ‪((BSN)left).isPerfect‬‬
‫&& )‪(rightH == h-1‬‬
‫;))(‪((BSN)right).isComplete‬‬
‫}‬
‫;‪return case1 || case2‬‬
‫}‬