003.class3_4

Download Report

Transcript 003.class3_4

‫מבני נתונים‬
‫שיעור ‪ – 3,4‬מבני נתונים בסיסיים‪.‬‬
‫מערך‪ ,‬תור‪ ,‬מחסנית‪.‬‬
‫מבנה נתונים ‪ -‬כללי‬
‫• מבנה נתונים מורכב מהגדרה מופשטת של‬
‫המבנה והפעולות האפשריות עליו‪.‬‬
‫• מימוש מבנה הנתונים בשפת תכנות‪ .‬למבנה‬
‫הנתונים המופשט יש לרוב מספר דרכי מימוש‪.‬‬
‫• למבנה נתונים מסויים יש שימושים שונים‬
‫(אפליקציות)‪ ,‬לעיתים מבנה נתונים משמש‬
‫בסיס למבנה נתונים מורכב יותר‪.‬‬
‫‪2‬‬
‫מערכים‬
‫‪Arrays‬‬
‫מערך הוא מבנה הנתונים הבסיסי והשימושי ביותר ברוב‬
‫שפות התכנות‪.‬‬
‫כל איבר במערך נקרא אלמנט‪.‬‬
‫כל אלמנט ניתן לגישה ע"י אינדקס מספרי‪.‬‬
‫ניתן לגשת לאיבר ‪ i‬בתוך מערך ‪ A‬ע"י ]‪A[i‬‬
‫מערכים – גישה לתאים‬
‫‪‬‬
‫גודל מערך הינו קבוע (ידוע בזמן קומפילציה)‪.‬‬
‫‪‬‬
‫אינדקס של איבר במערך יכול להיות כל ביטוי שערכו מספר‬
‫שלם – קבוע או משתנה או ביטוי מורכב‪ ,‬ואף כזה שערכו ידוע‬
‫רק בזמן ריצה‪.‬‬
‫‪‬‬
‫האינדקסים של מערך בגודל ‪ n‬הם המספרים בין ‪ 0‬ל‪.n-1 -‬‬
‫התייחסות לאיבר לא קיים במערך (איבר שהאינדקס שלו קטן‬
‫מ‪ 0 -‬או גדול או שווה ל‪ )n -‬עשויה לגרום לטעות בזמן ריצה‪.‬‬
‫‪4‬‬
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
‫מערכים ‪ -‬מוטיבציה‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫נתונה רשימה של מספרים המייצגים ציונים‪.‬‬
‫יש לחשב את ממוצע כל הציונים ולהדפיס את הציונים הגבוהים‬
‫מהממוצע‪.‬‬
‫הבעיה‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫על מנת לחשב את הממוצע יש לקרוא את כל הציונים‪.‬‬
‫לא ניתן לדעת לפני סוף הקלט‪ ,‬אלו מהציונים גבוהים מהממוצע‪.‬‬
‫לא ניתן לדעת בעת קליטת הנתונים אלו מהם צריכים להיות מודפסים‪.‬‬
‫יש לאחסן את כל הנתונים‪.‬‬
‫הפתרון‪ :‬שימוש במערכים‪.‬‬
‫‪8‬‬
// 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];
int i;
‫ בכל‬.‫קליטת נתונים לתוך המערך‬
double sum=0;
Scanner scan = new Scanner(System.in);
‫איטרציה נקלט מספר אחד לתוך‬
for (i=0; i<10; i++) {
‫ משמש‬i ‫ (המשתנה‬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]);
}
}
}
‫מבנה נתונים מופשט‬
‫‪Abstract Data Type‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫הגדרת מבנה הנתונים‪ ,‬תכונותיו והפעולות‬
‫(שיטות) הניתנות לביצוע על המבנה‪.‬‬
‫הגדרת מבנה נתונים מופשט מנותקת מאופן‬
‫המימוש של המבנה (ארגון זיכרון המחשב)‬
‫והשיטות שלו‪.‬‬
‫מגדיר מה קורה בעת שגיאות בהפעלת שיטות‪.‬‬
‫לעיתים יש כמה דרכים למימוש של מבנה‬
‫נתונים מופשט‪.‬‬
‫‪10‬‬
‫מחסנית – מבנה נתונים מופשט‬
.‫• מחסנית יכולה להכיל כל סוג של נתון‬
‫• הכנסה והוצאת איברים מהמחסנית ע"פ‬
LIFO "‫עקרון "אחרון נכנס ראשון יוצא‬
:‫• פעולות עיקריות‬
11
 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
 boolean isEmpty(): indicates whether no elements are
stored
‫מחסנית ‪ -‬שגיאות‬
‫• שגיאות עלולות להתרחש בעת נסיון להפעלת‬
‫שיטה ששייכת למבנה הנתונים‪.‬‬
‫• פעולות ‪ POP‬ו‪ TOP‬לא ניתנות לביצוע על‬
‫מחסנית ריקה‪.‬‬
‫• נסיון לבצע פעולות אלו על מחסנית ריקה תגרור‬
‫הודעת שגיאה מתאימה‪.‬‬
‫‪12‬‬
‫שימושים למחסנית‬
‫• שימושים ישירים‪:‬‬
‫– היסטוריית אתרים בדפדפן‬
‫– פעולות ‪ undo‬למיניהן‬
‫– שמירת משתנים מקומיים של פונקציות הקוראות‬
‫לפונקציות אחרות‪...‬‬
‫• שימושים עקיפים‪:‬‬
‫– שמירת נתונים לאלגוריתמים אחרים‬
‫– בסיס למבני נתונים מורכבים יותר‬
‫‪13‬‬
‫מחסנית ‪ -‬דוגמא‬
‫נגדיר מחלקה ‪ Stack‬עם השיטות הרלוונטיות‬
‫;)(‪Stack s = new Stack‬‬
‫;)‪s.push(12‬‬
‫;)‪s.push(4‬‬
‫;) ‪s.push( s.top() + 2‬‬
‫)(‪s.pop‬‬
‫מה תכיל המחסנית?‪s.push( s.top() ); //‬‬
‫‪14‬‬
‫מימוש מחסנית ע"י מערך‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫מימוש פשוט למחסנית ניתן בעזרת מערך‪.‬‬
‫מכניסים ערכים משמאל לימין‪.‬‬
‫משתנה ‪ t‬מצביע על הערך העליון של המחסנית‬
‫חסרון‪ :‬יש להגדיר מראש את הגודל המירבי‪.‬‬
‫חסרון‪ :‬אם מנסים להכניס ערך למחסנית מלאה‬
‫מקבלים שגיאה‪.‬‬
‫…‬
‫‪N-1‬‬
‫‪t‬‬
‫‪S‬‬
‫‪0 1 2‬‬
‫‪15‬‬
‫מימוש מחסנית ע"י מערך‬
:)‫ (נניח שמחזיקה ערכים שלמים‬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;}}
•
‫שגיאות טיפוסיות בשימוש במחסנית‬
‫• כתוב תוכנית המדפיסה את ערכי המחסנית תוך כדי מחיקתם‪:‬‬
‫{‪public class Main‬‬
‫{)][‪public static void main(String args‬‬
‫;)(‪Stack s = new Stack‬‬
‫הכנסת ערכים למחסנית ‪//‬‬
‫)‪for(int i = 0; i < 7; i++‬‬
‫;) ‪s.push( i‬‬
‫הדפסת הערכים תוך כדי מחיקתם ‪//‬‬
‫)‪for(int i = 0; i < s.size(); i++‬‬
‫;) )(‪System.out.println( s.pop‬‬
‫}‬
‫}‬
‫מה הטעות?‬
‫‪17‬‬
‫שגיאות טיפוסיות בשימוש במחסנית‬
:‫דרך נכונה‬
public class Main{
public static void main(String args[]){
Stack s = new Stack();
// ‫הכנסת ערכים למחסנית‬
for(int i = 0; i < 7; i++)
s.push( i );
// ‫הדפסת הערכים תוך כדי מחיקתם‬
int limit = s.size();
for(int i = 0; i < limit; i++)
System.out.println( s.pop() );
//‫דרך נוספת‬
// while( !s.isEmpty() )
// System.out.println( s.pop() );
}
}
•
‫דוגמא לשימוש במחסנית‪:‬‬
‫בדיקת איזון סוגריים‬
‫• בכתיבת תוכניות מחשב כאשר יש שימוש‬
‫בסוגריים ()‪ ][,}{,‬חייב להיות איזון בביטוי המכיל‬
‫סוגריים‪ ,‬כלומר כל פתיחת סוגר חייבת להיסגר‬
‫• מחסנית היא כלי יעיל לבדיקת איזון סוגריים‪.‬‬
‫כאשר מאתרים סגירת סוגריים יש לוודא שהיא‬
‫תואמת לסוג הסוגריים האחרונים שנפתחו‪...‬‬
‫• מה האלגוריתם?‬
‫‪19‬‬
‫אלגוריתם לבדיקת איזון סוגריים‬
‫• בנה מחסנית ריקה‬
‫• עבור על הביטוי תו אחר תו עד סופו (לולאה)‪:‬‬
‫– אם התו הוא פתיחת סוגריים הכנס אותו למחסנית (‪)push‬‬
‫– אם התו הוא סגירת סוגריים עשה‬
‫• אם המחסנית ריקה דווח "לא מאוזן"‬
‫• אחרת‪ ,‬שלוף תו מהמחסנית (‪ ,)pop‬אם התו הנ"ל לא מתאים‬
‫לסימון הסוגר דווח "לא מאוזן"‬
‫• אם לאחר מעבר על כל התווים המחסנית אינה ריקה‬
‫דווח "לא מאוזן"‬
‫‪20‬‬
‫• דוגמא‪if(a+{2*max(A[],5)}>7) :‬‬
‫חישוב ביטוי מתמטי בעזרת מחסנית‬
‫•‬
‫•‬
‫•‬
‫•‬
‫כמה זה ‪? 2+3*5, 4-4/2, 1+4^2‬‬
‫בחישוב ביטויים מתמטיים לא ניתן לבצע את‬
‫הפעולות לפי הסדר משמאל לימין‪ .‬יש קדימויות‬
‫ברורות בין הפעולות (כפל לפני חיבור וכו‪)..‬‬
‫זהו אתגר בחישוב אוטומטי של ביטויים‬
‫בתוכניות מחשב‪.‬‬
‫כמה זה ‪??? 1 - 2 - 4 ^ 5 * 3 * 6 / 7 ^ 2 ^ 2‬‬
‫‪21‬‬
‫ייצוג ‪ Infix‬לעומת ‪Postfix‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫הדרך בה אנו מורגלים לרשום ביטויים‬
‫מתמטיים נקרא ייצוג ‪ Infix‬למשל ‪8*3+4‬‬
‫ייצוג ‪ Postfix‬ניתן לחישוב ללא התחשבות‬
‫בקדימויות בין פעולות‪ .‬אופן בניית הביטוי ב‬
‫‪ Postfix‬לוקח בחשבון את הקדימויות‪.‬‬
‫הביטוי ‪ 2*3+4‬מיוצג כ ‪ 2 3 * 4 +‬ב ‪Postfix‬‬
‫ניתן להשתמש במחסנית לחישוב ביטוי ‪Postfix‬‬
‫וכמו כן להמרת ייצוג ‪ Infix‬ל ‪Postfix‬‬
‫‪22‬‬
‫המרת ‪ Infix‬ל ‪Postfix‬‬
‫• עבור על הביטוי ‪( Infix‬נניח שהוא נתון כמחרוזת) תו אחר‬
‫תו (לולאה) ובנה את ביטוי ה ‪Postfix‬‬
‫–‬
‫–‬
‫–‬
‫–‬
‫אם התו הוא מספר או משתנה‪ :‬הוסף אותו לביטוי החדש מימין‪.‬‬
‫אם התו הוא פעולה‪ :‬שלוף ערכים מהמחסנית והוסף אותם‬
‫לביטוי החדש עד אשר תופיע פעולה בעלת קדימות נמוכה‬
‫מהפעולה הנוכחית או סוגר שמאלי או סוף המחסנית ואז הוסף‬
‫את הפעולה הנוכחית למחסנית‪.‬‬
‫אם התו הוא סוגר שמאלי‪ :‬הוסף אותו למחסנית‪.‬‬
‫אם התו הוא סוגר ימני‪ :‬שלוף ערכים מהמחסנית והוסף אותם‬
‫לביטוי החדש עד שניתקלים בסוגר שמאלי או בסוף המחסנית‬
‫(את הסוגריים לא מוסיפים לביטוי החדש)‬
‫• כאשר מסיימים לעבור על כל התווים יש לשלוף את שאר‬
‫הערכים מתוך המחסנית ולהוסיפם לביטוי החדש‪.‬‬
‫‪23‬‬
‫דוגמא פשוטה‬
Infix Expression:
PostFix Expression:
Operator Stack:
24
3+2*4
‫דוגמא פשוטה‬
Infix Expression:
PostFix Expression:
Operator Stack:
25
+2*4
3
‫דוגמא פשוטה‬
Infix Expression:
PostFix Expression:
Operator Stack:
26
2*4
3
+
‫דוגמא פשוטה‬
Infix Expression:
PostFix Expression:
Operator Stack:
27
*4
32
+
‫דוגמא פשוטה‬
Infix Expression:
PostFix Expression:
Operator Stack:
28
4
32
+*
‫דוגמא פשוטה‬
Infix Expression:
PostFix Expression:
Operator Stack:
29
324
+*
‫דוגמא פשוטה‬
Infix Expression:
PostFix Expression:
Operator Stack:
30
324*+
‫הדגמת פעולת האלגוריתם‬
‫‪Infix: 1 - 2 ^ 3 ^ 3 - ( 4 + 5 * 6 ) * 7‬‬
‫‪Postfix: 1 2 3 ^ 3 ^ - 4 5 6 * + 7 * -‬‬
‫‪31‬‬
‫אלגוריתם לחישוב ‪Postfix‬‬
‫• עבור על הביטוי ‪( postfix‬נניח שהוא נתון כמחרוזת)‬
‫תו אחר תו משמאל לימין (לולאה)‪:‬‬
‫– אם התו הוא מספר או משתנה הוסף אותו למחסנית‬
‫– אחרת‪ ,‬אם התו הוא פעולה עשה‪:‬‬
‫•‬
‫•‬
‫•‬
‫•‬
‫שלוף ערך מהמחסנית והצב אותו מימין לפעולה‪.‬‬
‫שלוף ערך מהמחסנית והצב אותו משמאל לפעולה‪.‬‬
‫בצע את החישוב של הפעולה עם הערכים‪.‬‬
‫הוסף את התוצאה למחסנית‪.‬‬
‫• כאשר מסיימים לעבור על כל התווים‪ ,‬הערך האחרון‬
‫שנשאר במחסנית הוא התוצאה הסופית‪.‬‬
‫‪32‬‬
‫המרה וחישוב ‪ -‬דוגמא‬
‫‪5 * (6 + 2) – 12 / 4 = 37‬‬
‫‪Infix‬‬
‫? = – ‪5 6 2 + * 12 4 /‬‬
‫‪Postfix‬‬
‫‪33‬‬
‫תור – מבנה נתונים מופשט‬
.‫תור יכול להכיל כל סוג של נתון‬
‫הכנסה והוצאת איברים מהתור ע"פ‬
FIFO "‫עקרון "ראשון נכנס ראשון יוצא‬
‫הכנסת איבר לסוף התור והוצאה מתחילתו‬
:‫פעולות עיקריות‬
34
•
•
•
•
 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
 boolean isEmpty(): indicates whether no elements are
stored
‫תור ‪ -‬שגיאות‬
‫• שגיאות עלולות להתרחש בעת נסיון להפעלת‬
‫שיטה ששייכת למבנה הנתונים‪.‬‬
‫• פעולות ‪ dequeue‬ו ‪ front‬לא ניתנות לביצוע על‬
‫תור ריק‪.‬‬
‫• נסיון לבצע פעולות אלו על תור ריק תגרור הודעת‬
‫שגיאה מתאימה‪(throw EmptyQueueException) .‬‬
‫‪35‬‬
‫ דוגמא‬- ‫פעולות על תור‬
Operation
enqueue(5)
enqueue(3)
dequeue()
enqueue(7)
dequeue()
front()
dequeue()
dequeue()
isEmpty()
enqueue(9)
enqueue(7)
size()
enqueue(3)
enqueue(5)
dequeue()
36
Output
–
–
5
–
3
7
7
“error”
true
–
–
2
–
–
9
Q
(5)
(5, 3)
(3)
(3, 7)
(7)
(7)
()
()
()
(9)
(9, 7)
(9, 7)
(9, 7, 3)
(9, 7, 3, 5)
(7, 3, 5)
‫שימושים לתור‬
‫• שימושים ישירים‪:‬‬
‫–‬
‫–‬
‫–‬
‫–‬
‫–‬
‫רשימות המתנה‬
‫גישה למשאבים משותפים (תור למדפסת ציבורית)‬
‫תכנות מקבילי (תור לביצוע פעולות חישוב)‬
‫שימושים רבים במערכות הפעלה (קלט‪/‬פלט)‬
‫סימולציות למוקדי שירות (לחישוב מספר פקידים)‬
‫• שימושים עקיפים‪:‬‬
‫– שמירת נתונים לאלגוריתמים אחרים‬
‫– בסיס למבני נתונים מורכבים יותר‬
‫‪37‬‬
‫מימוש תור ע"י מערך‬
‫•‬
‫•‬
‫•‬
‫•‬
‫ניתן להשתמש במערך למימוש תור‪.‬‬
‫נחזיק משתנים ‪ f, r‬שיציינו את תחילת וסוף התור‬
‫ויעודכנו בהתאמה‪.‬‬
‫מיקום ‪ r‬נשאר ריק (הוא למעשה המיקום המציין‬
‫את אחד מאחורי האחרון בתור)‬
‫בעיה‪ :‬נגיע מהר מאוד לסוף המערך מכוון שכל‬
‫הוצאת ערך מהתור תקדם את ‪ r‬לכיוון ‪ f‬עד‬
‫שיחרוג מגבולות המערך‪ .‬למרות שמספר הערכים‬
‫בתור קטן מגודל המערך בפועל‪.‬‬
‫‪38‬‬
‫בעיית המימוש ע"י מערך‬
‫•בנה תור המבוסס על מערך בגודל ‪)f=0, r=0( 5‬‬
‫•הכנס ‪ 4‬ערכים לתור (‪)f=0, r=5‬‬
‫•הוצא ‪ 4‬ערכים מהתור (‪)f=4, r=5‬‬
‫•הכנס ערך לתור – שגיאת "תור מלא" למרות שהתור ריק!!‬
‫‪4‬‬
‫‪3‬‬
‫‪2‬‬
‫‪1‬‬
‫‪0‬‬
‫פתרון‪ :‬שימוש במערך בצורה מעגלית‪.‬‬
‫לא פותר את בעיית גודל מקסימלי של התור‪.‬‬
‫‪39‬‬
‫תור – מימוש ע"י מערך מעגלי‬
qback
qfront
qback
qback
qback
D
A
C
B
C
C
C
B
qfront
qfront
Insert elements A,B, C Remove element A Remove element B
D
C
qback
D
E
C
40
D
E
D
qfront
qback qfront
Insert element D, Insert element E
Array View
qback
qfront
Insert element D,
qfront C
qfront C
qback
Insert element D, Insert element E
Circular View
‫מימוש תור ע"י מערך מעגלי‬
‫שימוש במערך בגודל ‪ N‬באופן מעגלי‬
‫שני משתנים העוקבים אחר תחילת וסוף התור‬
‫‪ f‬אינדקס המציין את תחילת התור‬
‫‪ r‬אינדקס המציין מיקום אחד אחרי סוף התור‬
‫אינדקס ‪ r‬נשמר ריק במערך‪.‬‬
‫תור בתצורה רגילה‬
‫‪r‬‬
‫‪Q‬‬
‫‪f‬‬
‫‪0 1 2‬‬
‫תור בתצורה מעגלית‬
‫‪f‬‬
‫‪r‬‬
‫‪Q‬‬
‫‪0 1 2‬‬
‫פעולות תור‬
‫ • נשתמש באופרטור‬Algorithm size()
return (N - f + r) mod N
‫ (שארית אחרי‬MOD
‫חלוקה) לתפעול מעגלי‬
Algorithm isEmpty()
.‫של המערך‬
return (f = r)
Q
0 1 2
f
0 1 2
r
r
Q
42
f
‫פעולות תור‬
‫ זורקת‬enqueue ‫ • שיטת‬Algorithm enqueue(o)
if size() = N - 1 then
.‫שגיאה אם התור מלא‬
throw FullQueueException
else
Q[r]  o
r  (r + 1) mod N
Q
0 1 2
f
0 1 2
r
r
Q
43
f
‫פעולות תור‬
‫ זורקת‬dequeue ‫ • שיטת‬Algorithm dequeue()
if isEmpty() then
.‫שגיאה אם התור מלא‬
throw EmptyQueueException
else
o  Q[f]
f  (f + 1) mod N
return o
Q
0 1 2
f
0 1 2
r
r
Q
44
f
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}}
•
‫שימוש בתור‬
‫• כתוב תוכנית המדפיסה את ערכי התור תוך כדי מחיקתם‬
:‫ותדפיס את ממוצע האיברים והאיבר הכי גדול‬
public class Main{
public static void main(String args[]){
Queue q = new Queue (10);
// ‫הכנסת ערכים לתור‬
for (int i=0; i<8; i++)
q.enqueue(i*2);
// ‫הדפסת הערכים תוך כדי מחיקתם‬
int tmp ;
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);
}
46
‫דוגמא – סימולציית תור בבנק‬
‫•‬
‫•‬
‫•‬
‫•‬
‫תור יחיד עם נותן שירות אחד‪.‬‬
‫ידוע כי זמן השירות הממוצע לאדם הוא דקה‪.‬‬
‫כמו כן ידוע כי בכל דקה מצטרפים בין ‪ 0‬ל ‪2‬‬
‫לקוחות חדשים לתור‪.‬‬
‫בנוסף המערכת תחשב‪:‬‬
‫– מספר הלקוחות שקיבלו שירות בכל רגע נתון‪.‬‬
‫– זמן ההמתנה הכללי של כל הלקוחות בתור‪.‬‬
‫– זמן ההמתנה בתור המקסימלי‪.‬‬
‫‪47‬‬
‫פסאודו קוד לסימולציית תור‬
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. }
48
‫סימולצית תור ל‪ 5‬דקות‬
‫‪49‬‬
‫שימוש בתור לתזמון ‪Round Robin‬‬
‫• כאשר מספר לקוחות מקבלים שירות ממקור יחיד‬
‫ומעוניינים לתת לכל לקוח שירות לזמן קצוב‪ ,‬להחזירו‬
‫לסוף התור ולהמשיך להבא בתור‪.‬‬
‫• ניתן להשתמש בתור ‪ Q‬ולבצע את הפעולות הבאות‪:‬‬
‫הוצאת הלקוח הבא בתור )(‪e = Q.dequeue‬‬
‫מתן שירות ללקוח ‪Service element e‬‬
‫החזרת הלקוח לסוף התור )‪Q.enqueue(e‬‬
‫‪1.‬‬
‫‪2.‬‬
‫‪3.‬‬
‫‪The Queue‬‬
‫‪3. Enqueue the‬‬
‫‪serviced element‬‬
‫‪2 . Service the‬‬
‫‪next element‬‬
‫‪1. Deque the‬‬
‫‪next element‬‬
‫‪Shared‬‬
‫‪Service‬‬
‫‪50‬‬
‫תור עם עדיפויות‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫בתור עם עדיפויות איברי התור יוצאים בהתאם‬
‫לעדיפות שנקבעה מראש ולאו דוקא ע"פ סדר‬
‫כניסתם לתור‪.‬‬
‫איברים בעלי אותה העדיפות יוצאו ע"פ ‪FIFO‬‬
‫ניתן לממש תור עם עדיפויות ע"י מספר תורים‬
‫רגילים‪.‬‬
‫לכל רמת עדיפות יהיה תור משלו‪.‬‬
‫האיבר הבא בתור ייקבע ע"פ התור הלא ריק‬
‫בעל העדיפות הגבוה ביותר‪.‬‬
‫‪51‬‬
‫מימוש תור עם עדיפויות‬
class public PQueue{
private Queue list[]; //)‫מערך של תורים (לכל רמת עדיפות תור נפרד‬
private int prior, N; //‫מספר רמות העדיפות‬
public PQueue(int p, int n){//‫מספר רמות העדיפות וגודל מערך לכל רמה‬
prior=p; N=n; list=new Queue[p];
for (int i=0;i<p;i++) list[i]=new Queue(n);}// ‫בנאי מאתחל את המערך‬
public int size(){int sz; for (int i=0;i<num;i++) sz=sz+list[i].size();return sz;}
public boolean isEmpty(){boolean e=True; for (int i=0;i<num;i++) e=e &&
list[i].isEmpty(); return e;}
public int front(){for (int i=0;i<n;i++) if !list[i].isEmpty then return
list[i].front(); throw emptyQueueException;}
public int dequeue(){for (int i=0;i<n;i++) if !list[i].isEmpty then return
list[i].dequeue(); throw emptyQueueException;}
public void enqueue(int new, int priority){//‫ערך חדש ורמת עדיפותו‬
if list[priority].size()==N-1 then throw fullQueueException;//‫תור מלא‬
else list[priority].enqueu(new);}
52