Transcript 006.class8

‫מבני נתונים‬
‫שיעור ‪ – 8‬חזרה ותרגול‪.‬‬
‫מערך‪ ,‬תור‪ ,‬מחסנית‪ ,‬רשימה מקושרת‪,‬‬
‫עצים בינאריים‪.‬‬
Arrays
‫מערכים‬
‫הצהרה על מערך‬
int[] anArray; // declares an array of integers
byte[] anArrayOfBytes;
short[] anArrayOfShorts;
long[] anArrayOfLongs;
float[] anArrayOfFloats;
double[] anArrayOfDoubles;
boolean[] anArrayOfBooleans;
char[] anArrayOfChars;
String[] anArrayOfStrings;
‫ לשם כך יש לאתחל את‬,‫ההצהרה על מערך אינה יצירה של אובייקט מערך‬
:‫המערך‬
anArray = new int[10]; // create an array of integers using “new”
integer ‫ מספרים מסוג‬10 ‫בשלב זה נוצר אובייקט מערך ומוקצה מקום ל‬
•
•
•
Arrays
‫מערכים‬
‫אתחול ערכי האלמנטים במערך‬
anArray[0] = 100; // initialize first element
anArray[1] = 200; // initialize second element
anArray[2] = 300; // etc.
•
:‫גישה אל האלמנטים של המערך ע"י האינדקס‬
System.out.println("Element 1 at index 0: " + anArray[0]);
System.out.println("Element 2 at index 1: " + anArray[1]);
System.out.println("Element 3 at index 2: " + anAray[2]);
:‫דרך נוספת ליצירה ואתחול מערך‬
int[] anArray = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000};
.‫בדרך זו אורך המערך נקבע באופן אוטומטי ע"פ מספר האלמנטים בסוגריים‬
:‫ למשל מערך דו מימדי יוגדר כך‬,‫ניתן להגדיר מערכים מרובי מימדים‬
int [][] 2dArray=new int[5][10];
...‫ דוגמא‬...‫למעשה נוצר מערך של מערכים‬
•
•
•
•
•
‫מערכים‬
Arrays
‫מערך עצמים‬
•
‫כאשר אברי המערך הינם עצמים ולא טיפוסים פרימיטיביים יש צורך להקצות כל‬
! ‫איבר במערך במפורש‬
•
Line line_arr[];
line_arr = new Line[3];
line_arr[0].draw(); // BUG!
line_arr[0] = new Line();
line_arr
line_arr
line_arr
Array Object
Line Object
Array Object
Line Object
Line Object
‫תרגיל ‪3‬‬
‫• יש ליצור מחלקה ‪ SortedArray‬אשר מחזיקה‬
‫מערך של מספרים שלמים ‪ int‬ממויין‪.‬‬
‫• המחלקה תכיל מערך‪ ,‬שיטת הכנסת איברים‬
‫תוך שמירה על סדר המערך ושיטה המחזירה‬
‫איבר עם אינדקס מסוים ‪.i‬‬
‫• צור מחלקה ‪ Class7‬עם שיטת ‪ main‬והכנס ‪10‬‬
‫ערכים מהמשתמש‪ ,‬ולאחר מכן הכנס עוד ‪5‬‬
‫ערכים אקראיים בתחום בין הערך הקטן ביותר‬
‫והגדול ביותר שבמערך‪.‬‬
‫‪5‬‬
‫ תזכורת‬- ‫מספר אקראי‬
Random rnd = new Random();
int from= 10;
int to = 100;
int num= from+rnd.nextInt(to-from+1);
6
‫מימוש מחסנית ע"י מערך‬
:)‫ (נניח שמחזיקה ערכים שלמים‬Stack ‫נגדיר את המחלקה‬
class public Stack{
private int S[]; //‫משתנה מחלקה מערך של שלמים‬
private int num, t;
public Stack(int n){S=new int[n]; num=n; t=-1}// ‫בנאי מאתחל את המערך‬
public int size(){return t+1;}
public boolean isEmpty(){return t==-1;}
public int top(){
if isEmpty() then throw emptyStackException;//‫שגיאת מחסנית ריקה‬
else return S[t];}
public int pop(){
if isEmpty() then throw emptyStackException;//‫שגיאת מחסנית ריקה‬
else {int e = S[t]; t = t – 1; return e;}}
public void push(int new){
if size()==num then throw fullStackException;//‫שגיאת מחסנית מלאה‬
else {t = t + 1; S[t]=new;}}
•
java - ‫מימוש תור ע"י מערך‬
:)‫ (נניח שמחזיקה ערכים שלמים‬Queue ‫נגדיר את המחלקה‬
class public Queue{
private int Q[]; //‫משתנה מחלקה מערך של שלמים‬
private int N, f, r; //‫משתנים המצביעים על תחילת וסוף התור‬
public Stack(int n){Q=new int[n];N=n; f=0; r=0}// ‫בנאי מאתחל את המערך‬
public int size(){return (N-f+r) mod N;}
public boolean isEmpty(){return f==r;}
public int front(){
if isEmpty() then throw emptyQueueException;//‫שגיאת תור ריק‬
else return Q[f];}
public int dequeue(){
if isEmpty() then throw emptyQueueException;//‫שגיאת תור ריק‬
else {int e = Q[f]; f = (f+1) mod N; return e;}}
public void enqueue(int new){
if size()==N-1 then throw fullQueueException;//‫שגיאת תור מלא‬
else {Q[r]=new; r = (r+1) mod N}}
•
‫מימוש רשימה מקושרת חד כיוונית‬
class Node{
public Node next;
public int data;//)‫ניתן להגדיר כל סוג של נתונים (אובייקט‬
public Node (int d){
data = d;
next = null;
}
public void displayNode(){
System.out.println(“the data is:” + d);
}
}//end of class Node
class LinkedList
class LinkedList{
private Node first;//‫מצביע לאיבר הראשון‬
public LinkedList(){first = null;}
public boolean isEmpty(){return (first==null);}
public void insertFirst(int new){
Node newNode = new Node(new);//‫יצירת אוביקט‬
newNode.next = first;//‫עדכון האיבר הבא‬
first = newNode;//‫} עדכון ראש הרשימה‬
public Node deleteFirst(){
Node temp = first;//‫שמירת מצביע על האיבר הנמחק‬
first = first.next;//)‫עדכון ראש הרשימה (מחיקת הקודם‬
return temp;//‫} החזרת האיבר המחוק‬
public void displayList(){
System.out.println(“The List is: “);
Node current = first;
//‫מתחיל מהראשון‬
while(current != null){
//‫עד סוף הרשימה‬
current.displayNode();
//‫מדפיס את הנתון‬
current = current.next;}} //‫איבר הבא‬
}
‫מימוש עץ בינארי בג'אווה‬
Node ‫מחלקה‬
public class Node
{
public int data;
private Node leftChild;
private Node rightChild;
}
‫מימוש עץ בינארי בג'אווה‬
Tree ‫מחלקת‬
public class Tree
{
private Node root;
//Methods
public Node find(int key)
public void insert(int key)
public void delete(int key)
//and more methods…
}
find ‫מימוש רקורסיבי שיטת‬
public Node findR (int key, Node current){
if(current == null);
return null //‫לא נמצא‬
if(key < current.data)
return findR(key, current.leftChild); //‫בן שמאלי‬
if(key == current.data)
return current;//‫איבר מוחזר‬
if(key > current.data)
return findR(key, current.rightChild); //‫בן ימני‬
}
‫שיטת ‪insert‬‬
‫• פעולת הכנסת איבר היא למעשה זהה לפעולת‬
‫חיפוש איבר שאינו קיים‪.‬‬
‫• בדומה לחיפוש איבר‪ ,‬בהכנסת איבר חדש‬
‫"מטיילים" על העץ עד שמגיעים לעלה‪ ,‬אשר‬
‫הופך להורה של האיבר החדש המוכנס‪.‬‬
‫• האיבר החדש יהיה בן שמאלי של העלה אם‬
‫הוא קטן ממנו‪ ,‬או בן ימני אם הוא גדול ממנו‬
‫(בהתאם לחוקיות הסדר)‬
‫סריקת איברי העץ ‪Traversing -‬‬
‫• פעולה זו עוברת על כל איברי העץ ע"פ סדר‬
‫מסוים‬
‫• פעולת הסריקה פחות שימושית מחיפוש איבר‬
‫מסוים‬
‫• קיימות ‪ 3‬דרכים פשוטות לסריקת עץ בינרי‬
‫– ‪ :Inorder‬סריקה על כל איברי העץ בסדר עולה‬
‫– ‪ :Preorder‬כל איבר נסרק לפני הילדים שלו‬
‫– ‪ :Postorder‬כל איבר נסרק אחרי הילדים שלו‬
‫סריקת ‪Inorder‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫צורת הסריקה השכיחה והשימושית ביותר‪.‬‬
‫מאפשר ליצור רשימה ממוינת של איברי העץ‬
‫מימוש רקורסיבי יעיל לסריקת ‪Inorder‬‬
‫השיטה נקראת עם איבר נוכחי‪ ,‬כאשר מתחילים‬
‫מהשורש‪ ,‬ומבצעת שלושה פעולות‪:‬‬
‫‪ .1‬השיטה קוראת לעצמה (רקורסיה) עם הבן השמאלי‬
‫‪ .2‬מבצעת פעולה על האיבר הנוכחי (פעולת הביקור)‬
‫‪ .3‬השיטה קוראת לעצמה (רקורסיה) עם הבן הימני‬
‫סריקת ‪Preorder‬‬
‫• שיטה רקורסיבית לסריקת ‪ Preorder‬נקראת עם‬
‫איבר נוכחי החל מהשורש‪:‬‬
‫‪ .1‬מבצעת פעולה על האיבר הנוכחי (פעולת הביקור)‬
‫‪ .2‬השיטה קוראת לעצמה (רקורסיה) עם הבן השמאלי‬
‫‪ .3‬השיטה קוראת לעצמה (רקורסיה) עם הבן הימני‬
‫• שיטת סריקה זו שימושית כאשר יש להדפיס‬
‫מסמך עם פרקים ותתי פרקים ע"פ הסדר‬
‫סריקת ‪Postorder‬‬
‫• שיטה רקורסיבית לסריקת ‪ Postorder‬נקראת עם‬
‫איבר נוכחי החל מהשורש‪:‬‬
‫‪ .1‬השיטה קוראת לעצמה (רקורסיה) עם הבן השמאלי‬
‫‪ .2‬השיטה קוראת לעצמה (רקורסיה) עם הבן הימני‬
‫‪ .3‬מבצעת פעולה על האיבר הנוכחי (פעולת הביקור)‬
‫• שיטת סריקה זו שימושית כאשר יש לחשב נפח‬
‫קבצים של תיקיות ותתי תיקיות‪.‬‬
‫תרגיל ‪2‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫יש לבנות את מחלקות תור‪ ,‬מחסנית‪ ,‬רשימה מקושרת חד‬
‫כיוונית ועץ בינארי‪.‬‬
‫בהמשך לשיטת ‪ main‬במחלקה ‪ Class7‬צור מחסנית‪ ,‬תור‪,‬‬
‫רשימה מקושרת ועץ בינארי והכנס לתוכם את האיברים של‬
‫המערך הממויין ע"פ הסדר‪.‬‬
‫הדפס את איברי הרשימה המקושרת‪.‬‬
‫העבר ‪ 5‬איברים מהמחסנית לתור‪ ,‬ואח"כ ‪ 6‬איברים מהתור‬
‫למחסנית‪.‬‬
‫מחק את כל איברי המבנה המכיל מספר רב יותר של איברים‬
‫(התור או המחסנית) תוך הדפסתם‪.‬‬
‫הצג את איברי העץ ע"פ שלושת דרכי הסריקה (יש לממש‬
‫סריקה עם הדפסת האיברים)‬
‫‪19‬‬
‫תרגיל ‪3‬‬
‫נתון עץ בינארי כלשהו בעל ‪ n‬צמתים‪ .‬בכל צומת יש‪:‬‬
‫•‬
‫•‬
‫•‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬
‫מפתח – מספר טבעי כלשהו‬
‫שני מצביעים לבנים‬
‫שדה נוסף המכיל מספר טבעי (מותר להשתמש בו לביצוע המשימה‬
‫הנדרשת)‬
‫הצע אלג' לחישוב ערכו של המסלול הכבד ביותר בעץ מהשורש‬
‫לעלה‪ .‬המסלול הכבד הינו המסלול שסכום המפתחות בצמתים שלו‬
‫הוא מקסימלי‪.‬‬
‫יש להדפיס את הערכים לאורך מסלול זה‪.‬‬
‫סיבוכיות זמן נדרשת – )‪O(n‬‬
‫דוגמא‪:‬‬
‫‪100+20‬‬
‫‪20‬‬
‫‪50‬‬
‫‪0‬‬
‫‪100‬‬
‫פתרון‬
‫חישוב הערך‪:‬‬
‫•‬
‫•‬
‫מחשבים באופן רקורסיבי עבור שני תת‪-‬העצים ומוסיפים את ערך השורש‬
‫למקסימום מבינהם‪.‬‬
‫הדפסת המסלול‪:‬‬
‫•‬
‫•‬
‫•‬
‫בשדה הנוסף בכל צומת נרשום ‪ 0‬אם המקסימום התקבל מתת‪-‬העץ‬
‫השמאלי‪ ,‬ו‪ 1 -‬אם מהימני‪.‬‬
‫לאחר חישוב הערך נדפיס לאורך המסלול המסומן את ערכיו‪.‬‬