חוברת מבני נתונים ואלגוריתמים

‫מבני נתונים‬
‫ואלגוריתמים‬
‫‪0512.2510‬‬
‫בהצלחה‪,‬‬
‫ועד הנדסה‬
‫ת"ז‪:‬‬
‫אוניברסיטת תל‪-‬אביב‬
‫הפקולטה להנדסה‬
‫מועד א' סמסטר א‪ ,‬תשע"ה במבני נתונים ואלגוריתמים‬
‫זמן המבחן‪ :‬שלוש שעות‬
‫תאריך‪11.2.15 :‬‬
‫מרצה‪ :‬דנה רון‬
‫הנחיות‪:‬‬
‫‪‬‬
‫מותר להשתמש בארבעה דפי עזר‪ .‬אין להשתמש בשום סוג של מחשב‪.‬‬
‫‪‬‬
‫המבחן כולל ‪ 4‬שאלות‪ .‬הניקוד על כל שאלה מופיע בסוגריים‪.‬‬
‫כתבו את תשובותיכם על גבי טופס המבחן במקום המוקצה לכך‪ .‬מומלץ מאוד לכתוב תחילה את‬
‫‪‬‬
‫התשובה במחברת הטיוטה שקיבלתם ורק אחר כך להעתיק אותה‪ ,‬בצורה ברורה וקריאה‪ ,‬לטופס המבחן‪.‬‬
‫נמקו בקצרה אך בבהירות את כל טענותיכם‪ .‬טענה ללא נימוק לא תתקבל‪.‬‬
‫‪ ‬מותר להשתמש במשפטים ואלגוריתמים שנלמדו בשיעורים ובתרגולים או שהופיעו בתרגילי הבית‪.‬‬
‫במקרה כזה ניתן לצטט את מה שנלמד ללא צורך בהוכחה‪ .‬לעומת זאת‪ ,‬אם אתם משתמשים בגרסה שונה‬
‫מעט של אלגוריתם או ניתוח כלשהו יש להסביר במדויק מה ההבדלים‪.‬‬
‫‪‬‬
‫במבחן זה ‪ 8‬עמודים (כולל עמוד זה)‪ .‬אנא ודאו שכולם ברשותכם‪.‬‬
‫‪‬‬
‫אל תשכחו לרשום מספר ת"ז במקום המסומן‪.‬‬
‫ב ה צ ל ח ה!‬
‫‪.3‬‬
‫‪.4‬‬
‫‪.1‬‬
‫א)‬
‫א)‬
‫א)‬
‫ב)‬
‫ב)‬
‫ב)‬
‫‪.2‬‬
‫ג)‬
‫‪1‬‬
‫שאלה ‪ 30( 1‬נק')‬
‫נתבונן באלגוריתם הבא המקבל כקלט מערך ‪ A‬בגודל ‪ ,n‬שני אינדקסים ‪ p,r‬כך ש ‪ 1  p , r  n‬ופרמטר ‪,k‬‬
‫‪ .2kn1/2‬הפרוצדורה ‪ Proc‬גם היא מקבלת אותם פרמטרים‪ ,‬וזמן ריצתה ) ‪( (s (log k)2‬עבור ‪ ,)s=r-p+1‬לכל‬
‫מערך קלט‪.‬‬
‫)‪Alg(A,p,r,k‬‬
‫{‬
‫‪s := r-p+1‬‬
‫)‪if (s  1‬‬
‫‪return‬‬
‫‪t := s/k‬‬
‫)‪for (j = 0 to k-1‬‬
‫)‪Alg(A,p+jt,p+(j+1)t-1,k‬‬
‫)‪Proc(A,p,r,k‬‬
‫}‬
‫א‪ 15( .‬נק') מהו זמן הריצה של הפרוצדורה ‪ Alg‬כפונקציה של ‪ n‬ו ‪ k‬כאשר היא נקראת עם ‪ ?p=1, r=n‬כלומר‪ ,‬מהי‬
‫)‪ g(n,k‬כך שזמן הריצה של ‪ Alg‬הוא ))‪ ?(g(n,k‬מותר להניח ש ‪ n‬היא חזקה של ‪ .k‬שימו לב שלא ניתן להניח ש ‪k‬‬
‫הוא קבוע (לדוגמה‪ ,‬ייתכן ו ‪ .)k= n1/4‬נזכיר כי ‪.logab = log2b/log2a‬‬
‫עליכם לפעול לפי ההנחיה הבאה‪ :‬תארו את עץ הרקורסיה של האלגוריתם; כמה קדקודים יש בכל רמה? מה גובה‬
‫העץ? מה תרומת הרמה ה ‪ i‬בעץ לזמן הריצה?‬
‫_____________________________________________________________________________________________‬
‫_______ ______________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫____________________________________________ _________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_______________ ______________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪2‬‬
‫ב‪ 15( .‬נק') נשנה את האלגוריתם באופן הבא (כמקודם‪ A ,‬הוא מערך בגודל ‪ ,n‬ו ‪:)2kn1/2‬‬
‫)‪Alg2(A,p,r,k‬‬
‫{‬
‫‪s := r-p+1‬‬
‫)‪if (s < k‬‬
‫‪return‬‬
‫)‪IA := Proc2(A,p,r,k‬‬
‫{ )‪for (j = 1 to k‬‬
‫)‪Alg2(A,IA[j],IA[j+1]-1,k‬‬
‫}‬
‫)‪Proc(A,p,r,k‬‬
‫}‬
‫כאשר ‪ Proc2‬מחזירה מערך ‪ IA‬בגודל ‪ k+1‬כך ש ‪ p=IA[1]<IA[2]<…<IA[k+1]=r +1‬וזמן ריצתה גם הוא‬
‫) ‪ (s (log k)2‬עבור ‪ ,s=r-p+1‬לכל מערך קלט‪ .‬לדוגמה‪ ,‬עבור ‪ p=1, r=9 ,n=9‬ו ‪ ,k=3‬ייתכן ו ]‪.IA=[1,2,5,10‬‬
‫תנו חסם עליון טוב ככל האפשר על זמן הריצה של ‪ Alg2‬כפונקציה של ‪ n‬ו ‪ k‬כאשר היא נקראת עם ‪.p=1, r=n‬‬
‫עליכם לפעול לפי ההנחיה הבאה‪ :‬תנו חסם עליון טוב ככל האפשר על מספר הרמות בעץ הרקורסיה‪ .‬כלומר‪ ,‬עליכם‬
‫להצדיק מדוע מספר הרמות חסום מלמעלה על ידי מה שאתם טוענים עבור כל מערך קלט ‪ .A‬כמו כן תנו חסם עליון על‬
‫התרומה של כל רמה‪ .‬לא ניתן לטעון שעץ מסוים הוא הגרוע ביותר בלי להצדיק מדוע אכן כל עץ אחר נותן זמן ריצה‬
‫גדול יותר (או שווה)‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫______________________________ _______________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_ ____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫______________________________________ _______________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪3‬‬
‫שאלה ‪ 20( 2‬נק')‬
‫בשאלה זו נדון במבנה נתונים עבור עץ בינארי בו כל קדקוד הוא רשומה עם השדות הבאים‪ VAL :‬ובו הערך בקדקוד‬
‫(מספר)‪ PAR ,‬שהוא מצביע להורה של הקדקוד‪ ,LC ,‬שהוא מצביע לילד השמאלי של הקדקוד‪ ,‬ו ‪ ,RC‬שהוא מצביע‬
‫לילד הימני של הקדקוד (אם אין לקדקוד הורה‪/‬ילד ימני ‪ /‬ילד שמאלי אז המצביע המתאים הוא ‪ .)NULL‬כמו כן יש‬
‫שדה נוסף‪ SIZE ,‬שמכיל את מספר הקדקודים בתת העץ שקדקוד זה הוא השורש שלו (כולל הקדקוד עצמו)‪.‬‬
‫לדוגמה‪ ,‬עבור‪:‬‬
‫הגודל של תתי העצים ששורשיהם ‪ 2‬ו ‪ 10‬הוא ‪ ,1‬של ‪ 7‬הוא ‪ ,2‬ושל ‪ 5‬הוא ‪4‬‬
‫‪5‬‬
‫‪7‬‬
‫‪2‬‬
‫‪10‬‬
‫יהי ‪ T‬עץ חיפוש בינארי עם ‪ n‬קדקודים המיוצג על ידי מבנה הנתונים שתואר למעלה‪ .‬הניחו כי המספרים בעץ‬
‫(בשדה ‪ )VAL‬שונים זה מזה‪ .‬כתבו פסאודו‪-‬קוד עבור פרוצדורה רקורסיבית‪ ,‬המקבלת כקלט מצביע לשורש של העץ‬
‫‪ T‬ומספר ‪ ,x‬כך שאם ‪ x‬נמצא בעץ היא מחזירה את מיקומו של ‪ x‬בסדר ממוין מקטן לגדול של המספרים בעץ (כלומר‪,‬‬
‫אם הוא הכי קטן‪ ,‬היא מחזירה ‪ ,1‬אם הוא השני הכי קטן‪ ,‬היא מחזירה ‪ ,2‬וכך הלאה) ‪ ,‬ואם הוא לא נמצא בעץ אז היא‬
‫מחזירה ‪ .NOT-FOUND‬לדוגמה‪ ,‬עבור העץ למעלה ו ‪ ,x = 7‬הפלט הוא‪.3 :‬‬
‫הפרוצדורה יכולה לקבל פרמטר נוסף‪/‬פרמטרים נוספים ויש לכתוב במפורש מה ערכו‪/‬ם בקריאה הראשונית‬
‫לפרוצדורה‪ .‬זמן הריצה של הפרוצדורה צריך להיות לכל היותר ליניארי בגובה העץ‪.‬‬
‫הוסיפו הסבר קצר המבהיר את פעולת הפרוצדורה‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫___________________________________ __________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫______ _______________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫___________________________________________ __________________________________________________‬
‫‪4‬‬
‫שאלה ‪ 20( 3‬נק')‬
‫נתונה רשת זרימה )‪ N=(G,s,t,c‬כאשר )‪ G=(V,E‬הוא גרף מכוון‪ sV ,‬הוא קדקוד המקור‪ tV ,‬הוא קדקוד היעד‪ ,‬ו‬
‫‪ c‬היא פונקציית קיבול על הקשתות‪ .‬לכל קשת ‪ c(e) ,eE‬מספר שלם וחיובי ממש (אם אין קשת מ ‪ u‬ל ‪ v‬אז‬
‫‪ .)c(u,v)=0‬נזכיר שעבור פונקציית זרימה ‪ f‬אנו מסמנים את ערכה ב |‪ .|f‬נתון ש *‪ f‬היא פונקציית זרימה עם ערך‬
‫מרבי עבור ‪.N‬‬
‫‪-e‬‬
‫עבור קשת ‪ e‬ב ‪ , E‬נסמן ב ‪ N‬את הרשת המתקבלת מ ‪ N‬כאשר מסירים את ‪ e‬מ ‪( E‬כך שמורידים את הקיבול שלה‬
‫ל ‪ ,)0‬ומלבד זאת לא משנים דבר ברשת‪ .‬נסמן ב ‪ f*-e‬פונקציית זרימה עם ערך מרבי ב ‪ .N-e‬נאמר ש ‪ e‬היא קשת‬
‫הכי זניחה אם |‪ |f*| - |f*-e‬מינימאלי ביחס לכל הקשתות בגרף (כאשר ייתכן ויש יותר מקשת אחת כזו)‪.‬‬
‫עבור כל אחת משלוש הטענות הבאות‪ ,‬ענו האם היא נכונה תמיד (כלומר‪ ,‬לכל רשת ‪ )N‬או שאינה נכונה‪ .‬אם היא אינה‬
‫נכונה‪ ,‬תנו דוגמה נגדית‪ ,‬ואם היא נכונה נמקו במדויק מדוע (בהתבסס על מה שלמדנו בכיתה)‪.‬‬
‫א‪ 7( .‬נק') אם ‪ f*(e) = 0‬אז ‪ e‬היא קשת הכי זניחה‪.‬‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫ב‪ 7( .‬נק') אם })’‪ f*(e) = mine’E {f*(e‬אז ‪ e‬היא קשת הכי זניחה‪.‬‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫ג‪ 6( .‬נק') אם ‪ e‬שייכת לחתך עם קיבול מינימאלי ב ‪ N‬ובו לפחות שתי קשתות אז בהכרח היא אינה קשת הכי זניחה‪.‬‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫‪5‬‬
‫שאלה ‪ 30( 4‬נק')‬
‫נתונות שתי מחרוזות ‪ ‬ו ‪ ‬מעל אותו א"ב ‪ ‬כאשר ‪ n‬הוא האורך של ‪ ,‬ו ‪ m‬הוא האורך של ‪.‬‬
‫המחרוזות מיוצגות על ידי מערכים כך ש ]‪ [j‬הוא התו ה ‪ j‬במחרוזת ‪.‬‬
‫לדוגמה‪:‬‬
‫‪...‬‬
‫‪n‬‬
‫‪d‬‬
‫‪e‬‬
‫‪m‬‬
‫‪e‬‬
‫‪2‬‬
‫‪c‬‬
‫‪1‬‬
‫‪b‬‬
‫‪...‬‬
‫‪2‬‬
‫‪a‬‬
‫‪c‬‬
‫‪‬‬
‫‪a‬‬
‫‪1‬‬
‫‪b‬‬
‫‪‬‬
‫פונקציית התאמה }‪ h : {1,…,n}  {0,1,…,m‬מ ‪ ‬ל ‪ ‬הממפה בין חלק מהתווים ב ‪ ‬לתווים זהים ב ‪ ,‬צריכה‬
‫לקיים את התנאים הבאים‪:‬‬
‫(‪ )1‬לכל ‪ ,1  j  n‬אם ‪ ,h(j) > 0‬אז ])‪;[j] = [h(j‬‬
‫(‪ )2‬לכל ‪ ,1  j < j’  n‬אם ‪ h(j) > 0‬ו ‪ ,h(j’) > 0‬אז )’‪.h(j) < h(j‬‬
‫לדוגמה‪ ,‬עבור ‪ ‬ו‪ -‬מהדוגמה למעלה‪ ,‬הפונקציה ‪ h(1)=3, h(2)=h(3)=h(4)=0, h(5)=4‬היא פונקציית התאמה‪:‬‬
‫‪5‬‬
‫‪3‬‬
‫‪4‬‬
‫‪e‬‬
‫‪d‬‬
‫‪2‬‬
‫‪c‬‬
‫‪3‬‬
‫‪4‬‬
‫‪e‬‬
‫‪1‬‬
‫‪b‬‬
‫‪2‬‬
‫‪a‬‬
‫‪a‬‬
‫‪‬‬
‫‪1‬‬
‫‪c‬‬
‫‪b‬‬
‫‪‬‬
‫וגם ‪ h(1)=0, h(2)=1, h(3)=2, h(4)=0, h(5)=4‬היא פונקציית התאמה‪:‬‬
‫‪5‬‬
‫‪e‬‬
‫‪4‬‬
‫‪d‬‬
‫‪4‬‬
‫‪e‬‬
‫‪3‬‬
‫‪2‬‬
‫‪c‬‬
‫‪3‬‬
‫‪a‬‬
‫‪b‬‬
‫‪2‬‬
‫‪1‬‬
‫‪a‬‬
‫‪1‬‬
‫‪c‬‬
‫‪b‬‬
‫הערך של פונקציית התאמה הוא מספר האינדקסים ‪ 1jn‬כך ש ‪ .h(j)>0‬בדוגמאות שלמעלה‪ ,‬ערך הפונקציה‬
‫הראשונה ‪ 2‬וערך השנייה ‪.3‬‬
‫בהינתן שתי מחרוזות נהיה מעוניינים למצוא פונקציית התאמה עם ערך מרבי‪.‬‬
‫‪6‬‬
‫‪‬‬
‫‪‬‬
‫ראשית נרצה לחשב את הערך המרבי‪.‬‬
‫לשם כך‪ ,‬נגדיר לכל ‪ 1  j  n+1‬ו ‪ 1  k  m+1‬את )‪ V(j,k‬להיות הערך המרבי של פונקציית התאמה מ‬
‫]‪ [j,…,n‬ל ]‪( [k,…,m‬כאשר אם ‪ j=n+1‬אז ]‪ [j,…,n‬מחרוזת ריקה‪ ,‬ובאופן דומה‪ ,‬אם ‪ ,k=m+1‬אז‬
‫]‪ [k,…,m‬מחרוזת ריקה‪ ,‬כך שבמקרים אלו ערך פונקציית ההתאמה הוא ‪.)0‬‬
‫נשים לב שלכל ‪ 1  j  n‬ו ‪: 1  k  m‬‬
‫(‪ )1‬אם לא קיים ‪ k  r  m ,r‬כך ש ] ‪ ,[j] = [r‬אז ]‪;V[j][k] = V[j+1][k‬‬
‫(‪ )2‬אחרת‪ ,‬יהי ‪ r‬האינדקס המינימאלי בין ‪ k‬ל ‪ m‬המקיים ]‪ ,[j] = [r‬אז‬
‫}]‪V[j][k] = max{V[j+1][k],1+V[j+1][r+1‬‬
‫א‪ 18( .‬נק') כתבו פסאודו‪-‬קוד לאלגוריתם תכנון דינאמי שזמן ריצתו פולינומיאלי ב ‪ n‬ו ‪ ,m‬המקבל כקלט שתי‬
‫מחרוזות ‪ ‬ו ‪ ‬ואת אורכן‪ ,‬והמחזיר ערך מרבי של פונקציית התאמה מ ‪ ‬ל ‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫___________________________ __________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫מה זמן הריצה של האלגוריתם שכתבתם?‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪7‬‬
‫ב‪ 12( .‬נק') הראו‪ ,‬בעזרת כתיבת פרוצדורה נוספת‪ ,‬ואם יש צורך‪ ,‬תוספת לפסאודו‪-‬קוד שכתבתם (אשר לא משנה‬
‫אסימפטוטית את זמן הריצה של האלגוריתם)‪ ,‬כיצד ניתן לקבל פונקציית התאמה עם ערך מרבי‪ .‬כלומר‪ ,‬הפרוצדורה‬
‫הנוספת צריכה להדפיס זוגות ))‪ (1,h(1)), (2,h(2)), …, (n,h(n‬עבור פונקציה ‪ h‬עם ערך מרבי (לפי הסדר‪ ,‬משמאל‬
‫לימין)‪ .‬יש לכתוב במפורש עם אלו פרמטרים נקראת הפרוצדורה הנוספת‪ ,‬וזמן הריצה שלה צריך להיות ליניארי ב ‪.n‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫______________________________________________ _______________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_________________ ____________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪8‬‬
‫פתרון המבחן‬
‫שאלה ‪1‬‬
‫א‪ .‬לכל קדקוד פנימי בעץ הרקורסיה יש ‪ k‬ילדים‪ ,‬כך שברמה ה ‪ j‬יש ‪ kj‬קדקודים‪ ,‬כל אחד מתאים לתת מערך בגודל‬
‫‪ .s= n/kj‬כיוון שהעלים מתאימים לתת מערכי בגודל ‪ 1‬הרי שרמת העלים היא )‪ . logk(n)=log2(n)/log2(k‬התרומה‬
‫של כל קדקוד ברמה ‪ j‬שאינה רמת העלים היא ))‪ ((n/kj)log2(k‬כך שכל רמה מלבד רמת העלים תורמת סך הכל‬
‫))‪ .(n log2(k‬כל עלה תורם זמן קבוע‪ ,‬ומספר העלים ‪ n‬כך שביחד העלים תורמים )‪.(n‬‬
‫סך הכל נקבל ))‪.(n log(n) log(k‬‬
‫הערות‪ :‬כמעט כל הסטודנטים ענו נכון על סעיף זה‪.‬‬
‫ב‪ .‬גם עתה לכל קדקוד פנימי יש ‪ k‬ילדים‪ ,‬אך הקדקודים ברמה ‪ j‬אינם בהכרח מתאימים לתת מערכים בגודל זהה‪ .‬עם‬
‫זאת‪ ,‬סכום הגדלים של תתי המערכים בכל רמה הוא לכל היותר ‪ n‬כך שביחד הם עדיין תורמים לכל היותר‬
‫))‪ .O(n log2(k‬כיוון שתת המערך המתאים לכל קדקוד גודלו לכל היותר קטן ב ‪ k-1‬מהגודל של תת המערך‬
‫המתאים להורה שלו (כי כל אחד מ ‪ k-1‬האחים שלו מתאים לגודל לפחות ‪ ,)1‬ונעצרים כאשר מגיעים לתת מערכים‬
‫בגודל קטן מ ‪ ,k‬הרי שמספר הרמות בעץ הוא לכל היותר )‪ ,n/(k-1‬ונקבל חסם עליון של )‪.O(n2 log2(k)/k‬‬
‫הערות ושגיאות נפוצות‪:‬‬
‫‪ .1‬רבים מהסטודנטים נתחו לא נכון את גובה העץ‪ .‬בפרט חלק מהתשובות היו שגובה העץ הוא )‪ logk(n‬או ‪k‬‬
‫שאינם נכונות לחלוטין‪ .‬היו שציינו שגובה העץ חסום מלמעלה ע"י )‪ ,O(n‬זה כמובן נכון‪ ,‬אך לא הדוק‪ ,‬ולכן‬
‫ניתן ניקוד חלקי‪.‬‬
‫‪ .2‬חלק מהסטודנטים לא שמו לב שסכום כל רמה בעץ מלבד העלים‪ ,‬תורמת ))‪ ,O(n log2(k‬בדיוק כמו בסעיף‬
‫הראשון‪.‬‬
‫‪ .3‬חלק מהסטודנטים השאירו תשובות בצורה שאינה "נקיה" מבחינה אסימפטוטית‪ ,‬לדוגמא‬
‫‪ n  k ‬‬
‫‪2 ‬‬
‫‪ O  ‬במקום )‪ .O(n2 log2(k)/k‬לא הורדו על כך נקודות במקרה זה‪ ,‬אך שימו לב להבא‪.‬‬
‫‪ n log k ‬‬
‫‪ k ‬‬
‫‪‬‬
‫‪1‬‬
‫שאלה ‪2‬‬
‫יש הרבה צורות לפתור שאלה זו‪ ,‬להלן אחת‪.‬‬
‫הפרוצדורה נקראת עם ‪ pnode‬שהוא מצביע לשורש העץ ‪ T‬ועם ‪ .smaller= 0‬באופן כללי‪ ,‬בכל קריאה רקורסיבית‪,‬‬
‫‪ pnode‬הוא מצביע לתת עץ בו נמצא ‪( x‬אם הוא בעץ) ו ‪ smaller‬הוא מספר הערכים שידוע שהם קטנים ממש מ ‪x‬‬
‫בעץ‪ .‬הפרוצדורה עובדת בדומה ל ‪ Member‬מבחינת החיפוש אחר ‪ x‬בעץ‪ .‬הרקורסיה נעצרת או אם מגיעים ל‬
‫‪ pnode‬שהוא ‪ ,NULL‬כלומר ‪ x‬לא בעץ‪ ,‬או כאשר הערך ב ‪ pnode‬שווה ל ‪ .x‬אם ‪ x‬קטן מהערך ב ‪ pnode‬אז‬
‫ממשיכים לילד השמאלי (בלי עדכון ‪ ,smaller‬כי לא למדנו על ערכים נוספים בעץ הקטנים מ ‪ .)x‬אחרת (‪ x‬גדול או‬
‫שווה לערך בקדקוד)‪ ,‬אם ל ‪ pnode‬יש ילד שמאלי‪ ,‬אז מגדילים את ‪ smaller‬בגודל של תת העץ שלו (כי כל הערכים‬
‫בתת עץ זה קטנים מ ‪ .)x‬אם ‪ x‬שווה לערך ב ‪ pnode‬אז מחזירים את ‪ ,smaller+1‬ואם ‪ x‬גדול מהערך ב ‪ pnode‬אז‬
‫ממשיכים לילד הימני עם ‪.smaller+1‬‬
‫)‪Compute-Location(pnode,x,smaller‬‬
‫{‬
‫)‪if (pnode = NULL‬‬
‫)‪return(NOT-FOUND‬‬
‫)‪if (pnode  VAL > x‬‬
‫)‪return(pnode  LC,x,smaller‬‬
‫)‪if (pnode  LC != NULL‬‬
‫‪smaller := smaller + (pnode  LC) SIZE‬‬
‫)‪if (pnode  VAL = x‬‬
‫)‪return(smaller +1‬‬
‫)‪return(pnode  RC,x,smaller+1‬‬
‫}‬
‫הערות ושגיאות נפוצות‪:‬‬
‫‪ .1‬ניתן לפתור שאלה זו (והיו סטודנטים שעשו זאת) בלי לשלוח בקריאה הרקורסיבית פרמטר נוסף (‪,)smaller‬‬
‫אלא על ידי הוספת ‪ (pnode  LC) SIZE‬כאשר "חוזרים מהרקורסיה"‪.‬‬
‫‪ .2‬ניתן לפתור שאלה זו על בסיס האבחנה שהמיקום של שורש של עץ בתוך העץ הוא גודל העץ פחות גודל העץ‬
‫של תת הילד הימני (אם קיים כזה)‪ .‬היו סטודנטים שעשו זאת נכון אך היו כמה שלא בצעו נכון את הקריאות‬
‫הרקורסיביות ולכן קבלו תשובה שגויה‪.‬‬
‫‪ .3‬היו סטודנטים שפנו למצביעים בלי לבדוק קודם שהם אינם ‪.NULL‬‬
‫‪ .4‬היו סטודנטים שלא הוסיפו ‪ +1‬בקריאות הרקורסיביות לילד הימני ו‪/‬או כאשר מוצאים את ‪.x‬‬
‫‪ .5‬היו סטודנטים שניסו לפתור את הבעיה על בסיס ווריאציה על ‪ .INORDER‬גם אם עושים זאת נכון (ורבים‬
‫מאלו שעשו זאת לא עשו זאת נכון)‪ ,‬זמן הריצה ליניארי בגודל העץ ולא בגובהו‪ ,‬כפי שנדרש‪.‬‬
‫‪2‬‬
‫שאלה ‪3‬‬
‫א‪ .‬נכון‪ .‬לאחר שמורידים את הקשת ‪ ,e‬פונקציית הזרימה *‪ f‬היא עדיין פונקציית זרימה חוקית ב ‪ N-e‬כך שהיא‬
‫פונקציית זרימה עם ערך מרבי ב ‪( N-e‬כי ערך הזרימה המרבי אינו יכול לגדול אחרי הורדת קשת)‪ ,‬כלומר‪,‬‬
‫‪ ,|f*| = |f*-e|=0‬ולכל קשת הפרש זה הוא לכל הפחות ‪ ,0‬כך שזה המינימום האפשרי‪.‬‬
‫הערות‪:‬‬
‫כמעט כל הסטודנטים ענו נכון על סעיף זה‪.‬‬
‫ב‪ .‬לא נכון‪ .‬לדוגמה‪ (s,b) ,‬היא קשת שעליה זרימה ‪ ,1‬ואם נוריד אותה‬
‫אז ערך הזרימה ירד מ ‪ 3‬ל ‪ .2‬לעומת זאת‪ (s,a) ,‬היא קשת שעליה‬
‫זרימה ‪ ,2‬כלומר גבוהה יותר‪ ,‬אך אם נוריד אותה‪ ,‬ניתן יהיה עדיין‬
‫‪3/3‬‬
‫‪t‬‬
‫להזרים ‪ 3‬על ידי הגדלת הזרימה על )‪ (s,b‬ו )‪.(b,c‬‬
‫‪2/2‬‬
‫‪a‬‬
‫‪2/2‬‬
‫‪s‬‬
‫‪c‬‬
‫‪1/3‬‬
‫‪b‬‬
‫‪1/3‬‬
‫הערות ושגיאות נפוצות‪ :‬סטודנטים רבים ניסו להוכיח טענה זו בהתבסס על כך שכאשר מורידים קשת ‪ e‬אז ערך‬
‫הזרימה המרבית החדשה היא )‪ |f*-e|=|f*| - f*(e‬וזה כמובן שגוי‪.‬‬
‫ג‪ .‬לא נכון‪ .‬לדוגמה‪ ,‬בחתך )}‪ ,({s},{a,b,t‬שהוא חתך עם קיבול מינימאלי ‪,5‬‬
‫אם נוריד את הקשת )‪ (s,a‬אז הזרימה המרבית תרד ב ‪ ,2‬וכל קשת אחרת תגרום ‪2/2‬‬
‫לירידה של לפחות ‪( 2‬כלומר ‪ 2‬או ‪ )3‬ולכן היא כן קשת הכי זניחה (באופן‬
‫‪t‬‬
‫דומה גם )‪ (a,t‬אך לא שתי האחרות)‪.‬‬
‫‪a‬‬
‫‪2/2‬‬
‫‪s‬‬
‫‪3/3‬‬
‫‪3/3‬‬
‫‪b‬‬
‫הערות ושגיאות נפוצות‪ :‬חלק מהסטודנטים נתנו דוגמאות נגדיות לא חוקיות כגון רשתות שבהן אין שימור זרימה או‬
‫שהזרימה אינה מקסימום‪ .‬בנוסף‪ ,‬על מנת להפריך טענה יש לתת דוגמא נגדית – והיו סטודנטים שהתעלמו מדרישה זו‬
‫או שנתנו דוגמא נגדית שגויה‪.‬‬
‫‪3‬‬
4 ‫שאלה‬
)‫ ניתן להתעלם מהן בשלב זה‬,‫ (השורות המודגשות עבור הסעיף הבא‬.‫א‬
Max-Values(,,n,m)
{
for (k = 1 to m+1) /* Initialization of last row */
V[n+1][k] := 0
for(j = 1 to n) /* Initialization of last column */
{V[j][m+1] := 0; H[j][m+1]:=0 }
for (j = n downto 1) { /* Compute starting from last row since V[j][k] is computed based on
values in row j+1 of V */
for (k = 1 to m) { /* The order here is not important */
V[j][k] := V[j+1][k]; H[j][k]:=0 /* Initialize V[j][k] based on “no match” */
found := FALSE; r := k;
while(found = FALSE and rm) /* Search for match */
if ([j] = [r]) /* Found a match */
found := TRUE /* Should exist while loop */
if (found = TRUE)
if (1+V[j+1][r+1] > V[j][k]) /* Note: V[j][k] was initialized to V[j+1][k+1] */
{ V[j][k] := 1+ V[j+1][r+1] ; H[j][k]:= r }
}
}
Print-Match-Function(H,1,1)
return(V[1][1]) /* This is the value of the best matching from [1,…,n] to [1,…,m] */
}
‫ בתוכה לולאה‬,‫ איטרציות‬n ‫ ואז יש לולאה חיצונית שרצה‬,(n) ‫ כי האתחול לוקח זמן‬(n m2) ‫זמן הריצה הוא‬
.)‫ איטרציות (ובתוכה מתבצע מספר קבוע של פעולות‬m ‫ ובתוכה עוד לולאה שרצה לכל היותר‬,‫ איטרציות‬m ‫שרצה‬
:‫שגיאות נפוצות‬
‫היו מי שלא דאגו לאתחול או שלא אתחלו נכון‬
‫היו מי שבצעו סדר חישוב שגוי כך שפונים לכניסות במטריצה שעדיין לא חושבו‬
‫ הראשון שנותן התאמה‬r ‫היו מי שבלולאה הפנימית לא השתמשו ב‬
‫היו מי שלא החזירו ערך נכון‬
. Bottom-Up ‫ ו‬Memoization ‫היו מי שכתבו קוד שהוא ערבוב שגוי של‬
4
.1
.2
.3
.4
.5
‫ב‪ .‬בנוסף למטריצה ‪ V‬נחזיק גם מטריצה ‪ H‬כאשר נרצה ש ]‪ H[j][k‬יהיה האינדקס אליו ממופה ‪ j‬בפונקציית התאמה‬
‫אופטימאלית מ ]‪ [j,…,n‬ל ]‪ [k,…,m‬ראו שורות מודגשות בסעיף הקודם (בפרט‪ ,‬נקרא לפרוצדורה עם ‪.)j=k=1‬‬
‫פונקציית ההדפסה מופיעה להלן‪ .‬בכל קריאה מודפס הזוג )]‪ (j,H[j][k‬ויש קריאה רקורסיבית לפי הערך של‬
‫]‪ :H[j][k‬אם הוא ‪ 0‬זה אומר שאים התאמה‪ ,‬כך שממשיכים עם ‪ j+1‬ו ‪ ,k‬ואם יש התאמה (בין ]‪ [j‬ל )]‪,[H[j][k‬‬
‫אז ממשיכים עם ‪ j+1‬ו ‪ .H[j][k]+1‬נשים לב שאתחלנו את ]‪ H[j][m+1‬ל ‪ ,0‬כך שכאשר מגיעים ל ‪ j‬עבורו‬
‫‪ , H[j][k]=m‬כלומר ‪ ,h(j)=m‬אז עבור כל ‪ ,j’>j‬נדפיס )‪ .(j’,0‬ניתן היה גם לממש באופן איטרטיבי‪.‬‬
‫)‪Print-Match-Function(H,j,k‬‬
‫{‬
‫)‪if (j > n‬‬
‫‪return‬‬
‫)]‪print(j,H[j][k‬‬
‫)‪if (H[j][k] = 0‬‬
‫)‪Print-Match-Function(H,j+1,k‬‬
‫‪else‬‬
‫)‪Print-Match-Function(H,j+1,H[j][k]+1‬‬
‫}‬
‫שגיאות נפוצות‪:‬‬
‫‪ .1‬היו רבים שמילאו את מטריצת העזר כנדרש או באופן חלקי אך הפרוצדורה הייתה שגויה (על כך ניתן ניקוד‬
‫חלקי)‪.‬‬
‫‪ .2‬היו מי שניסו להשתמש במערך חד ממדי אך זה לא נותן את המידע הנדרש‬
‫‪ .3‬היו מי שלא הפרידו בקריאות הרקורסיביות בין המקרה שאין התאמה לבין המקרה שיש‬
‫‪5‬‬
‫ת"ז‪:‬‬
‫אוניברסיטת תל‪-‬אביב‬
‫הפקולטה להנדסה‬
‫מועד ב' תשע"ד במבני נתונים ואלגוריתמים‪ ,‬סמסטר ב'‬
‫זמן המבחן‪ :‬שלוש שעות‬
‫תאריך‪.202.8.1 :‬‬
‫מרצה‪ :‬דנה רון‬
‫הנחיות‪:‬‬
‫‪‬‬
‫מותר להשתמש בארבעה דפי עזר‪ .‬אין להשתמש בשום סוג של מחשב‪.‬‬
‫‪‬‬
‫המבחן כולל ‪ 4‬שאלות‪ .‬הניקוד על כל שאלה מופיע בסוגריים‪.‬‬
‫כתבו את תשובותיכם על גבי טופס המבחן במקום המוקצה לכך‪ .‬מומלץ מאוד לכתוב תחילה את‬
‫‪‬‬
‫התשובה במחברת הטיוטה שקיבלתם ורק אחר כך להעתיק אותה‪ ,‬בצורה ברורה וקריאה‪ ,‬לטופס המבחן‪.‬‬
‫נמקו בקצרה אך בבהירות את כל טענותיכם‪ .‬טענה ללא נימוק לא תתקבל‪.‬‬
‫‪ ‬מותר להשתמש במשפטים ואלגוריתמים שנלמדו בשיעורים ובתרגולים או שהופיעו בתרגילי הבית‪.‬‬
‫במקרה כזה ניתן לצטט את מה שנלמד ללא צורך בהוכחה‪ .‬לעומת זאת‪ ,‬אם אתם משתמשים בגרסה שונה‬
‫מעט של אלגוריתם או ניתוח כלשהו יש להסביר במדויק מה ההבדלים‪.‬‬
‫‪‬‬
‫במבחן זה ‪ 11‬עמודים (כולל עמוד זה)‪ .‬אנא ודאו שכולם ברשותכם‪.‬‬
‫‪‬‬
‫אל תשכחו לרשום מספר ת"ז במקום המסומן‪2‬‬
‫ב ה צ ל ח ה!‬
‫‪2.‬‬
‫‪2.‬‬
‫א)‬
‫‪23‬‬
‫‪21‬‬
‫א)‬
‫א)‬
‫ב)‬
‫ב)‬
‫ג)‬
‫ד)‬
‫ג)‬
‫‪1‬‬
‫ב)‬
‫ג)‬
‫שאלה ‪ 38( .‬נק')‬
‫יהי ‪ A‬מערך שבו ‪ n‬מספרים שלמים‪ .‬מספר ‪ x‬יקרא איבר רוב של ‪ A‬אם מספר ההופעות של ‪ x‬ב‪ A-‬הוא לפחות‬
‫‪ .  n / 2  1‬לדוגמה‪ :‬אם ‪ n=7‬ו‪ , A  [1,5, 2,5,5,14,5] -‬אז ‪ 5‬הוא איבר רוב כי הוא מופיע ‪ 4‬פעמים שזה לפחות‬
‫‪ 7 / 2  1  4‬פעמים‪ .‬שימו לב כי אם קיים איבר רוב במערך ‪ A‬אזי הוא יחיד‪.‬‬
‫נגדיר בעיה שנקרא לה "בעיית איבר הרוב"‪ :‬בהינתן המערך ‪ A‬וגודלו ‪ ,n‬יש למצוא האם יש ב ‪ A‬איבר רוב‪ .‬אם כן‪,‬‬
‫אז יש להחזיר איבר זה‪ .‬אחרת‪ ,‬יש להדפיס שלא קיים איבר רוב‪ .‬בסעיפים הבאים נעסוק בבעיית איבר הרוב‪.‬‬
‫א‪ .8( 2‬נק') נניח שהמערך ‪ A‬ממוין (מקטן לגדול)‪ .‬השלימו את הקוד שלעיל כך שיחזיר את איבר הרוב אם קיים‬
‫כזה איבר‪ ,‬ויחזיר ‪ NOT-FOUND‬אם לא קיים כזה איבר‪ .‬הסבירו בקיצור מדוע הפלט כנדרש‪ .‬בפרט‪ ,‬הסבירו מה‬
‫מקיימים ‪ left‬ו ‪( .right‬כתבו ההסבר לתשובתכם בשורות מימין לקוד)‪.‬‬
‫)‪Majority_Sorted(A,n‬‬
‫{‬
‫]‪pos := n/2 + 1; maybe_majority := A[pos‬‬
‫;‪min := 1; max := pos‬‬
‫___________________________________________‬
‫{ )‪while (min < max‬‬
‫___________________________________________‬
‫‪mid := (min+max)/2‬‬
‫)‪if (A[mid] = maybe_majority‬‬
‫___________________________________________‬
‫‪max := mid‬‬
‫‪else min := mid + 1‬‬
‫___________________________________________‬
‫}‬
‫___________________________________________‬
‫‪left := min; min := pos; max := n‬‬
‫{ )‪while (min < max‬‬
‫___________________________________________‬
‫‪mid := (min+max)/2‬‬
‫)‪if (A[mid] = maybe_majority‬‬
‫____________________________________‬
‫‪min := mid‬‬
‫‪else max := mid - 1‬‬
‫____________________________________‬
‫}‬
‫‪right := min‬‬
‫____________________________________‬
‫)______________ ‪if (right – left +1 ‬‬
‫)______________ (‪return‬‬
‫) ______________ (‪else return‬‬
‫}‬
‫מה זמן הריצה של הפרוצדורה כפונקציה של ‪( ?n‬כלומר‪ ,‬מהו )‪ g(n‬כך שזמן הריצה הוא ))‪ )?(g(n‬נמקו את‬
‫תשובתכם‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________ ________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪2‬‬
‫מכאן והלאה לא נניח ש ‪ A‬ממוין (והסעיפים הבאים אינם בונים על סעיף א)‪ .‬הפרוצדורה הבאה מקבלת מערך ‪A‬‬
‫בגודל ‪ n‬ומספר שלם ‪ k‬בין ‪ 1‬ל ‪ ,n‬ומחזירה מספר‪ .‬נרצה להראות כי אם ב ‪ A‬יש איבר רוב‪ ,‬אז הקריאה ל‬
‫)‪ Majority(A,n‬תחזיר אותו‪ .‬אם אין איבר רוב ב ‪ A‬אז הפרוצדורה תחזיר איבר כלשהו‪.‬‬
‫)‪1. Majority(A,k‬‬
‫{ ‪2.‬‬
‫‪3.‬‬
‫) ]‪if ( k = 1 ) then return ( A[1‬‬
‫‪4.‬‬
‫; ]‪val := A[k‬‬
‫‪5.‬‬
‫;‪j := 1; count := 1‬‬
‫‪6.‬‬
‫) ‪while( j < k and count > 0‬‬
‫‪7.‬‬
‫{‬
‫‪8.‬‬
‫) ‪if ( A[k-j] = val‬‬
‫‪9.‬‬
‫‪count := count+1‬‬
‫‪10.‬‬
‫‪else‬‬
‫‪11.‬‬
‫‪count := count-1‬‬
‫‪12.‬‬
‫;‪j := j+1‬‬
‫‪13.‬‬
‫}‬
‫‪14.‬‬
‫) ‪if ( j = k‬‬
‫‪15.‬‬
‫)‪return(val‬‬
‫‪16.‬‬
‫‪else‬‬
‫‪17.‬‬
‫) )‪return( Majority(A,k-j‬‬
‫} ‪18.‬‬
‫יהי *‪ j‬הערך של המשתנה ‪ j‬בסיום ריצת לולאת ה ‪( while‬כלומר‪ ,‬בשורה ‪.)14‬‬
‫ב‪ 1( 2‬נק')‬
‫(‪ )1‬מהו *‪ j‬כאשר קוראים ל )‪ Majority(A,k‬עם ]‪ A=[1,5,2,5,5,14,5‬ו ‪ ?k=7‬הסבירו בקיצור‪.‬‬
‫(‪ )2‬מהו *‪ j‬כאשר קוראים ל )‪ Majority(A,k‬עם ]‪ A=[1,14,2,5,5,5,5‬ו ‪ ?k=7‬הסבירו בקיצור‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪3‬‬
‫עבור תת מערך ]‪ A[1,…,t‬אנו אומרים ש ‪ x‬הוא איבר רוב ב ]‪ A[1,…,t‬אם הוא מופיע לפחות ‪ t/2 +1‬פעמים ב‬
‫]‪ .A[1,…,t‬נתונות העובדות הבאות (אין צורך להוכיח אותן)‪.‬‬
‫(‪ )1‬אם ‪ j*=k‬וקיים איבר רוב ב ]‪ A[1,…,k‬אז ‪( val‬כפי שהוגדר בשורה ‪ )4‬הוא איבר רוב זה‪.‬‬
‫(‪ )2‬אם ‪ j*<k‬וקיים איבר רוב ב ]‪ A[1,…,k‬אז איבר זה הוא גם איבר הרוב ב ]*‪.A[1,…,k-j‬‬
‫ג‪ 6( 2‬נק') בשימוש בעובדות אלו הוכיחו באינדוקציה על ‪ k‬שאם ב ]‪ A[1,..,k‬יש איבר רוב אז )‪Majority(A,k‬‬
‫מחזירה אותו‪( .‬לכן בפרט )‪ Majority(A,n‬מחזירה את איבר הרוב במערך כולו אם קיים איבר כזה‪).‬‬
‫_ ____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫______________________________________ _______________________________________________________‬
‫_____________________________________________________________________________________________‬
‫ד‪ .8( 2‬נק') מהי )‪ g(n‬כך שזמן הריצה של )‪ Majority(A,n‬הוא ))‪ ?(g(n‬נמקו את תשובתכם בעזרת תיאור מבנה‬
‫עץ הרקורסיה של האלגוריתם‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ ____________________________________ _________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_______________ ______________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫____________________________________________________ _________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪4‬‬
‫שאלה ‪ .3( .‬נק')‬
‫בסיום הריצה של אלגוריתם הופמן מתקבל עץ של קוד רישא בינארי אופטימאלי (ביחס לא"ב ‪ ‬הנתון והשכיחויות‬
‫הנתונות)‪ .‬השאלה היא כיצד ניתן לקבל את הקוד בהינתן העץ‪ .‬נניח כי כל קדקוד בעץ הוא רשומה המכילה את השדות‬
‫הבאים‪ – LET :‬האות אותה מיצג הקדקוד (באם הוא עלה‪ ,‬אחרת שדה זה ריק); ‪ – LC‬מצביע לילד השמאלי; ‪– RC‬‬
‫מצביע לילד הימני (אם הקדקוד הוא עלה אזי שני שדות אלה הם ‪ ;)NULL‬ו ‪ – WEIGHT‬המשקל של תת העץ‪.‬‬
‫כתבו פסאודו קוד עבור פרוצדורה המקבלת מצביע לשרש של עץ שכזה (ואולי פרמטרים נוספים לבחירתכם)‬
‫ומדפיסה רשימה של זוגות‪ :‬אות ומילת הקוד המתאימה לאות‪ ,‬עבור כל אות בא"ב ‪ . ‬הניחו כי ניתן לקרוא‬
‫לפרוצדורה )‪ strcat(s1,s2‬המקבלת שתי מחרוזות ‪ s1‬ו ‪( s2‬כאשר גם תו יחיד הוא מחרוזת) ומחזירה את המחרוזת‬
‫שהיא שרשור של ‪ s1‬עם ‪( s2‬לדוגמא‪ ,‬אם ‪ s1 = 1001‬ו ‪ s2 = 1‬אז )‪ strcat(s1,s2‬תחזיר את המחרוזת ‪ ,10011‬ואם‬
‫‪ s1‬היא המחרוזת הריקה אז )‪ strcat(s1,s2‬תחזיר את ‪ .)s2‬מותר לפרוצדורה להשתמש בזיכרון נוסף בגודל קבוע‪ ,‬אך‬
‫לא יותר מכך ‪.‬‬
‫הוסיפו הערות לצד הפסאודו‪-‬קוד ונתחו את זמן הריצה של האלגוריתם שכתבתם כפונקציה של |‪ 2|‬ניתן להניח ש‬
‫‪ ||>2‬ולהשתמש בכך שבעץ בינארי עם ‪ L‬עלים שבו לכל קדקוד פנימי יש שני ילדים‪ ,‬מספר הקדקודים הכולל הוא‬
‫)‪ .O(L‬זמן הריצה של ‪ strcat‬קבוע‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________ ________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪5‬‬
‫שאלה ‪ .6( 3‬נק')‬
‫על כל אחת מהטענות הבאות כתבו האם היא נכונה או שאינה נכונה‪ .‬אם הטענה מתקיימת‪ ,‬הסבירו במדויק מדוע‪ .‬אם‬
‫היא אינה מתקיימת‪ ,‬תנו דוגמה נגדית‪( .‬הסעיפים בשאלה זו אינם בונים זה על זה‪) .‬‬
‫א‪ 2‬להזכירכם‪ ,‬במימוש תור קדימויות באמצעות ערימה‪ ,‬כפי שלמדנו בכיתה‪ ,‬הערימה ‪ P‬מורכבת משדה גודל‬
‫(‪ )P.size‬וממערך המכיל את אברי הערימה (‪.)P.T‬‬
‫(‪ 5( )1‬נק') לכל ערימה ‪ P‬עבורה ‪ P.size2‬ולכל סדרה של אינדקסים ‪ 1i1<i2<…<itP.size‬מתקיים ש‬
‫]‪.P.T[i1]P.T[i2]…P.T[it‬‬
‫_____________________________ ________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫(‪ 5( )2‬נק') לכל גודל ‪ ,n2‬קיימת סדרה של אינדקסים ‪ 1i1<i2<…<it n‬כאשר )‪ t=(log n‬כך שלכל ערימה‬
‫‪ P‬עם ‪ n‬אברים (כלומר ‪ ,)P.size=n‬מתקיים ]‪.P.T[i1]P.T[i2]…P.T[it‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫________________________________ _____________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪6‬‬
‫ב‪ 0( 2‬נק') יהי ‪ G‬גרף עם משקלים על צלעותיו‪ ,‬יהי ‪ w0‬המשקל המינימאלי של צלע בגרף‪ ,‬ויהי ‪ w1>w0‬המשקל‬
‫השני הכי קטן‪ .‬אם יש רק צלע אחת עם משקל ‪ w0‬ורק צלע אחת עם משקל ‪( w1‬אבל ייתכן ומשקלים אחרים מופיעים‬
‫מספר פעמים)‪ ,‬אז הצלע עם משקל ‪ w1‬שייכת לכל עץ פורש עם משקל מינימאלי‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________ ________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫ג‪ 0( 2‬נק' – סעיף מגן (כלומר‪ ,‬הציון במבחן יהיה המקסימום בין סכום הנקודות על כל הסעיפים‪ ,‬לבין סכום‬
‫הנקודות על כל הסעיפים מלבד סעיף זה כפול ‪)(.8800.‬‬
‫‪2/3‬‬
‫עבור כל מערך קלט ‪ A‬שבו ‪ n>1‬מספרים שונים ניתן לקבל את ‪ n ‬המספרים הקטנים במערך בזמן )‪.O(n‬‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _______________________________________________ ______________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪7‬‬
‫שאלה ‪ 3.( 1‬נק')‬
‫בשאלה זו נרצה לפתור את הבעיה הבאה‪.‬‬
‫הקלט‪ :‬מספרים שלמים ‪ n>1‬ו ‪ ,m>1‬ומטריצה ‪ A‬שממדיה )‪ n x (m+1‬כאשר שורותיה מתאימות ל ‪1,…,n‬‬
‫ועמודותיה ל ‪ 0,…,m‬וכך שכל כניסה במטריצה היא מספר כלשהו‪.‬‬
‫הפלט‪ :‬מערך ‪ C‬בגודל ‪ n‬כך שכל ]‪ C[i‬הוא מספר שלם אי שלילי‪C[i]  m ,‬‬
‫]]‪A[i][C[i‬‬
‫‪‬‬
‫‪n‬‬
‫‪i 1‬‬
‫‪‬‬
‫‪n‬‬
‫‪i 1‬‬
‫‪,‬ו‬
‫‪ s( A, C ) ‬גדול ככל האפשר‪ .‬ראשית נחשב את הערך המרבי של )‪ s(A,C‬ואחר כך נמצא ‪C‬‬
‫שנותנת ערך שכזה‪ .‬לשם כך נגדיר‪ ,‬לכל ‪ ,1jn‬ו ‪ 0km‬את )‪ S(j,k‬להיות המקסימום של ]]‪A[i][C[i‬‬
‫תחת האילוץ ש ‪C[i]  k‬‬
‫‪j‬‬
‫‪‬‬
‫‪i 1‬‬
‫‪j‬‬
‫‪‬‬
‫‪i 1‬‬
‫‪ ,‬כאשר כל ]‪ C[i‬הוא מספר שלם אי‪-‬שלילי‪.‬‬
‫א) (‪ 5‬נק') איזו מהנוסחאות הבאות מתקיימת לכל ‪ 1 < j n‬ו ‪ ?0  k  m‬הסבירו את תשובתכם‪ ,‬כאשר יש‬
‫להצדיק את הבחירה מפורשות ולא מספיק לפסול שתיים מהאופציות על ידי מתן דוגמאות בהן הן לא מתקיימות‪.‬‬
‫(‪S ( j, k )  max 0t k S ( j  1, t )  A[ j ][t ] )1‬‬
‫(‪S ( j, k )  max 0t k S ( j  1, k  t )  A[ j ][k ] )2‬‬
‫(‪S ( j, k )  max 0t k S ( j  1, k  t )  A[ j ][t ] )3‬‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________ ________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪8‬‬
‫ב) (‪ .6‬נק') כתבו פסאודו‪-‬קוד עבור אלגוריתם המקבל כקלט את ‪ m ,n‬ו ‪ ,A‬והמחזיר כפלט את הערך המרבי של‬
‫)‪ . s(A,C‬זמן הריצה של האלגוריתם צריך להיות פולינומיאלי ב ‪ n‬ו ‪ m‬ועליכם לתת חסם עליון טוב ככל האפשר‬
‫על זמן הריצה של האלגוריתם שלכם‪ 2‬לא ניתן לכתוב בקוד שורות ביטויים של מקסימום כגון אלו הכתובים בסעיף‬
‫א' אלא יש לחשב אותם במפורט‪.‬‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫__________________________________ ___________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____ ________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________ ________________________________________________________________________________‬
‫‪9‬‬
‫ג) (‪ .8‬נק') הוסיפו פסאודו‪-‬קוד לאלגוריתם שכתבתם בסעיף ב‪ ,‬וכתבו פסאודו‪-‬קוד עבור פרוצדורה הנקראת‬
‫מהאלגוריתם (עליכם להוסיף גם את שורת הקריאה)‪ ,‬המדפיסה את הערכים ]‪( C[1],…,C[n‬לפי הסדר‪ ,‬מ ]‪C[1‬‬
‫ועד ]‪ )C[n‬עבור מערך ‪ C‬הנותן ערך )‪ s(A,C‬מרבי‪( .‬אין צורך למלא את המערך ‪ C‬האופטימאלי‪ ,‬אלא רק להדפיס‬
‫את הערכים בו‪ ).‬התוספות לקוד אינן משנות את זמן הריצה של האלגוריתם באופן אסימפטוטי‪ ,‬וזמן הריצה של‬
‫הפרוצדורה הנוספת צריך להיות )‪.O(n‬‬
‫__________ ___________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫__________________ ___________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪11‬‬
‫פתרון מועד ב' סמסטר ב' תשע"ד‬
1 ‫שאלה‬
‫ זה מתקיים כי אחרת או שהמופע האחרון‬.‫ הוא איבר רוב‬n/2 +1 ‫ אם קיים איבר רוב אז בהכרח האיבר במקום‬.‫א‬
‫ בשני המקרים זה נותן‬.‫ או שהמופע הראשון של איבר הרוב הוא אחרי מקום זה‬,‫של איבר הרוב הוא לפני מקום זה‬
while ‫ בלולאת ה‬.maybe_majority ‫ האלגוריתם מציב את הערך במקום זה במשתנה‬.‫מספר קטן מדי של מופעים‬
,left ‫ ומציב מיקום זה ב‬,‫הראשונה הוא מוצא את מיקום המופע הראשון של ערך זה במערך בעזרת חיפוש בינארי‬
‫ בסיום הוא בודק כמה איברים יש‬.right ‫ ומציב ב‬,‫ובלולאה השנייה הוא מוצא את מיקום המופע האחרון של ערך זה‬
‫ אחרת‬,maybe_majority ‫ אז מחזירים את הערך של‬,‫ ואם מספר זה הוא כנדרש מאיבר רוב‬,right ‫ ו‬left ‫בין‬
.NOT-FOUND ‫מחזירים‬
‫ צריך להשתמש בערך עליון (כפי שמודגש בקוד שלמטה) ולא‬mid ‫ בהצבה ב‬:‫בשאלה נפלה טעות בלולאה השנייה‬
.)‫ רוב הסטודנטים לא נתקלו כלל בבעיה‬,‫ מעבר לכך הקוד נשאר כשהיה (ואכן‬- ‫בערך תחתון‬
,mid=min ‫ כך ש‬max=min+1 ‫השימוש בערך תחתון גרם לכך שהלולאה עלולה לא להיעצר כי מגיעים למצב בו‬
.max ‫ ו‬min ‫ונשארים עם אותם ערכים של‬
Majority_Sorted(A,n)
{
pos := n/2 +1
maybe_majority := A[pos] /* if A contains majority value, then must occur in A[pos] */
min := 1; max := pos;
while (min < max) { /* Invariant of while loop: A[min,…,max] is non-empty and contains leftmost
occurrence of maybe_majority */
mid := (min+max)/2 /* setting of mid satisfies min  mid < max */
if (A[mid] = maybe_majority)
max := mid /* max decreases so that max-min decreases (but is non-negative) */
else min := mid + 1 /* min increases so that max-min decreases (but is non-negative) */
}
left := min /* left is leftmost occurrence of maybe_majority in A */
min := pos; max := n
while (min < max) { /* Invariant of while loop: A[min,…,max] is non-empty and contains
rightmost occurrence of maybe_majority */
mid := (min+max)/2 /* setting of mid satisfies min < mid  max */
if (A[mid] = maybe_majority)
min := mid /* min increases so that max-min decreases (but is non-negative) */
else max := mid – 1 /* max decreases so that max-min decreases (but is non-negative) */
}
right := min /* right is rightmost occurrence of maybe_majority in A */
if (right – left +1  n/2 +1) /* maybe majority is majority value in A */
return( maybe_majority)
else return( NOT-FOUND )
}
1
‫זמן הריצה של הפרוצדורה הוא ))‪ . (log(n‬הסבר‪ :‬סך כל הפעולות מחוץ ללולאות ה ‪ while‬לוקחות זמן קבוע‪ ,‬וכל‬
‫איטרציה של כל לולאת ‪ while‬לוקחת זמן קבוע‪ .‬נותר אם כן לחסום את מספר האיטרציות של כל אחת מהלולאות‪.‬‬
‫הראשונה מתחילה עם ‪ ,min=1, max = n/2+1‬ובכל איטרציה ההפרש בין ‪ min‬ל ‪ max‬קטן בפקטור ‪ ,2‬כך שיש‬
‫))‪ (log(n‬איטרציות‪ .‬באופן דומה‪ ,‬הלולאה השנייה מתחילה עם ‪ min=n/2+1‬ו ‪ ,max=n‬וגם כן ההפרש קטן‬
‫בפקטור ‪ 2‬בכל איטרציה‪.‬‬
‫שגיאות נפוצות‪:‬‬
‫היו סטודנטים אשר השלימו את הקוד נכון והסבירו את ההשלמה אך שגו בניתוח זמן הריצה (היו שטענו שזמן הריצה‬
‫)‪ (n‬והיו שטענו ש ))‪.)(nlog(n‬‬
‫‪2‬‬
‫ב‪ .‬עבור המערך הראשון נקבל ‪ j*=2‬ועבור השני‪ .j*=7 ,‬עבור הראשון‪ ,‬באיטרציה הראשונה של לולאת ה ‪,while‬‬
‫כיוון ש ‪ A[k-j]=A[6]=14‬שונה מ ‪ ,val=A[7]=5‬אז ‪ count‬יורד מ ‪ 1‬ל ‪ j ,0‬גדל ל ‪ ,2‬ויוצאים מלולאת ה ‪while‬‬
‫מיד אחרי איטרציה זו כי ‪ .count=0‬לעומת זאת‪ ,‬במערך השני‪ ,‬באיטרציה הראשונה ‪ A[k-j]=A[6]=5‬שזה שווה ל‬
‫‪ ,val‬כל ש ‪ count‬גדל ל ‪ 2‬וכמקודם ‪ j‬גדל ל ‪ .2‬באיטרציה הבאה ‪ count‬גדל ל ‪ 3‬ו ‪ j‬ל ‪ ,3‬ובבאה ‪ count‬גדל ל ‪ 4‬ו ‪j‬‬
‫ל ‪ .4‬בשלוש האיטרציות הבאות‪ ,‬כיוון שהערכים ב ]‪ A[k-j‬שונים מ ‪ val‬אזי ‪ count‬קטן בכל אחת מהן ב ‪ 1‬עד‬
‫שמגיע ל ‪ ,1‬בעוד ‪ j‬ממשיך לגדול עד ל ‪ 7‬כך שיוצאים מלולאת ה ‪ while‬כי ‪.j=k‬‬
‫ג‪ .‬בסיס האינדוקציה‪ .k=1 :‬במקרה זה האיבר היחיד בתת המערך הוא איבר רוב באופן טריוויאלי (כי ‪)1/2 +1 =1‬‬
‫והוא אכן מוחזר בשורה ‪.1‬‬
‫צעד האינדוקציה‪ .‬נוכיח שהטענה מתקיימת עבור ‪ k>1‬תחת הנחת האינדוקציה שהיא מתקיימת לכל ‪ ,1k’<k‬כלומר‬
‫שהפרוצדורה מחזירה את איבר הרוב אם קיים כשה כאשר היא נקראת על תת מערך בגודל קטן ממש מ ‪ k‬וגדול או‬
‫שווה ‪ .1‬בסיום לולאת ה ‪ ,while‬לפי עובדה (‪ ,)1‬אם ‪ j*=k‬אז ‪ val‬הוא איבר הרוב ב ]‪ A[1,…,k‬והא אכן מוחזר‪,‬‬
‫כנדרש‪ .‬אחרת‪ , j*<k ,‬ולפי עובדה (‪ ,)2‬איבר הרוב ב ]‪ A[1,…,k‬הוא גם איבר הרוב ב ]*‪ ,A[k-j‬אבל כיוון ש‬
‫‪( j*>1‬כי ‪ j‬אותחל ל ‪ 1‬וגדל לפחות ל ‪ )2‬הרי שלפי הנחת האינדוקציה (כי ‪ ,1k-j*<k‬הקריאה ל ‪Majority(A,k-‬‬
‫)*‪ j‬תחזיר את איבר הרוב ב ]*‪ A[1,..,k-j‬הוא איבר הרוב ב ]‪ ,A[1,…,k‬כנדרש‪.‬‬
‫שגיאות נפוצות‪:‬‬
‫סטודנטים לא מעטים ניסו להוכיח עבור ‪ k+1‬על בסיס ההנחה שהטענה מתקיימת עבור ‪ k‬אבל זה לא המבנה הנכון של‬
‫ההוכחה‪ ,‬כי הקריאה הרקורסיבית מתבצעת על תת מערך קטן יותר בגודל כלשהו (כלומר‪ ,‬יש להוכיח על ידי‬
‫אינדוקציה "שלמה" כפי שתואר לעיל)‪ .‬היו מי שלא השתמשו באחת העובדות ((‪ )1‬או (‪ ,))2‬היו מי שלא דאגו לבסיס‬
‫האינדוקציה‪ ,‬והיו מי שהראו הבנה חלקית כלשהי את למעשה לא נתנו הוכחת נכונות (בפרט לא באינדוקציה)‪.‬‬
‫ד‪ .‬זמן הריצה הוא )‪ ,(n‬לכל מערך קלט‪ .‬להלן הסבר‪ .‬מבנה עץ הרקורסיה הוא שרוך כי יש קריאה רקורסיבית אחת‬
‫מתוך האלגוריתם‪ .‬זמן הריצה בכל קריאה (לא כולל הקריאה הרקורסיבית ממנה) ליניארי ב *‪ ,j‬כלומר במספר‬
‫האיטרציות של לולאת ה ‪ .while‬כלומר‪ ,‬לעץ יש את המבנה הבא‪:‬‬
‫*‪cj0‬‬
‫כאשר הסכום על ה *‪ ji‬הוא ‪ n‬כי הקריאה הרקורסיבית‬
‫ה ‪ i‬היא על תת המערך בגודל *‪ ji-1‬יותר קטן מאשר‬
‫*‪cj2‬‬
‫תת המערך בקריאה הקודמת‪ .‬כלומר‪ ,‬אם נסמן את‬
‫…‬
‫הגדלים של תת המערכים בקריאות השונות‬
‫לאלגוריתם ב ‪ ,k0,…,kh‬אז ‪,k1=k0 – j0* ,k0=n‬‬
‫ובאופן כללי‪( ki = ki-1 – ji-1* ,‬ו ‪ jh*=kh‬כי *‪cjh‬‬
‫האלגוריתם נעצר)‪ ,‬ולכן הסכום על כל *‪ji‬‬
‫שווה ל ‪ .k0=n‬מכאן שזמן הריצה הכולל ליניארי ב ‪ n‬כפי שנטען‪.‬‬
‫*‪cj1‬‬
‫שגיאות נפוצות‪:‬‬
‫סטודנטים לא מעטים טענו שזמן הריצה הוא )‪ .(n2‬כיוון ש )‪ n = O(n2‬הרי שהחסם העליון נכון‪ ,‬אבל החסם התחתון‬
‫אינו נכון‪ ,‬כלומר זמן הריצה אינו )‪ .(n2‬בפרט היו שטענו שזהו זמן הריצה על קלט מסוים (לדוגמה‪ ,‬בו כל המספרים‬
‫שונים זה מזה)‪ ,‬וזו טעות‪.‬‬
‫‪3‬‬
‫שאלה ‪2‬‬
‫הקריאה הראשונה נעשית עם ‪ pnode‬שהוא השורש לעץ ו ‪ codeword‬שהיא מחרוזת ריקה‪ .‬בקריאות הרקורסיביות‬
‫קוראים לילדים‪ ,‬כאשר לילד השמאלי שולחים את המחרוזת המתאימה לקדקוד הנוכחי משורשרת עם ‪ ,0‬ולימני עם ‪1‬‬
‫(להזכירכם‪ ,‬לכל קדקוד פנימי בהכרח יש שני ילדים כי הקוד אופטימאלי)‪ .‬כאשר מגיעים לעלה פשוט מדפיסים את‬
‫האות המתאימה ואת המילה המתאימה לעלה‪ .‬זמן הריצה ליניארי במספר הקדקודים ‪ ,n‬כיוון שיש קריאה רקורסיבית‬
‫אחת בדיוק לכל קדקוד‪ .‬כיוון שלכל קדקוד בעץ יש שני ילדים הרי שמספר הקדקודים בעץ ליניארי ב |‪( |‬מספר‬
‫העלים)‪ ,‬ולכן זמן הריצה ליניארי ב |‪.|‬‬
‫)‪Print-Huff-Code(pnode,codeword‬‬
‫{‬
‫)‪if (pnode  LC = NULL & pnode  RC = NULL‬‬
‫)‪Print(pnode  LET, codeword‬‬
‫{ ‪else‬‬
‫)‪if (pnode  LC != NULL‬‬
‫))‪Print-Huff-Code(pnode  LC, strcat(codeword, 0‬‬
‫)‪if (pnode  RC != NULL‬‬
‫))‪Print-Huff-Code(pnode  RC, strcat(codeword,1‬‬
‫}‬
‫}‬
‫שגיאות נפוצות‪:‬‬
‫‪ .1‬חלק מהסטודנטים לא התייחסו כלל לשרשור מילת הקוד המצטברת עם ‪ 0/1‬בהתאם לכיוון ההתקדמות‪.‬‬
‫‪ .2‬רבים התייחסו למשקל הקדקוד למרות שאין משמעות למשקל הקדקוד בזמן מציאת מילת הקוד‪ ,‬בהינתן עץ בנוי‪.‬‬
‫ישנה משמעות למשקל הקדקוד רק במהלך בניית העץ (ולכן הוזכר שהוא חלק ממבנה הנתונים)‬
‫‪ .3‬חלק מהסטודנטים נתנו תנאי עצירה שגוי המתייחס למשקל הקדקוד‪.‬‬
‫‪4‬‬
‫שאלה ‪3‬‬
‫א‪ )1( .‬הטענה אינה נכונה‪ .‬לדוגמה ]‪ P.T = [1,3,2‬היא ערימה חוקית‪:‬‬
‫‪1‬‬
‫‪2‬‬
‫‪3‬‬
‫אך עבור ‪ ,i1=1, i2=2, i3=3‬הטענה אינה מתקיימת‪.‬‬
‫(‪ )2‬הטענה נכונה‪ .‬אם ניקח ‪ ij=2j-1‬עבור )‪ j=1,..,log(n‬אז סדרת האינדקסים הזו מתאימה למסלול בעץ הבינארי‬
‫הסדור חלקית המוגדר על ידי הערימה מהשורש ועד לעלה‪ ,‬ולפי תכונות עץ בינארי סדור חלקית ערכים אלו עולים‬
‫מונוטונית (אינם יורדים)‪ ,‬ואורך הסדרה כנדרש‪.‬‬
‫שגיאות נפוצות‪ :‬רבים נתנו את התשובה הנכונה (האם כל טענה נכונה או לא נכונה) אך לא נתנו הסבר או נתנו הסבר‬
‫שגוי‪.‬‬
‫ב‪ .‬הטענה נכונה‪ .‬תהי )‪ (x,y‬הצלע (היחידה) עם משקל ‪ .w1‬נניח בשלילה שיש עץ פורש ‪ T‬עם משקל מינימאלי שלא‬
‫מכיל צלע זו‪ .‬כיוון שזהו עץ פורש‪ ,‬יש מסלול בעץ בין ‪ x‬ל ‪ .y‬כיוון ש )‪ (x,y‬לא בעץ‪ ,‬מסלול זה מכיל לפחות שתי‬
‫צלעות‪ .‬כיוון שיש רק צלע אחת במשקל ‪ ,w0<w1‬ורק )‪ (x,y‬במשקל ‪ ,w1‬הרי שלפחות אחת הצלעות במסלול‪,‬‬
‫שנסמנה )‪ (u,v‬משקלה גדול ממש מ ‪ .w1‬נוריד צלע זו‪ ,‬כך שנקבל שני עצים‪ ,‬באחד ‪ x‬ובשני ‪ , y‬ועתה נוסיף את‬
‫הצלע )‪ (x,y‬כך שנקבל עץ פורש ’‪ .T‬משקלו של ’‪ w(T’) = w(T) – w(u,v) + w(x,y) < w(T) :T‬וקיבלנו‬
‫סתירה למינימאליות משקלו של ‪.T‬‬
‫שגיאות נפוצות‪:‬‬
‫‪ . 1‬לא ניתן להוכיח את הטענה ע"י אלגוריתם ספציפי או שימוש במשפט תנאי מספיק לבטיחות‪ .‬כל אלו מוכיחים קיום‬
‫בלבד‪.‬‬
‫‪ .2‬היו שניסו להוכיח בשלילה אך התייחסו לחתך בהוכחה‪ .‬אין חתך בהוכחה הזאת בשלילה‪.‬‬
‫ג‪ .‬הטענה נכונה‪ .‬נריץ )‪ Array-to-Heap(A,P‬לקבלת ערימה ‪ P‬ובה איברי המערך ‪ ,A‬ונבצע ‪ n2/3‬קריאות‬
‫)‪ DeleteMin(P‬לקבלת ‪ n2/3‬המספרים הקטנים ביותר‪ .‬זמן הריצה של ‪ Array-to-Heap‬הוא )‪ O(n‬וזמן הריצה‬
‫של כל קריאה ל ‪ DeleteMin‬הוא ))‪ O(log(n‬כך שנקבל את זמן הריצה הנדרש‪.‬‬
‫שגיאות נפוצות‪:‬‬
‫רבים ניסו להוכיח את הטענה ע"י אלגוריתם שלא עושה את המבוקש בזמן המבוקש‪.‬‬
‫‪5‬‬
‫שאלה ‪4‬‬
‫א) נוסחה ‪ 3‬היא הנכונה‪ .‬כיוון ש ‪C[i]  k‬‬
‫‪j‬‬
‫‪‬‬
‫‪i 1‬‬
‫כאשר כל ]‪ C[i‬הוא מספר שלם אי‪-‬שלילי‪ ,‬הרי ש ]‪ C[j‬יכול‬
‫להיות מספר של כלשהו ‪ t‬בין ‪ 0‬ל ‪ .k‬לכל בחירה של ‪ t‬בתחום ערכים אלו‪ ,‬בסכום ]]‪A[i][C[i‬‬
‫‪j 1‬‬
‫בסכום תורם ]‪ , A[j][t‬וכיוון ש ‪C[i]  k  t‬‬
‫‪‬‬
‫‪i 1‬‬
‫‪j‬‬
‫‪‬‬
‫‪i 1‬‬
‫‪ ,‬האיבר ה ‪j‬‬
‫‪ ,‬הסכום המרבי של שאר האיברים הוא )‪ . S(j-1,k-t‬בביטוי‬
‫מספר ‪ 3‬אנו לוקחים את הבחירה של ‪ t‬שנותנת מקסימום של סכום שני איברים אלו‪.‬‬
‫ב) (כל השורות המודגשות הן עבור הסעיף הבא‪).‬‬
‫)‪Min-cost-array(A, n ,m‬‬
‫{‬
‫‪for (k=0 to m) { /* Initialize the first row of the matrix S */‬‬
‫]‪S[1][k] : =A[1][k‬‬
‫‪T[1][k] := k‬‬
‫}‬
‫{ )‪for (j=2 to n‬‬
‫{ )‪for (k=0 to m‬‬
‫‪S[j][k] := S[j-1][k] + A[j][0] /* Initialize with choice of t=0 */‬‬
‫‪T[j[k] := 0‬‬
‫{ )‪for (t=1 to k‬‬
‫]‪new := S[j-1][k-t] + A[j][t‬‬
‫‪if (new > S[j][k]) { /* new setting of t gives better value */‬‬
‫‪S[j][k] := new‬‬
‫‪T[j][k] := t‬‬
‫}‬
‫}‬
‫}‬
‫}‬
‫)]‪return (S[n][m‬‬
‫}‬
‫זמן הריצה‪ O(nm2) :‬כי האתחול לוקח זמן )‪ O(m‬ויש בנוסף שלוש לולאות מקוננות‪ ,‬האחר רצה )‪ O(n‬איטרציות‪,‬‬
‫הבאה )‪ O(m‬איטרציות‪ ,‬וגם השלישית )‪ O(m‬איטרציות‪.‬‬
‫שגיאות נפוצות‪:‬‬
‫‪ .1‬לא בוצע איתחול לשורה הראשונה )‪ .(j=1‬זה גרם לכך שבלולאה המרכזית (אשר רצה מ ‪ )j=1‬הייתה גישה ל‬
‫]‪ S[0][k‬שלא מוגדר (אכן ניתן היה לחילופין להוסיף שורה ‪ 0‬ולאתחל אותה)‪.‬‬
‫‪ .2‬האיתחול של ]‪( S[j][k‬או של משתנה ‪ max‬שבסוף מוצב ב ]‪ )S[j][k‬לא היה נכון‪ .‬בפרט‪ ,‬סטודנטים רבים איתחלו‬
‫אותו ל ‪( 0‬והיו שאיתחלו ל ‪ )-1‬אבל כיוון שאין כל הנחה על הערכים ב ‪( A‬לא נאמר שהם אי שליליים) אז איתחול זה‬
‫שגוי‪.‬‬
‫‪ .3‬היו סטודנטים שהחזירו ערך לא נכון‪.‬‬
‫‪ .4‬היו סטודנטים שהחלק המרכזי של האלגוריתם (הלולאות בהם מחשבים את ערכי ‪ )S‬היה שגוי והיו כמה שניסו‬
‫שניסו לכתוב שילוב בין מימוש איטרטיבי )‪ (bottom-up‬ומימוש רקורסיבי עם זיכרון )‪.(memorization‬‬
‫‪6‬‬
‫ג) נוסיף לקוד של סעיף ב מספר שורות אשר ימלאו עבור כל ‪ j,k‬את אותו ‪ t‬הנותן את המקסימום בביטוי מסעיף א‪.‬‬
‫כלומר נמלא מטריצה ‪ T‬כך ש ‪ , T [ j ][k ]  arg max 0t k S[ j  1][k  t ]  A[ j ][t ]‬ובמקום‬
‫)]‪ return(S[n][m‬נקרא ל )‪ .Print_Best(n,m,T‬זמן הריצה של הפרוצדורה מסעיף ב לא גדל אסימפטוטית (כי‬
‫הוספנו מספר קבוע של פעולות בכל לולאה)‪ .‬זמן הריצה של הפרוצדורה ‪( Print_Best‬כאשר היא נקראת עם‬
‫‪ )j=n,k=m‬הוא )‪ O(n‬כי בכל קריאה רקורסיבית ‪ j‬קטן ב ‪ ,1‬כאשר הוא מתחיל ב ‪ n‬ונעצר כש ‪ ,j=1‬וזמן הריצה של‬
‫כל קריאה (לא כולל קריאות רקורסיביות ממנה)‪ ,‬קבוע‪.‬‬
‫)‪Print_Best(j,k,T‬‬
‫{‬
‫)‪if (j=1‬‬
‫)‪print(k‬‬
‫{ ‪else‬‬
‫)‪Print_Best(j-1, k-T[j][k],T‬‬
‫)]‪print(T[j][k‬‬
‫{‬
‫}‬
‫שגיאות נפוצות‪:‬‬
‫‪ .1‬היו סטודנטים שמילאו נכון (או כמעט נכון) את המטריצה ‪ T‬אך מעבר לכך לא כתבו פתרון נכון‪.‬‬
‫‪ .2‬היו סטודנטים שניסו למלא מערך חד מימדי ‪ ,C‬כאשר במקום השורה ‪ T[j][k]:=t‬שהוספנו לקוד בסעיף ב‪ ,‬הם‬
‫הוסיפו ‪ ,C[j]:=t‬ואז הם הדפיסו את ‪ .C‬זה שגוי כי ב ]‪ C[j‬יהיה תמיד ]‪( T[j][m‬כי ‪ m‬הוא הערך האחרון של ‪k‬‬
‫בלולאה)‪ ,‬וזה לא נותן פתרון נכון‪.‬‬
‫‪7‬‬
‫ת"ז‪:‬‬
‫אוניברסיטת תל‪-‬אביב‬
‫הפקולטה להנדסה‬
‫מועד א' סמסטר ב' תשע"ד במבני נתונים ואלגוריתמים‬
‫זמן המבחן‪ :‬שלוש שעות‬
‫תאריך‪02.6.02.4 :‬‬
‫מרצה‪ :‬דנה רון‬
‫הנחיות‪:‬‬
‫‪‬‬
‫מותר להשתמש בארבעה דפי עזר‪ .‬אין להשתמש בשום סוג של מחשב‪.‬‬
‫‪‬‬
‫המבחן כולל ‪ 4‬שאלות‪ .‬הניקוד על כל שאלה מופיע בסוגריים‪.‬‬
‫כתבו את תשובותיכם על גבי טופס המבחן במקום המוקצה לכך‪ .‬מומלץ מאוד לכתוב תחילה את‬
‫‪‬‬
‫התשובה במחברת הטיוטה שקיבלתם ורק אחר כך להעתיק אותה‪ ,‬בצורה ברורה וקריאה‪ ,‬לטופס המבחן‪.‬‬
‫נמקו בקצרה אך בבהירות את כל טענותיכם‪ .‬טענה ללא נימוק לא תתקבל‪.‬‬
‫‪ ‬מותר להשתמש במשפטים ואלגוריתמים שנלמדו בשיעורים ובתרגולים או שהופיעו בתרגילי הבית‪.‬‬
‫במקרה כזה ניתן לצטט את מה שנלמד ללא צורך בהוכחה‪ .‬לעומת זאת‪ ,‬אם אתם משתמשים בגרסה שונה‬
‫מעט של אלגוריתם או ניתוח כלשהו יש להסביר במדויק מה ההבדלים‪.‬‬
‫‪‬‬
‫במבחן זה ‪ 11‬עמודים (כולל עמוד זה)‪ .‬אנא ודאו שכולם ברשותכם‪.‬‬
‫‪‬‬
‫אל תשכחו לרשום מספר ת"ז במקום המסומן‪.‬‬
‫ב ה צ ל ח ה!‬
‫‪1‬‬
‫שאלה ‪ 02( .‬נק')‬
‫א‪ .0( .‬נק') יהי ‪ Alg‬האלגוריתם הרקורסיבי הבא‪ ,‬המקבל כקלט מערך ‪ A‬של ‪ n‬מספרים ושני אינדקסים ‪.pr‬‬
‫)‪Alg(A,p,r‬‬
‫{‬
‫)‪if (p=r‬‬
‫)‪return(0‬‬
‫‪q = (p+r)/2‬‬
‫‪num := 0‬‬
‫)‪for (i = p to q‬‬
‫)‪for (j = q+1 to r‬‬
‫)]‪if (A[i] > A[j‬‬
‫‪num := num+1‬‬
‫))‪return(num + Alg(A,p,q) + Alg(A,q+1,r‬‬
‫}‬
‫מה מחזיר האלגוריתם כאשר הוא נקרא עם ‪ ?p=1,r=n‬הסבירו בבירור את תשובתכם‪.‬‬
‫________________ _____________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪qt  1‬‬
‫‪. i 0 q ‬‬
‫מהו )‪ g(n‬כך שזמן הריצה של האלגוריתם הוא ))‪ ? (g(n‬במידה ותזדקקו לכך‪ ,‬נזכיר כי‬
‫‪q 1‬‬
‫‪i‬‬
‫‪t‬‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________________________ _____________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫‪2‬‬
‫ב‪ .8( .‬נק') נתון האלגוריתם הבא כאשר ‪ Partition‬ו ‪ MergeSort‬הם כפי שלמדנו בכיתה‪.‬‬
‫‪QMS(A,n,k,p,r) /* A is an array of size n, k<n/2, and 1 p,r  n */‬‬
‫{‬
‫) ‪if (r –p +1  n-k‬‬
‫)‪MergeSort(A,p,r‬‬
‫} ‪else‬‬
‫)‪q := Partition(A,p,r‬‬
‫)‪QMS(A,n,k,p,q‬‬
‫)‪QMS(A,n,k,q+1,r‬‬
‫}‬
‫}‬
‫נסמן את זמן הריצה של ‪ QMS‬כאשר היא נקראת עם ‪ r=n p=1‬ו ‪ k<n/2‬ב )‪ .TQMS(n,k‬בשאלה זו עליכם לנתח מהו‬
‫)‪ g(n,k‬כך ש ))‪ ,TQMS(n,k) = (g(n,k‬לפי השלבים הבאים‪:‬‬
‫(‪ )1‬תארו (בציור) את מבנה עץ הרקורסיה של האלגוריתם (כאשר העלים של העץ מתאימים לקריאות ל‬
‫‪ .)MergeSort‬השתמשו בכך ש ‪( k<n/2‬חישבו כיצד זה משפיע על מבנה העץ‪ ,‬לכל מערך קלט ‪ A‬בגודל ‪.)n‬‬
‫_____________________________________________________________________________________________‬
‫___________________________ __________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫___________________________________ __________________________________________________________‬
‫(‪ )2‬תנו חסם עליון (מנומק) על גובה העץ‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫__________________________ ___________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪3‬‬
‫(‪ )3‬תנו חסם עליון (מנומק) על התרומה הכוללת של העלים (המתאימים לקריאות ל ‪.)MergeSort‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫(‪ )4‬תנו חסם עליון (מנומק) על התרומה הכוללת של הקדקודים הפנימיים‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫______________________________________________ _______________________________________________‬
‫_____________________________________________________________________________________________‬
‫(‪ )5‬כתבו במפורש מהו החסם העליון שקיבלתם והראו שחסם זה הדוק‪ ,‬כלומר‪ ,‬שהוא גם חסם תחתון (על זמן הריצה‬
‫במקרה הגרוע)‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪4‬‬
‫שאלה ‪ .1( 0‬נק')‬
‫נתון עץ בינארי עם משקלים על צלעותיו‪ .‬כלומר‪ ,‬כל קדקוד הוא רשומה עם השדות הבאים‪ ,ID :‬שהוא שם הקדקוד‪,‬‬
‫‪ PAR‬שהוא מצביע להורה של הקדקוד‪ ,LC ,‬שהוא מצביע לילד השמאלי של הקדקוד‪ ,‬ו ‪ ,RC‬שהוא מצביע לילד‬
‫הימני של הקדקוד (אם אין לקדקוד הורה‪/‬ילד ימני ‪ /‬ילד שמאלי אז המצביע המתאים הוא ‪ .)NULL‬בנוסף‪ ,‬יש שני‬
‫שדות נוספים‪ WLC :‬שהוא משקל הצלע בין הקדקוד לילד השמאלי שלו‪ ,‬ו ‪ WRC‬שהוא משקל הצלע בין הקדקוד‬
‫לילד הימני שלו (במקרה ואין כזה ילד‪ ,‬המשקל הוא ‪ .)0‬נאמר שהמשקל המתאים לקדקוד בעץ הוא סכום משקלי‬
‫הצלעות במסלול מהשורש אליו‪ ,‬כאשר המשקל של השורש הוא ‪ .1‬המשקלים בעץ יכולים להיות גם שליליים‪.‬‬
‫כתבו פסאודו‪-‬קוד עבור פרוצדורה המקבלת מצביע לשורש של העץ‪ ,‬והמחזירה את המשקל המינימאלי של קדקוד‬
‫בעץ (אין צורך להחזיר את שם הקדקוד עם משקל זה‪ ,‬אלא רק את המשקל עצמו)‪ .‬לדוגמה‪ ,‬עבור העץ הבא‬
‫הפרוצדורה תחזיר ‪( -2‬המשקל של קדקוד ‪.)d‬‬
‫‪a‬‬
‫‪-1‬‬
‫‪3‬‬
‫‪b‬‬
‫‪c‬‬
‫‪-2‬‬
‫‪-5‬‬
‫‪e‬‬
‫‪d‬‬
‫‪2‬‬
‫‪3‬‬
‫‪g‬‬
‫‪f‬‬
‫הפרוצדורה יכולה לקבל גם פרמטרים נוספים‪ ,‬ויש לציין מה ערכם כאשר היא‬
‫נקראת עם מצביע לשורש העץ‪ .‬מותר לפרוצדורה להשתמש בזיכרון נוסף‬
‫בגודל קבוע‪ ,‬אך לא יותר מכך (בפרט‪ ,‬לא ניתן להשתמש במערך עזר בגודל ‪.)n‬‬
‫הוסיפו הערות לצד הפסאודו‪-‬קוד ונתחו את זמן הריצה של האלגוריתם‬
‫שכתבתם כפונקציה של מספר הקדקודים‪ n ,‬שבעץ‪ .‬ניתן להניח שהשורש‬
‫של העץ אינו ‪.NULL‬‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫_____________________________________________________________________________________‬
‫‪5‬‬
‫שאלה ‪ 04( 0‬נק' (‪ 8‬נק' לכל סעיף))‬
‫על כל אחד מהטענות הבאות ענו האם היא נכונה או שאינה נכונה‪( .‬הסעיפים אינם בונים זה על זה‪).‬‬
‫א‪ .‬לכל ‪ n>1‬קיימים גרפים עם ‪ n‬קדקודים ו )‪ m=(n5/3‬צלעות כך שזמן הריצה של ‪ BFS‬מכל קדקוד התחלה בגרף‬
‫הוא )‪ .(n4/3‬אם תשובתכם חיובית עליכם לתאר את מבנה הגרפים‪ ,‬ואם היא שלילית‪ ,‬עליכם להסביר על בסיס‬
‫תכונות האלגוריתם‪ ,‬מדוע לא קיימים כאלו גרפים‪.‬‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫__________________________________ ___________________________________________________________‬
‫ב‪ .‬יהי ‪ T‬עץ ‪ 2-3‬עם לפחות ‪ 9‬עלים‪ .‬אם מבצעים ‪ Delete‬לעלה ב ‪ T‬כך שלכל האבות הקדמונים של העלה בעץ יש‬
‫שני ילדים‪ ,‬אז גובה העץ בהכרח יקטן ב ‪ .1‬אם תשובתכם חיובית‪ ,‬עליכם לנמק מדוע זה נובע מתכונות ‪ ,Delete‬ואם‬
‫תשובתכם שלילית‪ ,‬עליכם לתת דוגמה נגדית‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫___________________ __________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ ________________________________________________ _____________________________________‬
‫_____________________________________________________________________________________________‬
‫‪6‬‬
‫ג‪ .‬תהי ‪ G‬רשת זרימה ובה לפחות ‪ 8‬קדקודים (כולל ‪ s‬ו ‪ .)t‬אם קיים חתך )‪ ,tT ,sS ,(S,T‬כך שיש בדיוק ‪3‬‬
‫קשתות עם קיבול חיובי החוצות את החתך (כלומר‪ (u,v) ,‬כך ש ‪ vT ,uS‬ו ‪ ,)c(u,v)>0‬אז כאשר אלגוריתם‬
‫פורד‪-‬פלקרסון מסיים את ריצתו‪ ,‬בהכרח יש לפחות ‪ 3‬קשתות רוויות (כלומר‪ ,‬עליהן הזרימה שווה לקיבול)‪ .‬אם‬
‫תשובתכם חיובית‪ ,‬עליכם לנמק מדוע זה נובע מתכונות האלגוריתם‪ ,‬ואם תשובתכם שלילית‪ ,‬עליכם לתת דוגמה‬
‫נגדית‪.‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫____________________ _________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫‪7‬‬
‫שאלה ‪ 0.( 4‬נק')‬
‫נתון מערך ‪ A‬של ‪ n‬מספרים שונים כאשר המערך ‪ A‬ממוין מקטן לגדול‪ .‬כמו כן נתון מערך ‪ w‬בגודל ‪ n‬כך ש ‪w[i]>0‬‬
‫הוא המשקל המיוחס למספר ]‪ .A[i‬עץ חוקי הוא עץ חיפוש בינארי שמכיל את ]‪ A[1],…,A[n‬בקדקודיו‪ .‬לכל עץ‬
‫‪n‬‬
‫חוקי ‪ ,T‬נגדיר את מחיר העץ ) ‪ , c(T‬כ )‪ , c(T )   w[i]  (d ( A[i])  1‬כאשר )]‪ d(A[i‬הוא עומק הקדקוד שמכיל‬
‫‪i 1‬‬
‫את המספר ]‪( A[i‬עומק השורש הוא ‪ ,1‬עומקי ילדיו ‪ ,1‬וכך הלאה)‪ .‬לדוגמה‪ ,‬אם ]‪ A=[10,20,30,40,50‬ו‬
‫]‪ w=[1,5,3,2,2‬אז מחיר העץ‬
‫‪21‬‬
‫‪11‬‬
‫‪41‬‬
‫‪51‬‬
‫הוא‬
‫‪31‬‬
‫‪5‬‬
‫‪ w[i]  (d ( A[i])  1)  1 2  5 1  3  3  2  2  2  3  26‬‬
‫‪i 1‬‬
‫בהינתן כקלט מערכים ‪ A‬ו ‪ ,w‬נהיה מעוניינים למצוא עץ (חוקי) ‪ T‬עם מחיר מינימאלי‪ .‬בשלב ראשון נתעניין במציאת‬
‫המחיר המינימאלי של עץ שכזה‪ .‬לשם כך נגדיר את ]‪ C[i][j‬להיות מחיר העץ האופטימאלי המכיל (רק) את האיברים‬
‫]‪ .A[i],…,A[j‬שימו לב שאם ‪ i > j‬אז ‪.C[i][j]=0‬‬
‫א‪ 1( .‬נק') עבור ‪ ,ij‬איזו מבין הנוסחאות הבאות מתקיימת? נמקו את תשובתכם בקיצור אך בבהירות‪.‬‬
‫הערה חשובה‪ :‬אם לא עניתם נכון בסעיף זה כך שתשתמשו בנוסחה לא נכונה בסעיף הבא‪ ,‬יורדו נקודות רק על סעיף‬
‫זה‪ ,‬והסעיף הבא ייבדק כאילו הנוסחה שנבחרה נכונה‪.‬‬
‫‪j‬‬
‫(‪C[i][ j ]  min it  j C[i][t  1]  C[t  1][ j ]  w[ s] )1‬‬
‫‪s i‬‬
‫‪‬‬
‫‪ j‬‬
‫‪‬‬
‫(‪C[i ][ j ]  min it  j C[i ][t  1]  C[t  1][ j ]   ( w[ s])  w[t ]  )2‬‬
‫‪ si‬‬
‫‪‬‬
‫‪‬‬
‫(‪C[i][ j ]  min it  j C[i][t  1]  C[t  1][ j ]  w[t ] )3‬‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫______________________________________________ _______________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪8‬‬
‫ב‪ .6( .‬נק') כתבו פסאודו‪-‬קוד עבור אלגוריתם המקבל כקלט את ‪ A ,n‬ו ‪ w‬והמחזיר כפלט את מחיר העץ‬
‫האופטימאלי עבור ‪ A‬ו ‪ .w‬זמן הריצה של האלגוריתם צריך להיות פולינומיאלי ב ‪ n‬ועליכם לתת חסם עליון טוב ככל‬
‫האפשר על זמן הריצה של האלגוריתם שלכם‪ .‬לא ניתן לכתוב בקוד שורות ביטויים של מינימום או סכום כגון אלו‬
‫הכתובים בסעיף א' אלא יש לחשב אותם במפורט‪.‬‬
‫_____________________________ ________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________ ________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪9‬‬
‫ג‪ .2( .‬נק') נניח שאנו מעוניינים למצוא לא רק את מחיר העץ האופטימלי‪ ,‬אלא גם להדפיס את הערכים שבקודקודי‬
‫העץ האופטימלי במעבר לפי סדר ‪ .Preorder‬להזכירכם‪ ,‬במעבר לפי סדר זה קודם מודפס השורש ולאחר מכן‬
‫הערכים בתת העץ של הילד השמאלי (לפי סדר ‪ )Preorder‬ולאחר מכן הערכים בתת העץ של הילד הימני (לפי סדר‬
‫‪ .)Preorder‬הוסיפו קוד לאלגוריתם שכתבתם בסעיף הקודם‪ ,‬והוסיפו פרוצדורה אשר נקראת מהאלגוריתם ואשר‬
‫מדפיסה את האיברים שבעץ כנדרש‪ .‬זמן הריצה של האלגוריתם אינו צריך לגדול (אסימפטוטית)‪ .‬מותר להשתמש‬
‫בזיכרון נוסף‪.‬‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫________________________________ _____________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫___ __________________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫________________________________________ _____________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫___________ __________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫________ _____________________________________________________________________________________‬
‫_____________________________________________________________________________________________‬
‫‪11‬‬
‫פתרון מועד א' סמסטר ב' תשע"ד‬
‫שאלה ‪1‬‬
‫א‪ .‬כאשר הוא נקרא עם ‪, p=1, r=n‬האלגוריתם מחזיר את מספר הזוגות )‪ (i,j‬כך ש ‪ 1i<jn‬ו ]‪.A[i]>A[j‬‬
‫הסבר‪ :‬בהינתן ‪ ,p,r‬אם ‪ ,p=r‬כלומר תת המערך בגודל ‪ ,1‬אז אין זוגות שכאלו‪ ,‬והאלגוריתם מחזיר ‪ 0‬כנדרש‪ .‬אחרת‬
‫(‪ ,p<r‬כלומר תת המערך בגודל לפחות ‪ ,)1‬האלגוריתם‪ ,‬בשתי לולאות ה ‪ for‬המקוננות‪ ,‬סופר את מספר הזוגות )‪(i,j‬‬
‫כך ש ‪ ,q+1jr ,piq‬המקיימים ]‪ A[i]>A[j‬ואחר כך קורא רקורסיבית לחישוב מספר הזוגות )‪ (i,j‬כך ש‬
‫‪ pi<jq‬ו ]‪ A[i]>A[j‬ומספר הזוגות )‪ (i,j‬כך ש ‪ q+1i<jr‬ו ]‪ .A[i]>A[j‬ביחד מקבלים את כל הזוגות )‪ (i,j‬כך‬
‫ש ‪ pi<jr‬ו ]‪ ,A[i]>A[j‬ובפרט זה מתקיים עבור ‪ p=1‬ו ‪ ,r=n‬כפי שנטען לעיל‪.‬‬
‫טעויות נפוצות‪ )1( :‬רבים מהסטודנטים תיארו במילים את פעולת האלגוריתם אך לא ענו מפורשות מה מחזיר האלגוריתם‬
‫כאשר נקרא עם ‪ )2( .p=1,r=n‬היו שענו שהאלגוריתם מחזיר את מספר ההחלפות שיש לבצע על מנת שהמערך יהיה‬
‫ממוין‪ .‬אך זה לא מוגדר היטב‪ :‬מספר ההחלפות המתבצעות על ידי איזה אלגוריתם? אפשר היה לקשור זאת ל ‪Insertion-‬‬
‫‪ Sort‬אם חושבים עליו כאילו הוא מבצע החלפה כל פעם שהוא רואה ערך בתת המערך‬
‫]‪ A[1,…,k-1‬הגדול מ ]‪( A[k‬וכך הוא"מחלחל" את ]‪"A[k‬במורד" המערך)‪ ,‬אך זה אלגוריתם ספציפי‪.‬‬
‫זמן הריצה של האלגוריתם מתואר על ידי נוסחת הנסיגה‪ .T(n) = 2T(n/2)+dn2 :‬ניתן להפעיל את משפט המסטר‪:‬‬
‫‪ ,f(n)=dn2 ,a=b=2‬כך ש ‪ ,p=1‬ו )‪ f(n)=(np+1‬וכן )‪ af(n/b)=2d(n/2)2=(1/2)dn2= cf(n‬עבור ‪ ,c<1‬כנדרש‬
‫על ידי המקרה השלישי של משפט המסטר‪ ,‬ומקבלים )‪.T(n)=(f(n))=(n2‬‬
‫ניתן גם לפתור על ידי תיאור עץ הרקורסיה‪ .‬זה עץ בינארי שגובהו )‪ log(n‬כי בכל רמה הגדלים של תתי המערכים‬
‫המתאימים לכל קדקוד ברמה קטנים בפקטור ‪ .2‬ברמה ‪ i‬יש ‪ 2i‬קדקודים‪ ,‬ותרומת כל קדקוד ‪ , d(n/2i)2‬כך שסך כל‬
‫התרומה של הרמה הוא ‪ .dn2/2i‬בשימוש בהנחיה (סכום של סדרה הנדסית) נקבל שתרומת כל הרמות ביחד היא‬
‫)‪.(n2‬‬
‫טעויות נפוצות‪ :‬היו סטודנטים אשר נתנו נוסחת רקורסיה נכונה ופתרו אותה לפי משפט המאסטר אך לא הסבירו כיצד‬
‫הפעילו את משפט המסטר‪ .‬היו שנתנו נוסחה נכונה אך פתרונה היה שגוי‪ .‬רבים מהסטודנטים תיארו עץ רקורסיה נכון אך‬
‫נתנו פתרון לא הדוק של )‪. O(n 2 log n‬‬
‫ב‪ )1( .‬האבחנה המרכזית היא שכיוון ש ‪ k<n/2‬הרי ש ‪ ,n-k>n/2‬ולפי תנאי העצירה של הרקורסיה (הגורם לקריאה‬
‫ל ‪ MergeSort‬ולא להמשך קריאות רקורסיביות לשני חלקים של תת המערך)‪ ,‬לכל קדקוד פנימי בעץ יש לכל היותר‬
‫ילד אחד שהוא קדקוד פנימי (כלומר‪ ,‬מתאים לתת מערך שגודלו יותר מ ‪ .)n-k‬מכאן שצורת העץ היא "מרבה רגליים"‬
‫("שרוך עם רגליים") כדלהלן (כאשר העלים מתאימים לקריאות ל ‪:)MergeSort‬‬
‫…‬
‫‪1‬‬
‫טעויות נפוצות‪ :‬סטודנטים רבים לא התייחסו לכך שהתנאי על ‪ k‬כופה את המבנה של עץ הרקורסיה ותיארו מבנה כללי‬
‫של עץ בינארי‪ .‬היו גם מי שתיארו את המבנה עבור המקרה הפרטי שבו ‪ Partition‬מחלקת את המערך לאיבר יחיד ולכל‬
‫שאר האיברים‪.‬‬
‫(‪ )2‬גובה העץ הוא לכל היותר ‪ .k‬זה מתקיים כי לכל קדקוד פנימי‪ ,‬תתי המערכים שמתאימים לילדיו של הקדקוד‬
‫קטנים ממש (לפחות באחד) מתת המערך שמתאים לו‪ .‬כיוון שהשורש מתאים למערך כולו‪ ,‬שגודלו ‪ ,n‬ותתי מערכים‬
‫בגודל לכל היותר ‪ n-k‬מתאימים לעלים‪ ,‬הרי שגובה העץ (אורך מרבה הרגליים) הוא לכל היותר ‪.k‬‬
‫טעויות נפוצות‪ :‬סטודנטים רבים נתנו את התשובה )‪ .O(n‬אם הנימוק היה נכון‪ ,‬כלומר היה נימוק נכון לכך שגובה העץ‬
‫הוא לכל היותר ‪ k‬וכיוון ש ‪ k<n/2‬גובה העץ הוא לכל היותר ‪ ,n/2‬אז על סעיף זה ניתנו מלוא הנקודות (והורדו רק‬
‫נקודות בשלב הסופי אם הביטוי הסופי לא היה תלוי ב ‪ k‬כפי שדרשנו בשאלה‪ .‬היו מי שלא נימקו את החסם כראוי‪.‬‬
‫היו גם מי שנתנו תשובות שגויות לחלוטין כדוגמת )‪ log(n‬או )‪.n/(n-k‬‬
‫(‪ )3‬כל עלה מתאים לריצת ‪ MergeSort‬על תת מערך‪ ,‬כאשר תתי המערכים זרים זה לזה‪ ,‬וסכום הגדלים שלהם ‪.n‬‬
‫אם נסמן את הגדלים שלהם ב ‪ n1,n2,…,nt‬אזי‪ ,‬לפי מה שידוע לנו על ‪ ,MergeSort‬זמן הריצה הכולל של כל העלים‬
‫)‪ ,∑icnilog(ni)∑i cnilog(n)=cn log(n‬כלומר‪.O(n log n) ,‬‬
‫הוא‬
‫טעויות נפוצות‪ :‬רבים מהסטודנטים טענו שזמן הריצה הוא ))‪ O((n-k)log(n-k‬על בסיס זמן הריצה על העלה המתאים‬
‫לתת המערך הגדול ביותר (ברמה האחרונה של העץ) מבלי להתייחס לתרומת כל העלים‪ .‬היו מי שטענו שהעלים האחרים‬
‫גודלם ‪ 1‬בלי לנמק מדוע זה המקרה שנותן חסם עליון על כל המקרים‪ .‬אמנם אסימפטוטית זה לא משנה כי ‪ , k<n/2‬אך‬
‫‪n‬‬
‫ אך זה כמובן שגוי ( לדוגמא במקרה בו ‪k=n/2-1‬‬‫ההסבר חסר‪ .‬היו סטודנטים שטענו שמספר העלים בעץ הוא‬
‫‪nk‬‬
‫נקבל לפי הנוסחה הזו שהעץ מכיל רק ‪ 2‬עלים)‪.‬‬
‫(‪ )4‬כל קדקוד פנימי מתאים לריצת ‪ Partition‬על תת מערך‪ ,‬כאשר זמן הריצה של ‪ Partition‬ליניארי בגודל תת‬
‫המערך‪ .‬לפי החסם על גובה העץ נקבל )‪.O(nk‬‬
‫טעויות נפוצות‪ :‬תת סעיף זה בונה על תת סעיף (‪ )2‬וכמעט כל הסטודנטים קיבלו עליו את הנקודות בהנחה שציינו נכון‬
‫את זמן ריצתה של ‪ partition‬וכפלו זאת בגובה העץ שנתנו בתת‪-‬סעיף (‪.)2‬‬
‫(‪ )5‬קיבלנו ))‪ .O(nk+nlog(n‬כדי לראות שזהו חסם הדוק‪ ,‬נתבונן במערך ממוין ובו המספרים שונים זה מזה‪.‬‬
‫‪ Partition‬ברמה ה ‪ i‬תפריד את תת המערך לתת מערך בגודל ‪ ,1‬עליו תתבצע קריאה ל ‪ ,MergeSort‬ולתת מערך‬
‫בגודל ‪ .n-i-1‬התרומה של הקדקודים הפנימיים היא )‪( cn+c(n-1)+…+c(n-k)>ck(n/2‬זכרו ש ‪ ,)n-k>n/2‬ותרומת‬
‫העלים היא לפחות כמו תרומה העלה הרחוק היותר מהשורש‪ ,‬כלומר לפחות )‪ ,c(n/2)log(n/2‬וסך הכל נקבל‬
‫))‪ .(nk+n log(n‬כלומר‪ ,‬קיבלנו שזמן הריצה הוא ))‪ (g(n,k‬עבור )‪.g(n,k) = nk+nlog(n‬‬
‫טעויות נפוצות‪ :‬רבים מהסטודנטים לא הוכיחו חסם תחתון כנדרש ‪ -‬על מנת להראות חסם תחתון יש להראות מערך‬
‫אשר משיג את זמן הריצה שהראיתם‪ ,‬ורבים מהסטודנטים לא תיארו מערך כזה‪.‬‬
‫רבים נתנו ביטוי סופי שתלוי רק ב ‪( n‬בפרט‪ ,)(n2) ,‬אך בשאלה נדרשתם במפורש לתת פונקציה )‪ g(n,k‬כך שזמן‬
‫הריצה של האלגוריתם הוא ))‪ ,(g(n,k‬כלומר נדרשתם לתת במפורש את התלות ב ‪ .k‬בפרט‪ ,‬שימו לב שאם )‪k<log(n‬‬
‫(לדוגמה‪ ,)k=loglog(n) ,‬אז זמן הריצה יהיה )‪.(nlog n‬‬
‫‪2‬‬
2 ‫שאלה‬
(pnode) ‫ בשניהם הפרוצדורה מקבל מצביע לקדקוד‬.‫ הנבדלים בתנאי העצירה‬,‫להלן שני פתרונות אפשריים לבעיה‬
‫ אז פשוט‬NULL ‫ אם המצביע אינו‬,‫ בגרסה הראשונה‬. (sum) ‫ואת סכום משקלי הצלעות במסלול מהשורש לקדקוד‬
‫ והמשקלים המינימאליים בתתי העצים‬,‫ שהוא משקל הקדקוד שהגענו אליו‬,sum ‫מחזירים את המינימום בין המשקל‬
‫של ילדיו (אותם מקבלים על ידי קריאות רקורסיביות לילדים כאשר למשקל המצטבר מוסיפים את המשקל על הצלע‬
‫ נשים לב שהמשקל‬,‫ כלומר לילד שאינו קיים‬,NULL ‫ אם הקריאה נעשית עם מצביע שהוא‬.)‫המתחברת לכל ילד‬
‫ זה מבטיח‬.‫ וזה גם הערך המוחזר‬,(0 ‫ (כי כשילד לא קיים אז המשקל על הצלע אליו הוא‬sum+0 ‫המצטבר שנשלח הוא‬
‫ בשביל תשובה נכונה‬0 ‫ ניתן היה למעשה גם להחזיר‬,0 ‫ כיוון שמשקל השורש הוא‬.‫שהמינימום עבור ההורה יהיה נכון‬
‫ אם לקדקוד חסר‬,‫ בגרסה השנייה‬.)‫כאשר קוראים לשורש (הגם שלא היה מוחזר בהכרח המשקל הנכון של כל קדקוד‬
.‫ ולכן העצירה תהיה כשמגיעים לעלה‬,‫ילד (או שניים) אז הקריאות הרקורסיביות לא מתבצעות‬
."‫ישנם פתרונות נוספים אשר אינם שולחים ערך מצטבר לקריאות הרקורסיביות והחישוב נעשה "בחזרה מהרקורסיה‬
.)‫ ניתן היה להשתמש במשתנה גלובאלי לשמירת המינימום (הגם שזה לא הכרחי‬,‫כמו כן‬
Min-Weight-ver1(pnode, sum)
/* Initially the procedure is called with a pointer to the root of the tree and sum=0 */
{
if(pnode = NULL) /* When pnode=NULL, this means that a call was made to a non-existing
child. The value returned is the weight of the parent that made the call */
return(sum)
else /* Return minimum between weight of node and the minimum weight of nodes in the
subtree of the left child and the right child */
return (min(sum,
Min-Weight-ver1(pnodeLC, sum+pnodeWLC),
Min-Weight-ver1(pnodeRC, sum+pnodeWRC)))
}
Min-Weight-ver2(pnode,sum)
/* Initially the procedure is called with a pointer to the root of the tree and sum=0 */
{
min-sum := sum
/* initialize min-sum to sum, which is the weight of the node that pnode points to */
if (pnode  LC != NULL) {
/* Get min weight of node in subtree of left child, and update min-sum if needed */
sum-left := Min-Weight-ver2(pnodeLC,sum+pnodeWLC)
if (sum-left < min-sum)
min-sum := sum-left
}
if (pnode  RC != NULL) {
/* Get min weight of node in subtree of right child, and update min-sum if needed */
sum-right := Min-Weight-ver2(pnodeRC,sum+pnodeWRC)
if (sum-right < min-sum)
min-sum := sum-right
}
return(min-sum)
}
3
‫זמן הריצה של כל אחת מהפרוצדורות ליניארי ב ‪ n‬כי מבקרים בכל קדקוד פעם אחת (ובגרסה השנייה גם יש‬
‫קריאה אחת לכל "ילד חסר" אבל זה רק מגדיל את זמן הריצה פי קבוע)‪ ,‬וזמן הריצה לכל קדקוד (או ילד חסר) קבוע‪.‬‬
‫טעויות נפוצות‪ .1 :‬רבים לא התייחסו למקרה שהמשקל המינימאלי הוא של קדקוד פנימי ולאו דווקא של עלה או‬
‫השורש (כפי שמתקיים בדוגמה שקיבלתם)‪ .‬הקוד המתקבל הוא מאד פשוט‪ ,‬אך לא נכון‪.‬‬
‫‪ .2‬חלק מהסטודנטים לא התייחסו למקרה שלקדקוד עליו מפעילים את הפרוצדורה יש רק ילד אחד‪ ,‬ולא טיפלו במקרה‬
‫שמפעילים את הפונקציה על ‪.NULL‬‬
‫‪ .3‬זמן הריצה הוא ‪ cn‬לכל קלט ולא רק לקלט הגרוע ביותר‪ .‬רבים התייחסו לזמן הריצה כזמן הריצה של הקלט הגרוע‬
‫ביותר ונתנו את דוגמת ה"שרוך" כדי להפוך להדוק‬
‫‪4‬‬
‫שאלה ‪3‬‬
‫א‪ .‬התשובה חיובית‪ .‬אם הגרף מורכב מ ‪ n1/3‬רכיבי קשירות כאשר בכל רכיב יש ‪ n2/3‬קדקודים וכל קדקוד ברכיב‬
‫מחובר לכל קדקוד אחר‪ ,‬אז מספר הצלעות בכל רכיב הוא )‪ .((n2/3)2)=(n4/3‬מכאן מקבלים שמספר הצלעות‬
‫הכולל הוא )‪ ,m=(n1/3n4/.3)=(n5/3‬וזמן הריצה מכל קדקוד התחלה הוא )‪.(n+n4/3)= (n4/3‬‬
‫טעויות נפוצות‪ :‬רבים ענו שהתשובה שלילית כי זמן הריצה תמיד גדל ליניארית עם מספר הצלעות‪ ,‬אך זה מתקיים רק‬
‫כשהגרף קשיר ולא באופן כללי (כפי שהבנייה לעיל מראה)‪.‬‬
‫היו שענו שהתשובה חיובית והסבירו מה צריך להתקיים בגרף‪ ,‬אך לא תיארו את המבנה באופן מלא כנדרש‪ .‬היו גם שענו‬
‫שהתשובה חיובית אך הבנייה שנתנו הייתה שגויה‪ ,‬כך שלא ניתן למעשה נימוק נכון לתשובה‪.‬‬
‫ב‪ .‬התשובה שלילית‪ .‬אם לאחד ההורים הקדמונים יש אח עם שלושה ילדים אז תהליך המחיקה ייעצר‪ .‬לדוגמה‪ ,‬בעץ‪:‬‬
‫‪20‬‬
‫‪15‬‬
‫‪17‬‬
‫‪13‬‬
‫‪9‬‬
‫‪11‬‬
‫‪7‬‬
‫‪3‬‬
‫‪5‬‬
‫אם נבצע )‪( ,Delete(3‬כאשר ‪ 3‬נמצא אכן בקדקוד של הוריו הקדמונים הם שני ילדים)‪ ,‬אז לאחר מחיקתו‪ 5 ,‬ייהפך‬
‫הילד הקטן של ההורה שלו‪ ,‬ו ‪ 7‬יעבור להיות הילד השני‪.‬‬
‫שימו לב‪ :‬הורה קדמון הוא כל קדקוד במסלול בין העלה לשורש (כולל ההורה של העלה)‪.‬‬
‫ג‪ .‬התשובה שלילית‪ .‬לדוגמה‪ ,‬להלן רשת עם ‪ 8‬קדקודים שיש בה חתך בין }‪ S={s‬לשאר הקדקודים שחוצות אותו‬
‫שלוש קשתות עם קיבול חיובי‪ ,‬אבל בסיום ריצת האלגוריתם יש רק קשת אחת רוויה‪( (d,e) ,‬המתאימה לחתך עם‬
‫קיבול מינימאלי‪ .)({s,a,b,c,d},{e,f,t}) :‬להזכירכם‪ ,‬הסימון ‪ x/y‬משמעו שהקיבול ‪ y‬והזרימה ‪ ,x‬ואם מופיע רק‬
‫מספר אחד מעל קשת הרי שהמשמעות היא שזהו הקיבול והזרימה על הקשת היא ‪.0‬‬
‫‪a‬‬
‫‪1/2‬‬
‫‪1/2‬‬
‫‪t‬‬
‫‪1/2‬‬
‫‪f‬‬
‫‪1/2‬‬
‫‪e‬‬
‫‪e‬‬
‫‪1/1‬‬
‫טעויות נפוצות‪ :‬היו סטודנטים שניסו לשלול את הטענה על ידי רשת שאינה עונה‬
‫על דרישות השאלה‪.‬‬
‫‪5‬‬
‫‪d‬‬
‫‪2‬‬
‫‪2‬‬
‫‪b‬‬
‫‪b‬‬
‫‪c‬‬
‫‪2‬‬
‫‪2‬‬
‫‪s‬‬
‫שאלה ‪4‬‬
‫א‪ .‬הנוסחה הנכונה היא הראשונה‪ .‬בעץ המכיל את האברים ]‪ A[i],…,A[j‬אחד מהם בשורש‪ .‬אם זהו ]‪ ,A[t‬אז‪ ,‬עומקו‬
‫‪ 0‬כך שהוא תורם ]‪ .w[t‬בתת העץ של הילד השמאלי שלו נמצאים האברים ]‪ A[i],…,A[t-1‬כאשר העץ האופטימאלי‬
‫עבורם מחירו ]‪ ,C[i][t-1‬וכיוון שהעומק של כל קדקוד בעץ ששורשו ]‪ A[t‬גדול ב ‪ 1‬מהעומק בעץ המכיל את‬
‫האיברים ]‪ A[i],.,A[t-1‬הרי שיש להוסיף את סכום המשקלים שלהם‪ .‬באופן דומה‪ ,‬בתת העץ של הילד הימני נמצאים‬
‫האברים ]‪ ,A[t+1],…,A[j‬תת העץ האופטימאלי עבורם הוא ]‪ C[t+1][j‬ויש להוסיף את משקליהם‪.‬‬
‫הסיבה לכך היא שגובה העץ עם האיברים ]‪ A[i],…,A[j‬גדול באחד מגובה שני תתי העצים שלו ולכן אם מחיר תת‬
‫‪t 1‬‬
‫העץ (השמאלי למשל) הוא )‪ w[s]  (d ( A[s])  1‬‬
‫‪ ,‬בעץ המלא‬
‫‪s i‬‬
‫‪t 1‬‬
‫‪t 1‬‬
‫‪t 1‬‬
‫‪s i‬‬
‫‪s i‬‬
‫‪s i‬‬
‫מחירו ]‪ w[s]  (d ( A[s])  1  1)   w[s]  (d ( A[s])  1)   w[s‬‬
‫‪ .‬באופן דומה עבור תת העץ הימני‪ .‬כמו‬
‫כן‪ ,‬צריך להוסיף את תרומת השורש‪ .w[t] ,‬כלומר‪ ,‬עבור כל ‪ ,t‬המחיר המינימאלי של עץ ששורשו ]‪ A[t‬הוא‬
‫‪t‬‬
‫]‪ , C[i][t  1]  C[t  1][ j ]   w[ s‬וכדי לקבל את העץ האופטימאלי עבור האברים ]‪ A[i],…,A[j‬ניקח את‬
‫‪s 1‬‬
‫המינימום על פני כל האפשרויות של בחירת השורש ]‪.A[t‬‬
‫ב‪( .‬השורה המודגשת היא עבור הסעיף הבא)‪ .‬באלגוריתם יש שימוש במטריצה )‪ .(n+1)x(n+1‬אפשר היה גם‬
‫להשתמש במטריצה ‪ nxn‬ולטפל לחוד במקרים ‪ t=i=1‬ו ‪. t=j=n‬‬
‫)‪Cost(n,A,w‬‬
‫{‬
‫)‪for (i=1 to n+1‬‬
‫)‪for (j = 0 to i-1‬‬
‫‪C[i][j] := 0 /* Actually suffices to initialize C[i][i-1] to 0 for all i */‬‬
‫‪for (d = 0 to n-1) /* Fill matrix C, diagonal by diagonal */‬‬
‫{ )‪for (i = 1 to n-d‬‬
‫‪j := i+d‬‬
‫‪sum := 0‬‬
‫‪for (s = i to j) /* Compute w[i]+…+w[j] */‬‬
‫]‪sum := sum+w[s‬‬
‫‪C[i][j] := ‬‬
‫‪for (t = i to j) { /* Compute cost for opt tree with A[t] in root */‬‬
‫‪new-cost := C[i][t-1]+C[t+1][j] + sum‬‬
‫{ )]‪if (new-cost < C[i][j‬‬
‫} ‪C[i][j] := new-cost; T[i][j] := t‬‬
‫}‬
‫}‬
‫)]‪return (C[1][n‬‬
‫}‬
‫זמן הריצה של האלגוריתם הוא )‪ .O(n3‬ראשית יש אתחול שרץ בזמן )‪ .O(n2‬אחר כך יש שתי לולאות זו בתוך זו‬
‫כאשר כל אחת רצה לכל היותר ‪ n‬איטרציות (האחת על ‪ d‬והשניה על ‪ ,)i‬ובתוך הפנימית יש עוד שתי לולאות שכאלו‬
‫אחת אחרי השנייה (האחת על ‪ s‬והשנייה על ‪.)t‬‬
‫‪6‬‬
‫טעויות נפוצות‪:‬‬
‫טעות משמעותית אחת הייתה לבצע את החישוב לפי סדר שגוי‪ ,‬כלומר שלא מקיים את התנאי שכאשר מחשבים את‬
‫]‪ C[i][j‬אז ]‪ C[i][t-1‬ו ]‪ C[t+1][j‬חושבו כבר לכל ‪ t‬בין ‪ i‬לבן ‪.j‬‬
‫היו גם בעיות עם אתחול חסר של ]‪ C[i][i-1‬שגורם לשגיאה בחישוב‪.‬‬
‫היו מעטים שהחזירו ערך לא נכון והיו כמה שטעו בחישוב זמן הריצה או שלא חישבו אותו‪.‬‬
‫ג‪ .‬נוסיף את השורה המודגשת בקוד של סעיף ב‪ ,‬כאשר ]‪ T[i][j‬זהו אותו ‪ t‬בין ‪ i‬ל ‪ j‬שנותן את המינימום בביטוי‬
‫שבסעיף הראשון‪ .‬כלומר‪ A[T[i][j]] ,‬הוא השרש האופטימאלי בעץ עבור ]‪( .A[i],…,A[j‬שימו לה שעבור זוגות‬
‫‪ ,i=j‬כלומר‪ ,‬כש ‪ ,d=0‬נקבל ‪ ).t=i=j‬כמו כן‪ ,‬במקום לעשות )]‪ ,return(C[1][n‬נקרא ל )‪,Print-Tree(1,n,A,T‬‬
‫כאשר ‪ Print-Tree‬היא הפרוצדורה הבאה‪.‬‬
‫)‪Print-Tree(i,j,A,T‬‬
‫{‬
‫]‪t := T[i][j‬‬
‫‪/* A[t] is in the root of the opt tree for A[i],…,A[j] */‬‬
‫)]‪Print(A[t‬‬
‫)‪if (t-1  i‬‬
‫‪/* A[t] has a left child (whose subtree contains A[i],…,A[t-1]) */‬‬
‫)‪Print-Tree(i,t-1,T‬‬
‫)‪if (t+1j‬‬
‫‪/* A[t] has a right child (whose subtree contains A[t+1],…,A[j]) */‬‬
‫)‪Print_tree)t+1,j,T‬‬
‫}‬
‫טעויות נפוצות‪ :‬היו סטודנטים לא מעטים שרק מלאו את מטריצת העזר כנדרש אך כתבו פרוצדורה שגויה לגמרי‪.‬‬
‫היו מי שלא דאגו לתנאי עצירה לרקורסיה‪ ,‬והיו טעויות קטנות יותר בקריאות הרקורסיביות‪.‬‬
‫‪7‬‬