מבני נתונים מופשטים בסיסיים רשימה : a1 , a2 ,....,an רשימה ריקה n=0 משמעויות : ראשון : a a a לפני 1 אחרון : n מקום : i a i 1 מבנה נתונים : L:LIST P:POSITION פעולות : המקום האחרי - אחרון :  יתכנו הרבה  אנחנו מעניינים בישום השמטת כפולים

Download Report

Transcript מבני נתונים מופשטים בסיסיים רשימה : a1 , a2 ,....,an רשימה ריקה n=0 משמעויות : ראשון : a a a לפני 1 אחרון : n מקום : i a i 1 מבנה נתונים : L:LIST P:POSITION פעולות : המקום האחרי - אחרון :  יתכנו הרבה  אנחנו מעניינים בישום השמטת כפולים

‫מבני נתונים מופשטים בסיסיים‬
‫רשימה‪:‬‬
‫‪a1 , a2 ,....,an‬‬
‫רשימה ריקה‬
‫‪n=0‬‬
‫משמעויות‪ :‬ראשון‪:‬‬
‫‪a‬‬
‫‪a‬‬
‫‪ a‬לפני‬
‫‪1‬‬
‫אחרון‪:‬‬
‫‪n‬‬
‫מקום‪:‬‬
‫‪i‬‬
‫‪a‬‬
‫‪i 1‬‬
‫מבנה נתונים‪:‬‬
‫‪L:LIST‬‬
‫‪P:POSITION‬‬
‫פעולות‪:‬‬
‫המקום האחרי‪-‬אחרון‪:‬‬
‫‪ ‬יתכנו הרבה‬
‫‪ ‬אנחנו מעניינים בישום השמטת כפולים‬
‫‪ ‬צריך‪ :‬מציאת ראשון‪ ,‬סריקה‪ ,‬קריאה‪ ,‬השמטה‪.‬‬
‫(‪END(L‬‬
‫פעולות‬
1. INSERT (x, p, L)
a1, a2,…..,ap-1, x, ap,….,an :‫ ברשימה‬p ‫אם יש‬
a1, a2,…..,an,x : p=END(L( ‫אם‬
Undefined
:‫אחרת‬
2. LOCATE(x, L)
END(L( ‫ אם לא מופיע‬.x ‫מקום ראשון של‬
3. RETRIEVE (p,L)
.L - ‫ נמצא ב‬p ‫מוגדר רק אם‬
4. DELETE(p,L)
a1, a2,…..,an a1, a2,…..,ap-1,ap+1,….,an
.L- ‫ ב‬p ‫מוגדר רק אם‬
5. NEXT(p,L), PREVIOUS(p,L)
‫מוגדר טבעי‬
6. MAKENULL(L)
7. FIRST(L)
2
‫יישום השמטת כפולים‬
Procedure PURGE (Var L:LIST)
Var
p,q: Position
{p = Current, q = Search}
begin
(1) p:= FIRST(L)
(2) while p<>END[L] do begin
(3)
q:= NEXT(p,L)
(4)
while q<>END(L) do
(5)
if same (RET(p,L), RET(q,L))
(6)
then DELETE(q,L)
(7)
else
(8)
q:= NEXT(q,L)
‫ אינו מקודם כי הרשימה התכווצה‬q
(9)
end ;
(10)
p:= NEXT(p,L)
end;
end; {PURGE}
3
‫יישומים של מבנה הנתונים‬
)‫ (סמנים‬,‫ רשימה מקושרת‬,‫מערך‬
‫יישום במערך‬
1st element
2nd “
last
‫רשימה‬
Last element
‫ריק‬
Maxlength
Const
maxlength = 99
type
LIST = record
elements: array[1..maxlength] of element type;
last: integer
end;
Position: integer;
function END(var L:LIST): Position
begin
return(L.Last+1)
end;
4
‫יישום ברשימה מקושרת (רגילה)‬
‫‪a2‬‬
‫‪an‬‬
‫‪a1‬‬
‫‪header‬‬
‫‪LIST‬‬
‫‪POS3‬‬
‫)‪POS.END(L‬‬
‫‪ ‬כל תא מורכב מ‪:‬‬
‫ ערך האיבר‬‫‪ -‬מצביע לאיבר הבא‬
‫‪ ‬מימוש עם מצביעים‬
‫‪5‬‬
‫‪POS2‬‬
‫‪POS1‬‬
:‫הגדרת הרשימה‬
type
celltype = record
element: elementtype;
next:celltype;
end
LIST = celltype
Position = celltype
6
: ‫בצוע לא יעיל‬
END[L]
)‫(צריך לרוץ על כל הרשימה‬
Function END (L:LIST) : position ;
{returns a pointer to the last cell of L }
Var
q: position
begin
q:= L ;
while q . next < > nil do
q:= q  . next ;
return (q) ;
end ; (END)
7
‫יישום רשימה באמצעות סמנים‬
‫)‪(CURSORS‬‬
‫• שימוש באינדקסים (בתוך מערך) במקום מצביעים‪.‬‬
‫‪1‬‬
‫‪H‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪L‬‬
‫‪5‬‬
‫‪6‬‬
‫‪7‬‬
‫‪8‬‬
‫‪9‬‬
‫‪next‬‬
‫‪element‬‬
‫• מאחסנים כמה רשימות ( ‪ +‬רשימת פנויים)‬
‫• אחרון מצביע על ‪.0‬‬
‫‪8‬‬
‫• ריקה ‪ -‬כששם האחרון מצביע על ‪.0‬‬
‫‪10‬‬
‫‪R‬‬
:‫דוגמה‬
L
M
5
1
2
4
3
s
0
4
y
0
8
o
e
-
2
0
3
10
11
6
5
6
7
Avail
9
7
n
-
1
8
9
10
11
L: y, e, s
M: n, o
Avail: 9, 10, 11, 6, 2, 4
‫הוספת והשמטת איברים‬
)‫ (מרשימת הפנויים‬DELETE
INSERT
9
‫ביצוע הזזה‬
‫שים לב‪ :‬כמו ברשימות מקושרות התייחסותנו לתא היא דרך המצביע עליו!!!!‬
‫העברת התא “‪ ”p‬לפני התא “‪:”q‬‬
‫‪3‬‬
‫‪p‬‬
‫‪4‬‬
‫‪2‬‬
‫‪q‬‬
‫‪1‬‬
‫‪temp‬‬
‫התא ש‪ p -‬מצביע עליו יזוז לפני התא ש‪ q-‬מצביע עליו‪.‬‬
‫שיטה‪( :‬לא לאבד תאים!)‬
‫א) לסמן ב ‪temp‬‬
‫‪10‬‬
‫ב) להעביר סמנים שניתן לשחרר‪.‬‬
‫השוואת יישומים‬
‫‪11‬‬
‫קריטריון‬
‫מערך‬
‫מקושרת‬
‫סמנים‬
‫גודל מקסימלי‬
‫מוגבל‬
‫“לא מוגבל”‬
‫מוגבל‪/‬בסה”כ‬
‫‪INS/DEL‬‬
‫)‪O(N‬‬
‫)‪O(1‬‬
‫)‪O(1‬‬
‫‪PREVIOUS‬‬
‫)‪O(1‬‬
‫)‪O(N‬‬
‫)‪O(N‬‬
‫‪END‬‬
‫)‪O(1‬‬
‫”)‪“O(N‬‬
‫”)‪“O(N‬‬
‫‪Position‬‬
‫ישיר‬
‫משתנה (יחסי)‬
‫משתנה (יחסי)‬
‫נצילות מקום‬
‫מבוזבז‬
‫“לא מבוזבז”‬
‫מבוזבז “פחות”‬
‫דרישת מקום‬
‫מקום * ‪1‬‬
‫מקום ‪ +‬מצביעים‬
‫מקום ‪ +‬סמנים‬
‫רשימה מקושרת כפולה‬
:‫מגבלות מקושרת רגילה‬
END(L( ‫ מציאת סוף‬.1
)‫ (ללכת הפוך‬PREVIOUS ‫ מציאת קודם‬.2
‫ מקושרת כפולה‬:‫פתרון‬
X
Y
Z
type
celltype = record
element: elementtype;
next, previous:celltype;
end ;
Position = celltype
DELETE ‫פשטות ביצוע‬
12
‫יישום התחלה וסוף‪:‬‬
‫אפשרות א’‪:‬‬
‫איבר ראשון ואחרון מצביעים על ‪.NIL‬‬
‫‪HEAD‬‬
‫אפשרות ב’‪:‬‬
‫סגירה מעגלית (הצבעה על ‪) HEAD‬‬
‫‪13‬‬
‫‪HEAD‬‬
‫השוואת רשימה כפולה לרגילה‬
‫יתרונות‬
‫• קלות בהליכה אחורנית‬
‫• קלות במציאת הסוף‬
‫• פשטות בהתייחסות למקום‬
‫חסרונות‬
‫• פי שניים מקום וזמן‪.‬‬
‫‪14‬‬
‫מבני רשימות מיוחדים‬
‫מחסנית ‪STACK‬‬
‫ניתן לגשת רק לראש‪.‬‬
‫•‪LIFO – Last In First Out‬‬
‫• דוגמה‪:‬‬
‫פעולות‪:‬‬
‫מחסנית רובה‬
‫ניירות על השולחן‬
‫)‪1. MAKE NULL (S‬‬
‫)‪2. TOP (S‬‬
‫)‪3. POP (S‬‬
‫)‪4. PUSH (S‬‬
‫)‪(TRUE | FALSE‬‬
‫‪15‬‬
‫)‪5. EMPTY (S‬‬
‫מימושים‪:‬‬
‫• כל הרשימות בהגבלת טיפול רק בהתחלה‪.‬‬
‫• רשימות מקושרות או סמנים‪ :‬בסדר‪.‬‬
‫• מערך ‪ -‬בסדר‪.‬‬
‫‪1‬‬
‫‪2‬‬
‫‪1st‬‬
‫‪3‬‬
‫‪TOP‬‬
‫‪2nd‬‬
‫‪:‬‬
‫‪MAXLENGTH‬‬
‫‪Last Element‬‬
‫‪Type‬‬
‫‪STACK = record‬‬
‫‪top: integer‬‬
‫]‪elements: array [1…MAXL] of element type‬‬
‫; ‪end‬‬
‫שימושים‪ :‬ברקורסיות‬
‫‪16‬‬
‫ישום פעולות‪ :‬פשוט‪ .‬לבצע לבד‪.‬‬
Queue
Queue‫תור‬
‫תור‬
‫• סוג מיוחד של רשימה‬
FIFO – First In First Out •
. FRONT -‫ יוצאים ב‬, REAR -‫• נכנסים ב‬
F
R
:‫פעולות‬
1) MAKENULL (Q)
2) ENQUEUE (x,Q) : INSERT (x,END (Q),Q)
3) FRONT (Q) : RET (FIRST (Q), Q)
4) DEQUEUE (Q) : DELETE (FIRST (Q), Q)
5) EMPTY (Q) : TRUE | FALSE
17
‫יישום‬
‫• כל היישומים הקודמים עובדים (רשימות)‬
‫• ליתר יעילות‪ :‬יישום מיוחד‪.‬‬
‫‪ +‬צריכים לגשת לסוף‬
‫‪ +‬יישום ברשימה מקושרת חד כיוונית‪.‬‬
‫• איבר אחד ריק (נוחיות טיפול ברשימה ריקה)‬
‫• מצביעים על התחלה וסוף‪.‬‬
‫‪TYPE‬‬
‫‪QUEUE : Record‬‬
‫‪front, rear :  celltype‬‬
‫‪18‬‬
:‫דוגמאות לפעולות‬
MAKENULL (Q)
F
R
Q
F= R
EMPTY
ENQUEUE (x,Q)
F
R
x
ENQUEUE (y,Q)
F
R
X
y
DEQUEUE (Q)
F
R
y
19
?‫יישום תור במערך‬
1
2
N
N times ENQUEUE(x,Q)
1
2
N
N-1 times DEQUEUE(Q)
1
2
N
N/2 time ENQUEUE(x,Q)
20
‫יישום תור במערך (מעגלי)‬
‫‪2‬‬
‫‪N‬‬
‫‪1‬‬
‫‪1‬‬
‫‪N‬‬
‫‪2‬‬
‫‪Q.FRONT‬‬
‫‪QUEUE‬‬
‫‪Q.REAR‬‬
‫‪ - REAR, FRONT‬נעים עם השעון‬
‫‪ - FRONT‬על ראשון‪ - REAR ,‬על אחרון‬
‫‪  F = R‬איבר בודד‬
‫‪21‬‬
‫שימו לב‪ :‬ניתן להכניס רק ‪ N-1‬איברים!!!!!!‬
‫‪F=R+1‬‬
‫‪ ‬ריק‬
‫עבור כל ‪ F‬יש רק ‪ N‬אפשרויות ל‪ R -‬ולכן ניתן לייצג רק‪:‬‬
‫‪F=R+2‬‬
‫‪ ‬מלא‬
‫‪0,1,2,……., N-1‬‬
‫שימוש מחסנית לביצוע רקורסיות‬
‫• בצוע קריאה לסברוטינה רגילה‪:‬‬
‫‪ ‬גורם במחשב לשימור המשתנים וכתובת חזרה‪ ,‬ואז קפיצה‬
‫לשגרה‪.‬‬
‫• בצוע חזרה מסברוטינה רגילה‪:‬‬
‫‪ ‬קריאת המשתנים ועדכונם וחזרה לכתובת החזרה‬
‫‪22‬‬
‫‪Subroutine B‬‬
‫‪Prog A‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫‪i =9‬‬
‫‪i = 15‬‬
‫‪.‬‬
‫‪Call B‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫‪.‬‬
‫‪return‬‬
‫‪.‬‬
‫סברוטינות רקורסיביות‬
‫עקרון דומה ‪ -‬אך הקפיצה היא לאותה שגרה‪.‬‬
‫ יכול לקפוץ הרבה פעמים (“לא חסום”)‬‫פתרון‪:‬‬
‫שמור המשתנים וכתובת החזרה בתוך ‪.STACK‬‬
‫בכל קריאה לרקורסיה‪:‬‬
‫הכנסת משתנים וכתובת ‪ PUSH(S(-‬חזרה למחסנית‬
‫בכל חזרה מרקורסיה‪:‬‬
‫הוצאת משתנים והכתובת (‪ POP(S‬מהמחסנית ועדכון‪.‬‬
‫בצוע חזרה לפי כתובת החזרה‪.‬‬
‫‪23‬‬
‫יישום רקורסיה בשפה שאין בה רקורסיה‬
‫• נבצע אותו הדבר‪ ,‬אבל בעצמנו‪.‬‬
‫• נחזיק ‪ STACK‬שבו‪:‬‬
‫‪ )1‬כל המשתנים הלוקאלים‪.‬‬
‫‪ )2‬כתובת חזרה‪.‬‬
‫‪ )3‬פרמטרי הקריאה‪ .‬ערכם מוחזרים‪.‬‬
‫(לא הכרחי)‬
‫‪24‬‬
‫)‪Function FACT(N‬‬
‫‪If N <= 1 then‬‬
‫)‪return (1‬‬
‫)‪(1‬‬
‫‪ELSE begin‬‬
‫)‪(2‬‬
‫)‪M:= FACT(N-1‬‬
‫)‪(3‬‬
‫)‪Return(N*M‬‬
‫)‪(4‬‬
‫‪(5) END‬‬
‫יישום לולאה באמצעות רקורסיה‬
‫‪While X do‬‬
‫)‬
‫( ‪SUBROUTINE WHILE‬‬
‫‪IF X then do begin‬‬
‫) ( ‪CALL WHILE‬‬
‫‪ELSE RETURN‬‬
‫‪END‬‬
‫תשומת לב‪:‬‬
‫כל המשתנים שמשתנים במשך הלולאה‬
‫וערכם הקודם משומש בלולאה הבאה‬
‫צריכים להגיע כפרמטרים או כגלובאלים‪.‬‬
‫‪25‬‬
‫‪‬‬
‫טבלאות דינאמיות‬
‫)‪(CLR 18.4 , p.367‬‬
‫• מתאים ל‪ STACK, QUEUE -‬ביישום מערך‪.‬‬
‫• יתאים גם ל ‪HASH, HEAP‬‬
‫מטפל בבעיית חוסר המקום‪ ,‬שנוצר דינאמית במבנה מבוסס מערך‪.‬‬
‫דוגמה‪ :‬מחסנית מבוססת מערך ‪ -‬מה עושים כשמתמלאת?‬
‫פתרון‪( :‬אלגוריתם)‪( :‬שיטת ההכפלה ‪)Doubling‬‬
‫‪ )1‬הקצה מקום מסויים לטבלה (פשוט‪)N2i :‬‬
‫‪ )2‬כשהמקום מתמלא והטבלה מכילה ‪ N‬אלמנטים‪:‬‬
‫א) הקצה מקום חדש לטבלה בגודל ‪2N‬‬
‫ב) העתק איברים לטבלה החדשה‪.‬‬
‫ג) שחרר טבלה ישנה‪.‬‬
‫‪26‬‬
‫סיבוכיות‬
‫‪ )1‬עבור פעולת ׂ‪)PER OPERATION) : INSERT‬‬
‫• אם אין הכפלה (‪O(1‬‬
‫• אם יש הכפלה (‪O(N‬‬
‫)‪2) AMORTIZED ANALYSIS CLR 356-363) AMORTIZED COST‬‬
‫• חשוב זמן ממוצע עבור פעולה במקרה הגרוע ביותר‪.‬‬
‫• שווה ל‪ , T(n)/n :‬כאשר (‪ T(n‬הוא סכום הפעולות על ‪ n‬איברים‪.‬‬
‫• שיטת ההתחשבנות (‪)ACCOUNTING‬‬
‫• מחשבנים לפעולה עלות מסויימת‪.‬‬
‫• עשויה להיות גבוהה או נמוכה ממה שעולה‪.‬‬
‫‪27‬‬
‫• כשהעלות המחושבת גבוהה מהעלות בפועל שומרים ‪ Credit‬לעצמים‬
‫(איברים) אחרים‪.‬‬
‫‪ Amortized Complexity )3‬של שיטת ה‪-‬‬
‫‪:Doubling‬‬
‫א) חישוב ישיר‪:‬‬
‫עלות כוללת של ‪ n‬איברים ‪:‬‬
‫• ‪ n‬הכנסות‪.‬‬
‫• העברות ‪:‬‬
‫‪1+2+4+8+ … + n‬‬
‫‪= 2n-1‬‬
‫‪‬‬
‫(‪T(n)=O(n‬‬
‫יותר מדויק ‪T(n)=3n -‬‬
‫עלות מהוונת )‪(Amortized‬‬
‫‪T(n)/n = 3‬‬
‫‪28‬‬
‫חישוב בשיטה החשבונאית (‪)accounting‬‬
‫הכנסת‬
‫איבר‬
‫‪n‬‬
‫‪n/2‬‬
‫בעת הכנסת איבר מחשבים לו עלות ‪3‬‬
‫‪ - 1‬עבור הכנסתו‪.‬‬
‫‪ - 1‬עבור העברתו בהעברה הבאה‪.‬‬
‫‪ - 1‬כ”תרומה לחבר” (אחד מה‪ ) n/2 -‬עבור העברתו בהעברה הבאה‪.‬‬
‫‪29‬‬
Comments
•
•
•
•
Single operations still expensive
Exercise on list is sqrt(n) amortized
Can work with deletions
Caution when both insertions & deletions are
allowed
30
‫עצים (‪)Trees‬‬
‫עצים ‪Trees‬‬
‫עץ = מבנה היררכי‬
‫הגדרה רקורסיבית‪:‬‬
‫‪ .1‬צומת בודד‪ .‬זהו גם שורש העץ‪.‬‬
‫‪ .2‬אם ‪ n‬הוא צומת ו ‪ T1….TK‬הינם עצים‪ ,‬ניתן לבנות עץ חדש שבו‬
‫‪ n‬השורש ו ‪ T1….TK‬הינם “תתי עצים”‪.‬‬
‫‪n‬‬
‫‪TK‬‬
‫‪...‬‬
‫‪TK‬‬
‫מושגים‪:‬‬
‫צומת =‬
‫עץ =‬
‫שורש =‬
‫תת‪-‬עץ =‬
‫‪31‬‬
‫‪T1‬‬
‫‪Node‬‬
‫‪Tree‬‬
‫‪Root‬‬
‫‪Subtree‬‬
‫‪T1‬‬
‫‪n‬‬
‫דוגמה‪ :‬פרקים וסעיפים בספר‬
‫‪book‬‬
‫‪c3‬‬
‫‪s3.1‬‬
‫‪s2.2‬‬
‫‪c2‬‬
‫‪c1‬‬
‫‪s2.1‬‬
‫‪s1.2 s1.3‬‬
‫‪s1.1‬‬
‫מושגים‪:‬‬
‫‪ - book‬הורה‪( Parent/‬אבא) של ‪c1, c2, c3‬‬
‫‪ - c1, c2‬ילדים‪ children/‬של ‪book‬‬
‫‪ - s2.1‬צאצא‪( Descendant/‬לא ישיר) של ‪book‬‬
‫‪ - n1, n2,…nk‬מסלול‪( Path/‬אם כ”א הורה של הקודם)‬
‫אורך המסלול = מס’ הקשתות‬
‫= מס’ הצמתים (פחות אחד)‬
‫צומת ללא ילדים = עלה‪Leaf/‬‬
‫‪32‬‬
‫‪ - n1‬אב קדמון‪ Ancestor/‬של ‪nk‬‬
‫‪book‬‬
‫‪c1‬‬
‫‪s1.1‬‬
‫‪s1.2‬‬
‫‪s1.3‬‬
‫‪c2‬‬
‫‪s2.1‬‬
‫‪s2.2‬‬
‫‪c3‬‬
‫‪s3.1‬‬
‫תת‪-‬עץ ‪ -‬צומת עם כל צאצאיו‬
‫גובה העץ ‪ -‬אורך המסלול הארוך ביותר מהשורש לעלה (‪)height‬‬
‫עומק צומת ‪ -‬אורך המסלול מהצומת לשורש (‪)depth‬‬
‫סדר בצמתים‬
‫בד”כ ‪ -‬משמעות לסדר הילדים‪ .‬מסדרים משמאל לימין‪.‬‬
‫‪a‬‬
‫‪b‬‬
‫‪a‬‬
‫‪C‬‬
‫‪C‬‬
‫אם הסדר לא חשוב ‪ -‬עץ לא מסודר )‪(unordered tree‬‬
‫‪33‬‬
‫‪b‬‬
‫לסריקת הצמתים בעץ‬
‫סיסטמטיות‬
‫צורות‬
‫הצמתים בעץ‬
‫ססטמיות לסריקת‬
‫צורות‬
‫‪Preorder , postorder , Inorder‬‬
‫הגדרה רקורסיבית‪:‬‬
‫• אם ‪ T‬הוא ריק ‪ -‬אזי הרשימה הריקה היא ‪)Post,IN( Preorder‬‬
‫• אם ‪ T‬היא צומת בודד (‪ )n‬אזי הרשימה הבנויה מ‪ n -‬הינה ‪)Post,In) Preorder‬‬
‫• אחרת אם ‪ T‬הוא עץ עם שורש ‪ n‬ותתי עצים ‪ T1,…,Tk‬אזי ‪:‬‬
‫‪34‬‬
‫‪: PREORDER‬‬
‫)‪n, PRE(T1(, … , PRE)TK‬‬
‫‪: POST‬‬
‫‪POST (T1(, … , POST )TK), n‬‬
‫‪: IN‬‬
‫)‪IN(T1), n , IN(T2(, … ,IN)TK‬‬
Procedure PREORDER (n: node)
(1) list n ;
(2) for each child c of n, in order from
left do:
PREORDER (C)
end ;
.‫ בבית‬POSORDER, INORDER ‫להשלים כתיבת‬
1
:‫דוגמה‬
2
4
3
7
5
8
6
1,2,3,4,5,6,7,8
: PRE
3,2,5,4,6,1,7,8
: IN
3,5,6,4,2,7,8,1
: POST
35
‫שיטה למספור‬
‫הקף העץ בכיוון הפוך לשעון‪:‬‬
‫‪1‬‬
‫‪2‬‬
‫‪4‬‬
‫‪3‬‬
‫‪8‬‬
‫‪6‬‬
‫‪ :PRE‬סמן צומת בפעם הראשונה‪.‬‬
‫‪ : IN‬סמן עלה בפעם הראשונה‪.‬‬
‫סמן צומת פנימי בפעם השניה‪.‬‬
‫‪ :POST‬סמן צומת בפעם האחרונה‪.‬‬
‫‪36‬‬
‫‪5‬‬
‫עצים מסומנים ועצי ביטויים‬
‫)‪(Labeled Trees, Expression Trees‬‬
‫עצים מסומנים‪ :‬מסמנים את הצומת בסימון כלשהוא‪.‬‬
‫עצי ביטויים‪ :‬העץ מייצג ביטוי מתמטי‪.‬‬
‫דוגמה‪:‬‬
‫)‪= (a+b)*(c+d‬‬
‫*‬
‫‪+‬‬
‫‪n3‬‬
‫‪d‬‬
‫‪n7‬‬
‫‪c‬‬
‫‪n6‬‬
‫‪n1‬‬
‫‪+‬‬
‫‪n2‬‬
‫‪b‬‬
‫‪n5‬‬
‫חוקיות הביטוי בעץ ביטויים‪:‬‬
‫‪ .1‬כל עלה מסומן באופרנד‪.‬‬
‫‪ .2‬צומת פנימי מסומן בפעולה (אופרטור)‬
‫בינארי ו‪ E1,E2 -‬הינם ערכי הביטויים‬
‫ואם האופרטור‬
‫‪E1‬‬
‫המבוטאים ע”י תתי העץ אזי הביטוי הוא‪E2 :‬‬
‫‪ .3‬אופרטור אונרי ‪ -‬ילד יחידי‪.‬‬
‫‪37‬‬
‫‪a‬‬
‫‪n4‬‬
‫סדר הסריקה של עצי ביטוי קובע יצוג שונה של הביטוי ‪-‬‬
‫‪ - Inorder .1‬היצוג הרגיל‬
‫‪ ( Postorder .2‬פולני)‬
‫(‪)a+b)*(c+d‬‬
‫‪ab + cd + ‬‬
‫(מחשבוני ‪)HP‬‬
‫(אין כפל משמעות !!)‬
‫שימוש במספור לאינפורמציה שושלת‬
‫‪112‬‬
‫אם ‪: POST‬‬
‫)‪Y= desc(x‬‬
‫‪X‬‬
‫‪50‬‬
‫צמתים‬
‫‪y‬‬
‫‪63-112‬‬
‫‪38‬‬
‫)‪Post(x) - #desc(x) <= Post(y) <= Post(x‬‬
‫מבנה נתונים אבסטרקטי של עץ‬
‫פעולות שיעניינו אותנו‪:‬‬
‫‪ - PARENT (N, T) .1‬החזר את אבא של ‪ n‬ב ‪.T‬‬
‫אם ‪ n‬הוא השורש החזר ‪.Nil‬‬
‫‪ - LEFTMOST_CHILD(n, T) .2‬החזר הבן השמאלי ביותר של ‪ n‬בעץ ‪.T‬‬
‫‪ Nil‬אם ‪ n‬עלה‪.‬‬
‫‪RIGHT_SIBLING(n, T) 3.‬‬
‫אח ימני של ‪ n‬ב ‪ Nil. T‬אם אין‪.‬‬
‫‪ - LABEL(n, T) .4‬סימון ‪ n‬ב ‪.T‬‬
‫(לא נדרש תמיד)‪.‬‬
‫‪ - CREATi(r, T1,…Ti( .5‬יוצר עץ חדש עם שורש ‪ r‬שבו‪:‬‬
‫א) ‪ r‬השורש מסומן ב ‪U‬‬
‫ב) ל ‪ r‬יש ‪ i‬בנים‪ i ,‬תתי עצים‪T1,…Ti .‬‬
‫‪39‬‬
‫מחזיר‬
‫עץ עם שורש ‪.r‬‬
‫‪i=0‬‬
‫‪ r‬גם שורש וגם עלה‪.‬‬
.‫ אם ריק‬Nil ‫ החזרת השורש או‬- ROOT(T) .6
.T ‫ יוצר את העץ הריק‬- MAKENULL(T) .7
ADT ‫ בעזרת ה‬PREORDER ‫ כתיבת‬:‫דוגמה‬
Procedure PREORDER (n: node)
{list the descendants of n in PREORDER}
var c: node;
Begin
print (LABEL (n, T))
c := LEFTMOST_CHILD(n, T);
while c <> Nil do begin
PREORDER(c);
c := RIGHT_SIBLING(c, T)
end;
end; {PREORDER}
40
‫כתיבה לא רקורסיבית של ‪PREORDER‬‬
‫• נלך במורד העץ שמאלה ככל שנוכל‬
‫•כשלא ניתן נעבור לאח הימני של הצומת האחרון‬
‫אם אין ‪ -‬נעלה למעלה ונזוז לאחיו הימני‬
‫‪1‬‬
‫‪2‬‬
‫‪9‬‬
‫‪8‬‬
‫‪3‬‬
‫‪7‬‬
‫‪6‬‬
‫‪4‬‬
‫‪5‬‬
‫בצוע וישום‪:‬‬
‫נחזיק מחסנית ובה נאחסן בכל רגע את המסלול מהשורש עד לצומת שבה אנו מבקרים‪.‬‬
‫מחסנית ‪ ‬רקורסיה‬
‫‪41‬‬
Procedure NPREORDER(T: TREE);
{nonrecursive preorder traversal of tree T}
var
m:node; {a temporary}
S:STACK; {stack of nodes holding path from the
root to the parent TOP(S) of the current node m}
begin
{initialize}
MAKENULL(S);
m:= ROOT(T);
while true do
if m < > NULL then begin
print (LABEL(m, T));
PUSH(m, S);
{explore leftmost child of m}
m:= LEFTMOST_CHILD(m, T);
end
else begin
{exploration of path on stack is now complete}
if EMPTY(S) then
return;
{explore right sibling of node on top of stack}
m:= RIGHT_SIBLING(TOP(S), T);
POP(S);
end
end; {NPREORDER}
42
‫‪X96‬‬
‫‪3.43‬‬
‫מימוש עצים‬
‫יצוג עץ באמצעות מערך (מערך הורים) ‪:‬‬
‫• יצוג פשטני התומך ב‪PARENT -‬‬
‫• מערך ]‪ A[i‬שבו ]‪ A[i‬הוא סמן (‪ )Cursor‬להורה של ‪: i‬‬
‫• בעיה לתמוך ב‪LEFTMOST_CHILD -‬‬
‫‪RIGHT_SIBLING‬‬
‫• ניתן לייצג ‪( LABEL‬במערך נוסף)‬
‫‪a‬‬
‫דוגמה‪:‬‬
‫‪1‬‬
‫‪e‬‬
‫‪0 1 1 2 2‬‬
‫‪T:‬‬
‫‪b‬‬
‫‪2‬‬
‫‪3‬‬
‫‪c‬‬
‫‪1 2 3 4 5‬‬
‫‪d‬‬
‫‪5‬‬
‫‪a b c d e‬‬
‫‪LABEL‬‬
‫‪1 2 3 4 5‬‬
‫בעיית ‪ LCHILD‬ו‪ :RSIBLING -‬לא מוגדר סדר מספיק בייצוג הנוכחי !‬
‫נניח‪ :‬נשכן בנים אחרי האב ומשמאל לימין ‪.‬‬
‫‪43‬‬
‫‪4‬‬
X96
3.44
Function R_SIBLING (n:node ; T:Tree)
node ;
{return R_SIB of n in T (o if none) }
var
i,parent: node ;
begin
parent:= T(n)
for i:= n+1 to max nodes do
if T(i) = parent then
return (i) ;
return (0) ;
end ;
R_SIBLING ‫ ישום‬- ‫אזי‬
DATA TYPES
type
node = integer
TREE = array [ 1 … max nodes ]
of node ;
44
‫ייצוג עצים על‪-‬ידי רשימות בנים‬
‫ לכל צומת ‪ -‬רשימת בניו‬‫ כל מבנה רשימה ‪ -‬קביל‪ ,‬אבל מספר בנים משתנה‬‫‪ ‬עדיפות לרשימה מקושרת‪.‬‬
‫דוגמה‪:‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪9‬‬
‫‪10‬‬
‫‪5‬‬
‫‪8‬‬
‫‪7‬‬
‫‪4‬‬
‫‪6‬‬
‫‪HEADER‬‬
‫‪8‬‬
‫‪45‬‬
‫‪3‬‬
‫‪5‬‬
‫‪10‬‬
‫‪7‬‬
‫‪2‬‬
‫‪4‬‬
‫‪9‬‬
‫‪6‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫‪6‬‬
‫‪7‬‬
‫‪8‬‬
‫‪9‬‬
‫‪10‬‬
‫מבנה הנתונים המופשט‬
Type
node = integer
list =
position =
Tree = record
header: array[1..MAXNODES] of list
labels: array[1..MAXNODES] of label type
end;
:L-CHILD ‫בצוע‬
Function L-CHILD(n: node, T: Tree): node;
var
L:list;
begin
L: T.header[n]
if empty[L] then
return(0);
else
return(RETRIEVE(FIRST(L), L))
end;
46
‫יישום ספציפי של הרשימה באמצעות מערך הסמנים‬
‫‪4‬‬
‫אח‬
‫‪6‬‬
‫‪2‬‬
‫‪3‬‬
‫‪node next‬‬
‫‪cell space‬‬
‫(רשימת אח ימני)‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫‪6‬‬
‫‪7‬‬
‫‪8‬‬
‫‪9‬‬
‫‪4‬‬
‫‪2‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪Header‬‬
‫(בן שמאלי)‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫יתרונות וחסרונות‪:‬‬
‫• ניתן למצוא ילד שמאלי ואח במהירות‪.‬‬
‫•קשה למצוא הורים‪.‬‬
‫• קשה לחבר עצים (‪CREATEi(V,...‬‬
‫אמנם כל התאים ב ‪ cellspace‬משותפים אבל לכל עץ ‪ header‬משלו‪.‬‬
‫‪47‬‬
‫פתרון פשוט‬
‫כל האינפורמציה שהיתה היא‪:‬‬
‫• בן ראשון (שמאלי)‬
‫• אח ראשון (ימני)‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫‪6‬‬
‫‪7‬‬
‫‪8‬‬
‫‪9‬‬
‫‪10‬‬
‫‪11‬‬
‫‪D‬‬
‫‪11‬‬
‫‪B‬‬
‫‪A‬‬
‫‪C‬‬
‫‪Right sibling‬‬
‫‪5‬‬
‫‪2‬‬
‫‪label‬‬
‫‪Left child‬‬
‫הכל פשוט פרט ל ‪Parent‬‬
‫פתרונות‪:‬‬
‫‪ )1‬הוסף שדה רביעי (עלות מקום‪ ,‬יעילות זמן)‬
‫‪ )2‬אח ימני של האח הימני ביותר‬
‫‪48‬‬
‫‪A‬‬
‫‪C‬‬
‫‪D‬‬
‫‪B‬‬
‫איך מבצעים (‪?CREATE2(V,T1,T2‬‬
‫‪ )1‬צור צומת חדשה ‪ V‬ותן לה סימון מתאים‬
‫(בד”כ נשמור רשימת ‪ available‬לתאים פנויים)‬
‫‪V.left = T1 (2‬‬
‫‪T1.right = T2 (3‬‬
‫‪49‬‬
‫יישום עצים שרירותיים‬
‫כל צומת מכילה ‪ 3‬מצביעים‪:‬‬
‫ בן שמאלי‬‫ אח ימני‬‫(אופציונלי)‬
‫ הורה‬‫‪a‬‬
‫‪c‬‬
‫‪d‬‬
‫‪g‬‬
‫ניתן לחשב באמצעות מצביעים‬
‫‪50‬‬
‫‪b‬‬
‫‪f‬‬
‫‪e‬‬
X96
3.49
)!‫יישום ברשימת מצביעים (זהה‬
A
B
C
lchild
D
label
rsibling
A
C
B
D
‫שידוך עצים ברשימת מצביעים‬
T1
1) temp:= avail
?
3
6
T2
2) avail:=cellspace[avail].R
3) cellspace[temp].LC:=T1
?
4) cellspace[temp].label:=v
2
Avail
temp
v
1
4
0
5
5) cellspace[temp].RS:=0
6) cellspace[T1].RS:=T2
51
‫עצים בינאריים‬
‫‪ -‬עץ ריק או לכל צומת יש תת קבוצה של {ילד ימני‪ ,‬ילד שמאלי}‬
‫דוגמא‪:‬‬
‫‪1‬‬
‫‪2‬‬
‫‪5‬‬
‫‪6‬‬
‫‪1‬‬
‫‪4‬‬
‫‪7‬‬
‫‪5‬‬
‫‪6‬‬
‫‪3‬‬
‫‪7‬‬
‫הנ”ל‪:‬‬
‫ זהים בעצים מסודרים‬‫ שונים בעצים בינאריים‬‫סדרי סקירה‪:‬‬
‫‪ - Pre, Post‬יתנו תוצאה זהה למה שיתנו בעץ סדור‪.‬‬
‫‪ - In‬לא בהכרח זהה!‬
‫‪52‬‬
‫‪2‬‬
‫‪4‬‬
‫‪3‬‬
‫ייצוג‪:‬‬
‫‪ )1‬מערך של רשומות‬
‫‪Var‬‬
‫‪cellspace: array[1…maxnodes] of record‬‬
‫‪leftchild: integer‬‬
‫‪rightchild: integer‬‬
‫;‪end‬‬
‫דוגמא‪ :‬קוד ‪Huffman‬‬
‫ נתון סט של אותיות ‪a, b, c, d, e‬‬‫ מופיעות בשפה בהסתברויות שונות‪:‬‬‫‪0.12, 0.4, 0.15, 0.08, 0.25‬‬
‫ רוצים לקודד ל ‪ 0/1‬בצורה יעילה‬‫אפשרות א’ ‪ -‬שלשות‪:‬‬
‫‪000‬‬
‫‪001‬‬
‫‪010‬‬
‫‪011‬‬
‫‪100‬‬
‫‪a‬‬
‫‪b‬‬
‫‪c‬‬
‫‪d‬‬
‫‪e‬‬
‫אורך ממוצע‪3 :‬‬
‫‪53‬‬
‫אפשרות ב’ ‪ -‬ייצוג קצר לאותיות שכיחות‬
‫ייצוג ארוך לאותיות נדירות‬
‫שימוש בקוד פרפיקסי =‬
‫אף אות אינה פרפיקס של אחרת‬
‫דוגמא‪:‬‬
‫‪000‬‬
‫‪11‬‬
‫‪01‬‬
‫‪001‬‬
‫‪10‬‬
‫אורך ממוצע‪:‬‬
‫‪3(0.12+0.15)+2(0.4+0.08+2.5)=2.27‬‬
‫בעיה‪ :‬בהינתן אותיות והסתברויות מצא קוד פרפיקסי יעיל‪.‬‬
‫‪a‬‬
‫‪b‬‬
‫‪c‬‬
‫‪d‬‬
‫‪e‬‬
‫יצוג קוד פרפיקסי בעזרת עץ בינארי‪:‬‬
‫ אותיות בעלים‬‫ ‪ 0/1‬בענפים (שמאל=‪ ,0‬ימין=‪)1‬‬‫‪ -‬אותיות בעלים‬
‫מבטיח פרפיקס‬
‫ישום ‪Huffman‬‬
‫ יהיה לנו יער (אוסף עצים)‬‫ העלים = אותיות‬‫ מסלולים = סיומות של מילים‬‫ לכל עץ משקל = סכום ההסתברויות‬‫‪54‬‬
‫‪-‬כל פעם שדך את העצים הקלים ביותר‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
‫‪0‬‬
‫‪0‬‬
‫‪1‬‬
‫‪1‬‬
‫‪0‬‬
:‫דוגמא‬
0.12
a
0.4
b
.
0.15
c
.
.
0.08
d
0.25
e
.
.
0.2
X1
X2
0.35
X3
0.6
1.0X4
X4
:‫חישוב אורך ממוצע‬
X3
b 0.4
X2
e 0.25
X1
c 0.15
a 0.12
d 0.08
a
d
c
e
b
0.12*4
0.08*4
0.15*3
0.25*2
0.4*1
2.15
55
‫מבנה נתונים‬
‫‪ )1‬לשמור את מבנה העצים‪ :‬לכל צומת אבא ובנים‪.‬‬
‫‪Parent‬‬
‫‪ )2‬לכל עץ משקלו ושורשו‪.‬‬
‫‪Root‬‬
‫‪56‬‬
‫‪Weight‬‬
‫‪Forest‬‬
‫‪Rchild‬‬
‫‪Lchild‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫‪4‬‬
‫‪5‬‬
‫‪6‬‬
‫‪7‬‬
‫‪ )3‬שמירת האלף‪-‬בית (סטאטי)‬
‫דינמיות‬
‫‪1‬‬
‫‪0.12‬‬
‫‪a‬‬
‫‪2‬‬
‫‪0.4‬‬
‫‪b‬‬
‫‪3‬‬
‫‪0.15‬‬
‫‪c‬‬
‫‪4‬‬
‫‪0.08‬‬
‫‪d‬‬
‫‪5‬‬
‫‪0.25‬‬
‫‪e‬‬
‫‪ALPHABET‬‬
‫ בכל פעולה מוסיפים צומת ‪ -‬מורידים עץ‪.‬‬‫ הוספת צומת ‪ -‬בסוף של ‪TREE‬‬‫ הורדת עץ‪ :‬מ ‪ T1‬ו ‪ T2‬יוצרים ‪.T‬‬‫נבצע ‪T2+T1‬‬
‫‪T1‬‬
‫‪ -‬זריקת ‪ :T2‬החלף מקומות בין ‪ T2‬ו ‪ TLAST‬והקטן האינדקס ל ‪LAST‬‬
‫‪57‬‬
‫ממוש עצים בינאריים‬
‫ניתן לממש באמצעות פוינטרים‪:‬‬
‫‪type‬‬
‫‪node = record‬‬
‫‪lchild : node‬‬
‫‪rchild : node‬‬
‫‪parent: node‬‬
‫‪end‬‬
‫אחסון עצים בינאריים במערך‪:‬‬
‫• טוב למבנה סטאטי‬
‫• אם צומת ‪ x‬בתא ‪: i‬‬
‫אז‬
‫‪:‬‬
‫‪Ichild(x): 2i‬‬
‫‪rchild(x): 2i+1‬‬
‫• טוב במיוחד אם העץ מושלם (או שתילת עצים אחרים בחורים)‪.‬‬
‫‪58‬‬
‫‪X96‬‬
‫‪3.48‬‬
‫איך מבצעים (‪:CREATEz (v,T1,Tz‬‬
‫‪ )1‬צור רשימה חדשה ‪ V‬ותן לה סימון מתאים‬
‫(בד”כ נשמור רשימת ‪ Avail‬לתאים פנויים)‬
‫‪59‬‬
‫‪(2‬‬
‫‪V. left = T1‬‬
‫‪(3‬‬
‫‪V.right = T2‬‬