230 likes | 452 Vues
מבני נתונים. שיעור 8 – חזרה ותרגול. מערך, תור, מחסנית, רשימה מקושרת, עצים בינאריים. Arrays מערכים. הצהרה על מערך int [] anArray ; // declares an array of integers byte[] anArrayOfBytes ; short[] anArrayOfShorts ; long[] anArrayOfLongs ; float[] anArrayOfFloats ;
E N D
מבני נתונים שיעור 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” • בשלב זה נוצר אובייקט מערך ומוקצה מקום ל 10 מספרים מסוג integer
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 Array Object Line Object Line Object Line Object
תרגיל 3 • יש ליצור מחלקה SortedArray אשר מחזיקה מערך של מספרים שלמים int ממויין. • המחלקה תכיל מערך, שיטת הכנסת איברים תוך שמירה על סדר המערך ושיטה המחזירה איבר עם אינדקס מסוים i. • צור מחלקה Class7 עם שיטת main והכנס 10 ערכים מהמשתמש, ולאחר מכן הכנס עוד 5 ערכים אקראיים בתחום בין הערך הקטן ביותר והגדול ביותר שבמערך.
מספר אקראי - תזכורת Random rnd = new Random(); int from= 10; int to = 100; int num= from+rnd.nextInt(to-from+1);
מימוש מחסנית ע"י מערך • נגדיר את המחלקה 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 booleanisEmpty(){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 booleanisEmpty(){return f==r;} public int front(){ if isEmpty() then throw emptyQueueException;//שגיאת תור ריק else return Q[f];} public intdequeue(){ 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 booleanisEmpty(){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 • השיטה נקראת עם איבר נוכחי, כאשר מתחילים מהשורש, ומבצעת שלושה פעולות: • השיטה קוראת לעצמה (רקורסיה) עם הבן השמאלי • מבצעת פעולה על האיבר הנוכחי (פעולת הביקור) • השיטה קוראת לעצמה (רקורסיה) עם הבן הימני
סריקת Preorder • שיטה רקורסיבית לסריקת Preorder נקראת עם איבר נוכחי החל מהשורש: • מבצעת פעולה על האיבר הנוכחי (פעולת הביקור) • השיטה קוראת לעצמה (רקורסיה) עם הבן השמאלי • השיטה קוראת לעצמה (רקורסיה) עם הבן הימני • שיטת סריקה זו שימושית כאשר יש להדפיס מסמך עם פרקים ותתי פרקים ע"פ הסדר
סריקת Postorder • שיטה רקורסיבית לסריקת Postorder נקראת עם איבר נוכחי החל מהשורש: • השיטה קוראת לעצמה (רקורסיה) עם הבן השמאלי • השיטה קוראת לעצמה (רקורסיה) עם הבן הימני • מבצעת פעולה על האיבר הנוכחי (פעולת הביקור) • שיטת סריקה זו שימושית כאשר יש לחשב נפח קבצים של תיקיות ותתי תיקיות.
תרגיל 2 • יש לבנות את מחלקות תור, מחסנית, רשימה מקושרת חד כיוונית ועץ בינארי. • בהמשך לשיטת main במחלקה Class7 צור מחסנית, תור, רשימה מקושרת ועץ בינארי והכנס לתוכם את האיברים של המערך הממויין ע"פ הסדר. • הדפס את איברי הרשימה המקושרת. • העבר 5 איברים מהמחסנית לתור, ואח"כ 6 איברים מהתור למחסנית. • מחק את כל איברי המבנה המכיל מספר רב יותר של איברים (התור או המחסנית) תוך הדפסתם. • הצג את איברי העץ ע"פ שלושת דרכי הסריקה (יש לממש סריקה עם הדפסת האיברים)
נתון עץ בינארי כלשהו בעל n צמתים. בכל צומת יש: מפתח – מספר טבעי כלשהו שני מצביעים לבנים שדה נוסף המכיל מספר טבעי (מותר להשתמש בו לביצוע המשימה הנדרשת) הצע אלג' לחישוב ערכו של המסלול הכבד ביותר בעץ מהשורש לעלה. המסלול הכבד הינו המסלול שסכום המפתחות בצמתים שלו הוא מקסימלי. יש להדפיס את הערכים לאורך מסלול זה. סיבוכיות זמן נדרשת – O(n) תרגיל 3
דוגמא: 100+20 20 0 100 50
חישוב הערך: מחשבים באופן רקורסיבי עבור שני תת-העצים ומוסיפים את ערך השורש למקסימום מבינהם. הדפסת המסלול: בשדה הנוסף בכל צומת נרשום 0 אם המקסימום התקבל מתת-העץ השמאלי, ו- 1 אם מהימני. לאחר חישוב הערך נדפיס לאורך המסלול המסומן את ערכיו. פתרון