1 / 56

תרגול 12

תרגול 12. מבני נתונים. היום בתרגול. רשימה מקושרת תור Iterator מחסנית. רשימה מקושרת ( Linked List ). רשימה מקושרת הינה קבוצה סדורה של אובייקטים, כאשר כל אובייקט ברשימה מכיל הצבעה לאובייקט הבא. כל אובייקט מהווה חוליה בשרשרת: - קודקוד ברשימה הינו מסוג Link - הרשימה כולה נקראת LinkedList.

Download Presentation

תרגול 12

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. תרגול 12 מבני נתונים

  2. היום בתרגול • רשימה מקושרת • תור • Iterator • מחסנית

  3. רשימה מקושרת (Linked List) רשימה מקושרת הינה קבוצה סדורה של אובייקטים, כאשר כל אובייקט ברשימה מכיל הצבעה לאובייקט הבא. כל אובייקט מהווה חוליה בשרשרת: - קודקוד ברשימה הינו מסוג Link - הרשימה כולה נקראת LinkedList null Link Data Next

  4. publicclass Link { private Object data; private Link next; public Link(Object data, Link next) { this.data = data; this.next = next; } public Link(Object data) { this(data, null); } public Object getData() { returndata; } publicvoid setData(Object data) { this.data = data; } public Link getNext() { returnnext; } publicvoid setNext(Link next) { this.next = next; } } המחלקה Link Link Data Next

  5. המחלקה LinkedList • publicclassLinkedList { • privateLink first; • publicLinkedList (){ • first = null; • } • publicLinkedList (Object data){ • first = newLink(data,null); • } • ... • }

  6. LinkedList first data next null המחלקה LinkedList data data next next

  7. נוסיף למחלקה את השיטהisEmpty() נרצה לדעת האם הרשימה שלנו מכילה איברים או לא. נוסיף את השיטה הבוליאניתisEmpty() אשר תחזיר true אם הרשימה ריקה, ו-false אחרת. publicbooleanisEmpty() { return(first == null); }

  8. נוסיף למחלקה את השיטה addLast • publicvoid addLast(Object data) { • Link newLink = new Link(data, null); • if (isEmpty()) { • first = newLink; • } • else { • Link linkPointer = first; • while (linkPointer.getNext() != null) { • linkPointer = linkPointer.getNext(); • } • linkPointer.setNext(newLink); • } • }

  9. דוגמת שימוש LinkedList lst = new LinkedList(); • lst.addLast("World!"); lst.addLast("Hello"); lst.addLast("Beautiful"); next data data data next next LinkedList first null null

  10. נוסיף למחלקה גם את השיטה removeFirst • השיטה מסירה את החוליה הראשונה ברשימה ומחזירה את האובייקט המוצבע על ידה. • public Object removeFirst(){ • Object ans; • if (isEmpty()) { • ans = null; • } • else { • ans = first.getData(); • first = first.getNext(); • } • return ans; • }

  11. המשך דוגמת שימוש lst.removeFirst(); lst.removeFirst(); lst.removeFirst(); next data data data next next LinkedList null first "Beautiful" "Hello" "World!"

  12. המשך דוגמת שימוש lst.removeFirst(); lst.removeFirst(); lst.removeFirst(); next data data next LinkedList null first "World!" “Beautiful"

  13. המשך דוגמת שימוש lst.removeFirst(); lst.removeFirst(); lst.removeFirst(); next data LinkedList null first "World!"

  14. המשך דוגמת שימוש lst.removeFirst(); lst.removeFirst(); lst.removeFirst(); LinkedList null first

  15. נוסיף למחלקה את השיטה getMiddle השיטה getMiddleמחזירה את האיבר האמצעי ברישמה. - רעיונות לפתרון?

  16. public Object getMiddle(){ Object ans; if(isEmpty()) { ans = null; } else { Link current = first; Link jumper = first; while( (jumper != null) && (jumper.getNext() != null) ){ current = current.getNext(); jumper = jumper.getNext().getNext(); } ans = current.getData(); } return ans; } &&

  17. while(jumper != null && jumper.getNext() != null) { current = current.getNext(); jumper = jumper.getNext().getNext(); } ans = current.getData(); …

  18. נוסיף את השיטה containsCycle השיטה containsCycle בודקת האם הרשימה מכילה מעגל. • האם בכלל עלולים להיווצר מעגלים שכאלו? • חידה: כמה מעגלים לכל היותר יכולים להיות ברשימה מקושרת?

  19. publicboolean containsCycle(){ boolean ans; if(isEmpty()) { ans = false; } else { Link current = first; Link jumper = first; boolean isStart = true; while(jumper != null && (current != jumper || isStart)){ isStart = false; current = current.getNext(); jumper = jumper.getNext(); if (jumper != null) jumper = jumper.getNext(); } ans = (jumper != null); } return ans; }

  20. while(jumper != null && (current != jumper || start)) { start = false; current = current.getNext(); jumper = jumper.getNext(); if (jumper != null) jumper = jumper.getNext(); }

  21. while(jumper != null && (current != jumper || start)) { start = false; current = current.getNext(); jumper = jumper.getNext(); if (jumper != null) jumper = jumper.getNext(); }

  22. while(jumper != null && (current != jumper || start)) { start = false; current = current.getNext(); jumper = jumper.getNext(); if (jumper != null) jumper = jumper.getNext(); }

  23. while(jumper != null && (current != jumper || start)) { start = false; current = current.getNext(); jumper = jumper.getNext(); if (jumper != null) jumper = jumper.getNext(); }

  24. while(jumper != null && (current != jumper || start)) { start = false; current = current.getNext(); jumper = jumper.getNext(); if (jumper != null) jumper = jumper.getNext(); }

  25. while(jumper != null && (current != jumper || start)) { start = false; current = current.getNext(); jumper = jumper.getNext(); if (jumper != null) jumper = jumper.getNext(); }

  26. Iterator

  27. Iterator מידע ונתונים (data) הדרושים לתכנית מחשב נשמרים בתוך מבנה נתונים (data structure). על מבנה נתונים יש צורך לבצע מספר פעולות, כמו הכנסת נתונים והוצאת נתונים. אחת הדרכים להוציא נתונים היא לעבור על אוסף הנתונים פריט-מידע אחר פריט-מידע.

  28. Iterator נרצה שתכונה זו תהיה משותפת למבני נתונים רבים, למשל לרשימה, שראינו זה עתה. לכן נגדיר ממשק, שאותו כל מבנה נתונים יממש. נרצה להגיד שמבנה נתונים הוא ניתן למעבר פריט-אחר-פריט, ובאנגלית: Iterable. ב-JAVA קיים הממשק: publicinterfaceIterable { /** *Returnsaniteratoroverasetofelements. * *@returnanIterator. */ Iterator iterator(); }

  29. Iterator יהיה לנו אובייקט שיעזור בתהליך. אובייקט זה יעבור על אוסף הנתונים פריט אחר פריט, לפי סדר מסוים, ובאנגלית:Iterator . נרצה להפריד בין אופן המעבר על הפריטים,למחלקה עליה הוא פועל. ב-JAVA מוגדר ממשק לעבודה עם אובייקט כזה:

  30. publicinterface Iterator { /** *Returnstrueiftheiterationhasmoreelements. *@returntrueiftheiteratorhasmoreelements. */ boolean hasNext(); /** *Returnsthenextelementintheiteration. *@returnthenextelementintheiteration. * @exception NoSuchElementException iteration has no more elements. */ Object next(); /** *Removesfromtheunderlyingcollectionthelastelementreturnedbythe *iterator(optionaloperation) *@exceptionUnsupportedOperationExceptionifthe"remove" *operationisnotsupportedbythisIterator. * *@exceptionIllegalStateExceptionifthe"next"methodhasnot *yetbeencalled,orthe"remove"methodhasalready *beencalledafterthelastcalltothe"next" *method. */ void remove(); }

  31. שימוש ב-Iterator • בהמשך נראה כיצד לשנות את המחלקה LinkedList כך שתתמוך ב-Iterator. • כרגע נניח שהמחלקה כבר תומכת בו, ועל סמך זאת נעשה שימוש ב-Iterator שמתקבל מהשיטה iterator(), שמובטחת לנו מכיוון ש-LinkedList מממשת את Iterable. • publicstaticvoid main(String[] args) { • LinkedList lst = new LinkedList(); • lst.addLast("Shnitsels");lst.addLast("Are");lst.addLast("Tasty"); • Iterator it = lst.iterator(); • while (it.hasNext()) { • Object currentData = it.next(); • System.out.print(currentData); • if (it.hasNext())System.out.print(", "); • } • System.out.println(); • }

  32. דוגמת שימוש • while (it.hasNext()) { • Object currentData = it.next(); • System.out.print(currentData); • if (it.hasNext()) • System.out.print(", "); • } • System.out.println(); data data next next LinkedList ListIterator Shnitsels, Are, Tasty first currentLink data next null

  33. מימוש Iterator עבור LinkedList publicclassListIterator implements Iterator { private Link currentLink; public ListIterator(Link first) { currentLink = first; } publicboolean hasNext() { return currentLink != null; } public Object next() { if (!hasNext()) { thrownewNoSuchElementException(); } Object data = currentLink.getData(); currentLink = currentLink.getNext(); return data; } publicvoidremove() { thrownewUnsupportedOperationException(); } }

  34. מימוש Iterable במחלקה LinkedList • יש לממש את השיטה iterator() של הממשק Iterable ב LinkedList • publicclassLinkedListimplementsIterable{ • … // All methods and fields unchanged • publicIterator iterator(){ • returnnewListIterator(first); • } • … • }

  35. Iterator - הערות • Iteratorמניח שלא נעשה שינוי באוסף עליו הוא עובר במהלך המעבר. אם נעשה שינוי – האיטרטוראינו במצב חוקי ואין הבטחה לפעולה תקינה שלו. • השיטה ()nextמחויבת לזרוק את החריגה NoSuchElementExceptionבמידה ואין יותר אלמנטים באוסף. (אם לפני כל קריאה ל-next()נוודא ש hasNext() החזירה true אזי לא נתקל בחריגה זו). • החריגה UnsupportedOperationExceptionמשמשת כאשר אנו מחויבים לספק מימוש של שיטה מסוימת (למשל כי היא מוגדרת בממשק) במחלקה שלנו, אך אין ברצוננו/יכולתנו לתמוך בה. במקרה כזה בגוף השיטה נזרוק את החריגה.

  36. תור - Queue  תור (Queue) הוא מבנה נתונים המזכיר תור של אנשים: האיבר שנכנס ראשון לתור- יוצא ראשון. ניתן להסתכל כעל כקופסה סגורה בעלת 2 פתחים- פתח הכנסה ופתח הוצאה. איבר שנכנס ראשון יוצא ראשון - FIFO(FIFO - First In First Out). שימושים: ניהל תהליכים ע"י מערכת ההפעלה, ניהול גישות למשאב משותף, ...

  37. public interface Queue{ /** *isEmpty-checksifthequeueisemptyornot. *@returntrueifthequeueisempty */ publicboolean isEmpty(); /** *dequeue-removesanobjectfromtheheadofthequeue. * (FIFOorder) *@returnthenextobjectinthequeue. */ public Object dequeue(); /** *enqueue-insertsanobjectintothequeue. *@paramotheobjecttobeenqueued. */ publicvoid enqueue(Object o); }

  38. מימוש תור ע"י רשימה מקושרת • מימוש כזה יהיה פשוט מאוד באמצעות הרשימה המקושרת שהגדרנו בתחילת התרגול. • publicclassQueueAsList implements Queue { • private LinkedList lst; • public QueueAsList() { lst = new LinkedList(); } • publicboolean isEmpty() {return lst.isEmpty(); } • public Object dequeue() {return lst.removeFirst();} • publicvoidenqueue(Object o) {lst.addLast(o);} • }

  39. דוגמה • נרצה לקלוט מהמשתמש מספר מחרוזות, ורק • כאשר הוא יסיים להקליד (למשל ע"י זיהוי שורה • ריקה) נדפיס בחזרה את כל המחרוזות בדיוק לפי • סדר ההכנסה.

  40. import java.util.Scanner; … publicstaticvoidmain(String args[]) { Scanner sc = new Scanner(System.in); Queue q = new QueueAsList(); System.out.println("Insert few lines … "); while (sc.hasNextLine()) { String line = sc.nextLine(); q.enqueue( line ); } System.out.println("Printing all the lines back!"); while (!q.isEmpty()) { System.out.println(q.dequeue()); } }

  41. דוגמה נוספת- Wimbeldon • נרצה לסמלץ (לדמות) מהלך של טורניר טניס בשיטת פלייאוף.

  42. המשך נרצה לממש את השיטה: publicstaticPlayer simulateTournament( LinkedListplayersList) אשר מקבלת רשימה של שחקנים ומבצעת סימולציה של טורניר טניס באופן הבא: • בשלב הראשון השחקנים מתחלקים לזוגות. • מכל זוג המנצח עולה לשלב הבא, ושוב השחקנים מתחלקים לזוגות עד שנותר שחקן בודד שהוא המנצח (טורניר נוק-אאוט).

  43. הרעיון נממש את השיטה ע"י שימוש בתור: • נאתחל את התור באיברי הרשימה. • כל עוד התור מכיל יותר מאיבר אחד נשלוף שני שחקנים מהתור. • "ניתן" להם לשחק ביניהם, ואת המנצח נכניס לסוף התור (עבר לסיבוב הבא).

  44. הרעיון שחקן 4 שחקן 4 שחקן 3 שחקן 2 שחקן 1 שלב 1: שחקן 1 שחקן 3 שחקן 4 שחקן 2

  45. הרעיון שלב 2: שחקן 2 שחקן 4 שחקן 4 שחקן 3 שחקן 2 שחקן 1 שלב 1: שחקן 2 שחקן 3 שחקן 4

  46. הרעיון שלב 2: שחקן 4 שחקן 2 שחקן 4 שחקן 4 שחקן 3 שחקן 2 שחקן 1 שלב 1: שחקן 2 שחקן 4

  47. הרעיון שחקן 2 שלב 3 (המנצח): שלב 2: שחקן 4 שחקן 2 שחקן 4 שחקן 4 שחקן 3 שחקן 2 שחקן 1 שלב 1: שחקן 2

  48. publicstatic Player simulateTournament(LinkedList playersList){ Queue q = new QueueAsList(); Iterator it = playersList.iterator(); Player winner = null; while (it.hasNext()) { q.enqueue(it.next()); } while (!q.isEmpty()) { Player first = (Player)q.dequeue(); if (q.isEmpty()) { winner = first; } else { Player second = (Player)q.dequeue(); Player matchWinner = simulateMatch(first, second); q.enqueue(matchWinner); } } return winner; } 48

  49. מחסנית - Stack • מחסנית (stack) היא מבנה נתונים שמזכיר מחסנית של רובה-האיבר שנכנס ראשון יוצא אחרון (LIFO - Last In First Out). • ניתן להסתכל על מחסנית כעל קופסה סגורה בעלת פתח יחיד- הן עבור ההכנסה והן עבור ההוצאה. • הגישה דרך פתח יחיד יוצרת מצב שבו איבר שנכנס אחרון יוצא ראשון- LIFO . • מחסנית היא שימושית כאשר יש צורך לשמור נתונים בסדר מסוים ולשלוף אותם בסדר ההפוך.

  50. publicinterface Stack { /** *push-addsanelementtothestack. *@paramotheelementedtobeinsertedtothestack. */ publicvoid push (Object o); /** *pop-removesanelementformthestack(LIFOorder). *@returntheelementfromthetopofthestack. */ public Object pop (); /** *isEmpty-checksifthestackisemptyornot. *@returntrueifthereisnomoreelementsinthestack. */ publicboolean isEmpty(); }

More Related