1 / 52

מבני נתונים

מבני נתונים. שיעור 3,4 – מבני נתונים בסיסיים. מערך, תור, מחסנית. מבנה נתונים - כללי. מבנה נתונים מורכב מהגדרה מופשטת של המבנה והפעולות האפשריות עליו. מימוש מבנה הנתונים בשפת תכנות. למבנה הנתונים המופשט יש לרוב מספר דרכי מימוש.

hisano
Download Presentation

מבני נתונים

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. מבני נתונים שיעור 3,4 – מבני נתונים בסיסיים.מערך, תור, מחסנית.

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

  3. Arrays מערכים מערך הוא מבנה הנתונים הבסיסי והשימושי ביותר ברוב שפות התכנות. כל איבר במערך נקרא אלמנט. כל אלמנט ניתן לגישה ע"י אינדקס מספרי. ניתן לגשת לאיבר i בתוך מערך Aע"י A[i]

  4. מערכים – גישה לתאים • גודל מערך הינו קבוע (ידוע בזמן קומפילציה). • אינדקס של איבר במערך יכול להיות כל ביטוי שערכו מספר שלם – קבוע או משתנה או ביטוי מורכב, ואף כזה שערכו ידוע רק בזמן ריצה. • האינדקסים של מערך בגודל n הם המספרים בין 0 ל- n-1. התייחסות לאיבר לא קיים במערך (איבר שהאינדקס שלו קטן מ- 0 או גדול או שווה ל- n) עשויה לגרום לטעות בזמן ריצה.

  5. 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

  6. 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]; • למעשה נוצר מערך של מערכים... דוגמא...

  7. 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

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

  9. מערכים - דוגמא קליטת נתונים לתוך המערך. בכל איטרציה נקלט מספר אחד לתוך התא ה- i (המשתנה i משמש כמונה "הרץ" על האינדקסים של המערך). // This program reads 10 grades and prints the average grade. import java.util.Scanner; Public static void main(String args[]) { int grades[] = new int[10]; inti; double sum=0; Scanner scan = new Scanner(System.in); for (i=0; i<10; i++) { grades[i]=scan.nextInt(); } for (i=0; i<10; i++) { sum = sum+grades[i]; } double average = sum/10; System.out.println("The following grades are above average:\n"); for (i=0; i<10; i++) { if (grades[i]>average) { System.out.println(grades[i]); } } } סכימת אברי מערך. הדפסת התאים הרלוונטיים מן המערך.

  10. מבנה נתונים מופשטAbstract Data Type • הגדרת מבנה הנתונים, תכונותיו והפעולות (שיטות) הניתנות לביצוע על המבנה. • הגדרת מבנה נתונים מופשט מנותקת מאופן המימוש של המבנה (ארגון זיכרון המחשב) והשיטות שלו. • מגדיר מה קורה בעת שגיאות בהפעלת שיטות. • לעיתים יש כמה דרכים למימוש של מבנה נתונים מופשט.

  11. מחסנית – מבנה נתונים מופשט • מחסנית יכולה להכיל כל סוג של נתון. • הכנסה והוצאת איברים מהמחסנית ע"פעקרון "אחרון נכנס ראשון יוצא" LIFO • פעולות עיקריות: • push(object o): inserts an element • object pop(): removes and returns the last inserted element • object top(): returns a reference to the last inserted element without removing it • integer size(): returns the number of elements stored • booleanisEmpty(): indicates whether no elements are stored

  12. מחסנית - שגיאות • שגיאות עלולות להתרחש בעת נסיון להפעלת שיטה ששייכת למבנה הנתונים. • פעולות POP וTOP לא ניתנות לביצוע על מחסנית ריקה. • נסיון לבצע פעולות אלו על מחסנית ריקה תגרור הודעת שגיאה מתאימה.

  13. שימושים למחסנית • שימושים ישירים: • היסטוריית אתרים בדפדפן • פעולות undo למיניהן • שמירת משתנים מקומיים של פונקציות הקוראות לפונקציות אחרות... • שימושים עקיפים: • שמירת נתונים לאלגוריתמים אחרים • בסיס למבני נתונים מורכבים יותר

  14. מחסנית - דוגמא נגדיר מחלקה Stack עם השיטות הרלוונטיות Stack s = new Stack(); s.push(12); s.push(4); s.push( s.top() + 2 ); s.pop() s.push( s.top() ); //מה תכיל המחסנית?

  15. מימוש מחסנית ע"י מערך • מימוש פשוט למחסנית ניתן בעזרת מערך. • מכניסים ערכים משמאל לימין. • משתנה t מצביע על הערך העליון של המחסנית • חסרון: יש להגדיר מראש את הגודל המירבי. • חסרון: אם מנסים להכניס ערך למחסנית מלאה מקבלים שגיאה. … S 0 1 2 t N-1

  16. מימוש מחסנית ע"י מערך • נגדיר את המחלקה 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;}}

  17. שגיאות טיפוסיות בשימוש במחסנית • כתוב תוכנית המדפיסה את ערכי המחסנית תוך כדי מחיקתם: public class Main{ public static void main(String args[]){ Stack s = new Stack(); // הכנסת ערכים למחסנית for(inti = 0; i < 7; i++) s.push( i ); // הדפסת הערכים תוך כדי מחיקתם for(inti = 0; i < s.size(); i++) System.out.println( s.pop() ); } } מה הטעות?

  18. שגיאות טיפוסיות בשימוש במחסנית • דרך נכונה: public class Main{ public static void main(String args[]){ Stack s = new Stack(); // הכנסת ערכים למחסנית for(inti = 0; i < 7; i++) s.push( i ); // הדפסת הערכים תוך כדי מחיקתם intlimit = s.size(); for(inti = 0; i < limit; i++) System.out.println( s.pop() ); //דרך נוספת // while( !s.isEmpty() ) // System.out.println( s.pop() ); } }

  19. דוגמא לשימוש במחסנית: בדיקת איזון סוגריים • בכתיבת תוכניות מחשב כאשר יש שימוש בסוגריים (),{},[] חייב להיות איזון בביטוי המכיל סוגריים, כלומר כל פתיחת סוגר חייבת להיסגר • מחסנית היא כלי יעיל לבדיקת איזון סוגריים. כאשר מאתרים סגירת סוגריים יש לוודא שהיא תואמת לסוג הסוגריים האחרונים שנפתחו... • מה האלגוריתם?

  20. אלגוריתם לבדיקת איזון סוגריים • בנה מחסנית ריקה • עבור על הביטוי תו אחר תו עד סופו (לולאה): • אם התו הוא פתיחת סוגריים הכנס אותו למחסנית (push) • אם התו הוא סגירת סוגריים עשה • אם המחסנית ריקה דווח "לא מאוזן" • אחרת, שלוף תו מהמחסנית (pop), אם התו הנ"ל לא מתאים לסימון הסוגר דווח "לא מאוזן" • אם לאחר מעבר על כל התווים המחסנית אינה ריקה דווח "לא מאוזן" • דוגמא: if(a+{2*max(A[],5)}>7)

  21. חישוב ביטוי מתמטי בעזרת מחסנית • כמה זה 2+3*5, 4-4/2, 1+4^2 ? • בחישוב ביטויים מתמטיים לא ניתן לבצע את הפעולות לפי הסדר משמאל לימין. יש קדימויות ברורות בין הפעולות (כפל לפני חיבור וכו..) • זהו אתגר בחישוב אוטומטי של ביטויים בתוכניות מחשב. • כמה זה 1 - 2 - 4 ^ 5 * 3 * 6 / 7 ^ 2 ^ 2 ???

  22. ייצוג Infix לעומת Postfix • הדרך בה אנו מורגלים לרשום ביטויים מתמטיים נקרא ייצוג Infix למשל 3+4*8 • ייצוג Postfix ניתן לחישוב ללא התחשבות בקדימויות בין פעולות. אופן בניית הביטוי ב Postfix לוקח בחשבון את הקדימויות. • הביטוי 2*3+4 מיוצג כ 2 3 * 4 + ב Postfix • ניתן להשתמש במחסנית לחישוב ביטוי Postfix וכמו כן להמרת ייצוג Infixל Postfix

  23. המרת Infix ל Postfix • עבור על הביטוי Infix (נניח שהוא נתון כמחרוזת) תו אחר תו (לולאה) ובנה את ביטוי ה Postfix • אם התו הוא מספר או משתנה: הוסף אותו לביטוי החדש מימין. • אם התו הוא פעולה: שלוף ערכים מהמחסנית והוסף אותם לביטוי החדש עד אשר תופיע פעולה בעלת קדימות נמוכה מהפעולה הנוכחית או סוגר שמאלי או סוף המחסנית ואז הוסף את הפעולה הנוכחית למחסנית. • אם התו הוא סוגר שמאלי: הוסף אותו למחסנית. • אם התו הוא סוגר ימני: שלוף ערכים מהמחסנית והוסף אותם לביטוי החדש עד שניתקלים בסוגר שמאלי או בסוף המחסנית (את הסוגריים לא מוסיפים לביטוי החדש) • כאשר מסיימים לעבור על כל התווים יש לשלוף את שאר הערכים מתוך המחסנית ולהוסיפם לביטוי החדש.

  24. דוגמא פשוטה Infix Expression: 3 + 2 * 4 PostFix Expression: Operator Stack:

  25. דוגמא פשוטה Infix Expression: + 2 * 4 PostFix Expression:3 Operator Stack:

  26. דוגמא פשוטה Infix Expression: 2 * 4 PostFix Expression:3 Operator Stack: +

  27. דוגמא פשוטה Infix Expression: * 4 PostFix Expression:3 2 Operator Stack: +

  28. דוגמא פשוטה Infix Expression: 4 PostFix Expression:3 2 Operator Stack: + *

  29. דוגמא פשוטה Infix Expression: PostFix Expression:3 2 4 Operator Stack: + *

  30. דוגמא פשוטה Infix Expression: PostFix Expression:3 2 4 * + Operator Stack:

  31. הדגמת פעולת האלגוריתם Infix: 1 - 2 ^ 3 ^ 3 - ( 4 + 5 * 6 ) * 7 Postfix: 1 2 3 ^ 3 ^ - 4 5 6 * + 7 * -

  32. אלגוריתם לחישוב Postfix • עבור על הביטוי postfix (נניח שהוא נתון כמחרוזת) תו אחר תו משמאל לימין (לולאה): • אם התו הוא מספר או משתנה הוסף אותו למחסנית • אחרת, אם התו הוא פעולה עשה: • שלוף ערך מהמחסנית והצב אותו מימין לפעולה. • שלוף ערך מהמחסנית והצב אותו משמאל לפעולה. • בצע את החישוב של הפעולה עם הערכים. • הוסף את התוצאה למחסנית. • כאשר מסיימים לעבור על כל התווים, הערך האחרון שנשאר במחסנית הוא התוצאה הסופית.

  33. המרה וחישוב - דוגמא 5 * (6 + 2) – 12 / 4 = 37 Infix • 5 6 2 + * 12 4 / – = ? Postfix

  34. תור – מבנה נתונים מופשט • תור יכול להכיל כל סוג של נתון. • הכנסה והוצאת איברים מהתור ע"פעקרון "ראשון נכנס ראשון יוצא" FIFO • הכנסת איבר לסוף התור והוצאה מתחילתו • פעולות עיקריות: • enqueue(object): inserts an element at the end of the queue • object dequeue(): removes and returns the element at the front of the queue • object front(): returns the element at the front without removing it • integer size(): returns the number of elements stored • booleanisEmpty(): indicates whether no elements are stored

  35. תור - שגיאות • שגיאות עלולות להתרחש בעת נסיון להפעלת שיטה ששייכת למבנה הנתונים. • פעולות dequeueוfront לא ניתנות לביצוע על תור ריק. • נסיון לבצע פעולות אלו על תור ריק תגרור הודעת שגיאה מתאימה. (throw EmptyQueueException)

  36. פעולות על תור - דוגמא Operation Output Q enqueue(5) – (5) enqueue(3) – (5, 3) dequeue() 5 (3) enqueue(7) – (3, 7) dequeue() 3 (7) front() 7 (7) dequeue() 7 () dequeue() “error” () isEmpty() true () enqueue(9) – (9) enqueue(7) – (9, 7) size() 2 (9, 7) enqueue(3) – (9, 7, 3) enqueue(5) – (9, 7, 3, 5) dequeue() 9 (7, 3, 5)

  37. שימושים לתור • שימושים ישירים: • רשימות המתנה • גישה למשאבים משותפים (תור למדפסת ציבורית) • תכנות מקבילי (תור לביצוע פעולות חישוב) • שימושים רבים במערכות הפעלה (קלט/פלט) • סימולציות למוקדי שירות (לחישוב מספר פקידים) • שימושים עקיפים: • שמירת נתונים לאלגוריתמים אחרים • בסיס למבני נתונים מורכבים יותר

  38. מימוש תור ע"י מערך • ניתן להשתמש במערך למימוש תור. • נחזיק משתנים f, r שיציינו את תחילת וסוף התורויעודכנו בהתאמה. • מיקום r נשאר ריק (הוא למעשה המיקום המציין את אחד מאחורי האחרון בתור) • בעיה: נגיע מהר מאוד לסוף המערך מכוון שכל הוצאת ערך מהתור תקדם את r לכיוון f עד שיחרוג מגבולות המערך. למרות שמספר הערכים בתור קטן מגודל המערך בפועל.

  39. בעיית המימוש ע"י מערך • בנה תור המבוסס על מערך בגודל 5 (f=0, r=0) • הכנס 4 ערכים לתור (f=0, r=5) • הוצא 4 ערכים מהתור (f=4, r=5) • הכנס ערך לתור – שגיאת "תור מלא" למרות שהתור ריק!! 0 1 2 3 4 פתרון: שימוש במערך בצורה מעגלית. לא פותר את בעיית גודל מקסימלי של התור.

  40. תור – מימוש ע"י מערך מעגלי

  41. Q 0 1 2 f r Q 0 1 2 r f מימוש תור ע"י מערך מעגלי • שימוש במערך בגודל N באופן מעגלי • שני משתנים העוקבים אחר תחילת וסוף התור fאינדקס המציין את תחילת התור • rאינדקס המציין מיקום אחד אחרי סוף התור • אינדקס r נשמר ריק במערך. תור בתצורה רגילה תור בתצורה מעגלית

  42. Q 0 1 2 f r Q 0 1 2 r f פעולות תור Algorithmsize() return(N-f +r) mod N AlgorithmisEmpty() return(f=r) • נשתמש באופרטור MOD (שארית אחרי חלוקה) לתפעול מעגלי של המערך.

  43. Q 0 1 2 f r Q 0 1 2 r f פעולות תור Algorithmenqueue(o) ifsize()=N 1then throw FullQueueException else Q[r] o r(r + 1) mod N • שיטתenqueue זורקת שגיאה אם התור מלא.

  44. Q 0 1 2 f r Q 0 1 2 r f פעולות תור Algorithmdequeue() ifisEmpty()then throw EmptyQueueException else oQ[f] f(f + 1) mod N returno • שיטתdequeue זורקת שגיאה אם התור מלא.

  45. מימוש תור ע"י מערך - 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}}

  46. שימוש בתור • כתוב תוכנית המדפיסה את ערכי התור תוך כדי מחיקתם ותדפיס את ממוצע האיברים והאיבר הכי גדול: public class Main{ public static void main(String args[]){ Queue q = new Queue (10); // הכנסת ערכים לתור for (inti=0; i<8; i++) q.enqueue(i*2); // הדפסת הערכים תוך כדי מחיקתם inttmp ; int sum = 0; int max = q.front(); while (!q.isEmpty()) {tmp= q.dequeue() ; sum=sum+tmp; if tmp>max then max=tmp; System.out.println(tmp);} System.out.println(“max=“ + max); System.out.println(“mean=“ + sum/8); }

  47. דוגמא – סימולציית תור בבנק • תור יחיד עם נותן שירות אחד. • ידוע כי זמן השירות הממוצע לאדם הוא דקה. • כמו כן ידוע כי בכל דקה מצטרפים בין 0 ל 2 לקוחות חדשים לתור. • בנוסף המערכת תחשב: • מספר הלקוחות שקיבלו שירות בכל רגע נתון. • זמן ההמתנה הכללי של כל הלקוחות בתור. • זמן ההמתנה בתור המקסימלי.

  48. פסאודו קוד לסימולציית תור Initialize the queue to empty. for ( minute = 0 ; minute < n ; ++minute ) { if the queue is not empty, then remove the customer at the front of the queue. Compute a random number k between 0 and 3. If k is 1, then add one customer to the line. If k is 2, then add two customers to the line. Otherwise (if k is 0 or 3), do not add any customers to the line. }

  49. סימולצית תור ל5 דקות

  50. The Queue 2 . Service the 3 . Enqueue the 1 . Deque the next element serviced element next element Shared Service שימוש בתור לתזמון Round Robin • כאשר מספר לקוחות מקבלים שירות ממקור יחיד ומעוניינים לתת לכל לקוח שירות לזמן קצוב, להחזירו לסוף התור ולהמשיך להבא בתור. • ניתן להשתמש בתור Qולבצע את הפעולות הבאות: • e = Q.dequeue()הוצאת הלקוח הבא בתור • Service element e מתן שירות ללקוח • Q.enqueue(e)החזרת הלקוח לסוף התור

More Related