שיעור במבני נתונים ויעילות אלגוריתמים מיום ד

‫מכללת אורט כפר‪-‬סבא‬
‫מבני נתונים‬
‫ויעילות אלגוריתמים‬
‫מימוש עץ בינארי בסביבת העבודה‬
‫ייצוג ביטוי חשבוני באמצעות עץ בינארי‬
‫סריקת עץ בינארי לפי רמות‬
‫מציאת זוג איברים במערך ממוין שסכומם נתון‬
‫‪24.12.14‬‬
‫אורי וולטמן‬
‫‪[email protected]‬‬
‫חידה לחימום‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫יש מאה חכמים שעומדים בטור‪ :‬החכם האחרון בטור רואה את כל החכמים‬
‫שלפניו‪ ,‬החכם הלפני‪-‬אחרון רואה את כולם פרט לאחרון‪ ,‬וכך הלאה – עד‬
‫לחכם העומד בראש הטור‪ ,‬שלא רואה איש‪.‬‬
‫כל חכם חובש כובע בצבע לבן או שחור‪ .‬כל חכם יודע את צבעי הכובעים של‬
‫כל האנשים העומדים לפניו בטור‪ ,‬אולם הוא אינו יודע את צבע כובעו שלו‪.‬‬
‫אדם מסוים עובר על פני הטור ושואל כל אחד ממאה החכמים‪ ,‬מה צבע‬
‫הכובע שעל ראשו‪ .‬לחכם מותר לענות רק "שחור" או "לבן"‪.‬‬
‫הראשון שנשאל הוא החכם העומד אחרון בטור‪ ,‬ומשם ממשיכים לפי הסדר‪,‬‬
‫עד לחכם העומד בראש הטור‪.‬‬
‫אותם חכמים ששוגים כאשר הם נשאלים לגבי צבע כובעם – מוצאים להורג‪.‬‬
‫מצאו אסטרטגיה בה יש לנקוט כדי להבטיח שכמה שיותר מהחכמים ישרדו‪.‬‬
‫מימוש עץ בינארי‬
‫‪‬‬
‫‪‬‬
‫מימוש טבעי לטנ"מ עץ בינארי יעשה שימוש בחוליה‪ ,‬אשר תכיל שדה ערך‬
‫(‪ ,)info‬בדומה לחוליה ברשימה מקושרת‪.‬‬
‫להבדיל מברשימה מקושרת‪ ,‬כאן יכיל כל צומת שני מצביעים‪ left :‬ו‪,right-‬‬
‫המצביעים לתת‪-‬עץ השמאלי ולתת‪-‬עץ הימני‪ ,‬בהתאמה‪:‬‬
‫;‪typedef int tree_item‬‬
‫{ ‪struct node_type‬‬
‫;‪tree_item info‬‬
‫;‪struct node_type *left, *right‬‬
‫;}‬
‫‪‬‬
‫נגדיר עץ בינארי בתור מצביע למבנה הזה‪:‬‬
‫;‪typedef struct node_type *tree‬‬
‫עץ בינארי‬
‫‪‬‬
‫תזכורת – אלו הן פעולות הממשק של טנ"מ 'עץ בינארי'‪:‬‬
‫אתחל‪-‬עץ‬
‫פעולה המחזירה עץ בינארי ריק‬
‫בנה‪-‬עץ )‪(L,R,x‬‬
‫פעולה המחזירה עץ בינארי שבשורשו האיבר ‪ ,x‬התת‪-‬עץ‬
‫השמאלי שלו ‪ ,L‬והתת‪-‬עץ הימני שלו ‪.R‬‬
‫הנחות‪ :‬העצים ‪ L‬ו‪ R-‬מאותחלים‪.‬‬
‫תת‪-‬עץ‪-‬שמאלי )‪(T‬‬
‫פעולה המחזירה את התת‪-‬עץ השמאלי של ‪.T‬‬
‫הנחות‪ T :‬מאותחל ואינו ריק‪.‬‬
‫תת‪-‬עץ‪-‬ימני )‪(T‬‬
‫פעולה המחזירה את התת‪-‬עץ הימני של ‪.T‬‬
‫הנחות‪ T :‬מאותחל ואינו ריק‪.‬‬
‫החלף‪-‬תת‪-‬עץ‪-‬שמאלי‬
‫)‪(T,new_tree‬‬
‫פעולה המחליפה את התת‪-‬עץ השמאלי של ‪ T‬בעץ הבינארי‬
‫‪.new_tree‬‬
‫הנחות‪ :‬העצים ‪ T‬ו‪ new_tree -‬מאותחלים‪ T ,‬איננו ריק‪.‬‬
‫עץ בינארי‬
‫‪‬‬
‫תזכורת – אלו הן פעולות הממשק של טנ"מ 'עץ בינארי'‪:‬‬
‫החלף‪-‬תת‪-‬עץ‪-‬ימני‬
‫)‪(T,new_tree‬‬
‫פעולה המחליפה את התת‪-‬עץ הימני של ‪ T‬בעץ הבינארי‬
‫‪.new_tree‬‬
‫הנחות‪ :‬העצים ‪ T‬ו‪ new_tree -‬מאותחלים‪ T ,‬איננו ריק‪.‬‬
‫אחזר‪-‬שורש )‪(T‬‬
‫פעולה המחזירה את האיבר שבשורשו של ‪ .T‬הנחות‪T :‬‬
‫מאותחל ואיננו ריק‪.‬‬
‫עדכן‪-‬שורש )‪(T,x‬‬
‫פעולה המשנה את התוכן של שורש ‪ T‬להיות ‪.x‬‬
‫הנחות‪ T :‬מאותחל ואיננו ריק‬
‫עץ‪-‬ריק?)‪(T‬‬
‫פעולה המחזירה 'אמת' אם העץ הבינארי ‪ T‬הוא עץ ריק‪,‬‬
‫ו'שקר' אחרת‪.‬‬
‫הנחה‪ T :‬מאותחל‪.‬‬
‫מימוש עץ בינארי‬
:tree.h-‫נתונות הכותרות של הפונקציות ב‬
tree tree_init (void);
tree tree_build (tree lsub, tree rsub, tree_item data);
tree tree_lsub (tree t);
tree tree_rsub (tree t);
void tree_change_lsub (tree *t, tree new_tree);
void tree_change_rsub (tree *t, tree new_tree);
tree_item tree_root_retrieve (tree t);
void tree_root_modify (tree *t, tree_item data);
int tree_empty (tree t);

‫מימוש עץ בינארי‬
:tree.c ‫ובקובץ המימוש‬
tree tree_init (void)
{
return NULL;
}
tree tree_build (tree lsub, tree rsub, tree_item data)
{
tree t;
t = malloc(sizeof(struct node_type));
t->info = data;
t->left = lsub;
t->right = rsub;
return t;
}

‫מימוש עץ בינארי‬
tree tree_lsub (tree t)
{
return t->left;
}
tree tree_rsub (tree t)
{
return t->right;
}
‫ נכתוב‬,tree_change_lsub -‫ ו‬tree_change_rsub ‫לצורך מימוש פעולות הממשק‬
:‫ המקבלת מצביע לעץ ומשחררת את כל צמתיו‬,tree_delete ‫פונקצית עזר בשם‬
void tree_delete (tree *t)
{
if (!tree_empty(*t))
{
tree_delete(&((*t)->left));
tree_delete(&((*t)->right));
free(*t);
}
}

‫מימוש עץ בינארי‬
void tree_change_lsub (tree *t, tree new_tree)
{
tree_delete(&((*t)->left));
(*t)->left = new_tree;
}
.right-‫ מוחלף ב‬left-‫ פרט לכך ש‬,‫ זהה לגמרי‬tree_change_rsub ‫הפונקציה‬
tree_item tree_root_retrieve (tree t)
{
return t->info;
}
void tree_root_modify (tree *t, tree_item data)
{
(*t)->info = data;
}
int tree_empty (tree t)
{
return (t == NULL);
}
‫מה סיבוכיות זמן‬
‫הריצה של כל אחת‬
?‫מפעולות הממשק‬

‫עץ ביטוי בינארי‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫לעיתים קרובות‪ ,‬כאשר קומפיילר נתקל בביטוי חשבוני בעת סריקה של קוד מקור‬
‫בשפת תכנות‪ ,‬הוא מייצג את הביטוי החשבוני באמצעות עץ בינארי‪.‬‬
‫נניח שמדובר בביטוי המורכב ממספרים חד‪-‬ספרתיים שיקראו אופרנדים‬
‫(‪ ,)operands‬ומפעולות החשבון הבסיסיות ‪ -‬חיבור‪ ,‬חיסור‪ ,‬כפל וחילוק ‪-‬‬
‫הנקראות אופרטורים (‪.)operators‬‬
‫כמו כן‪ ,‬כדי לחסוך את הטיפול בקדימויות שבין האופרטורים‪ ,‬נניח שהביטוי‬
‫החשבוני "ממוסגר לחלוטין"‪ ,‬כלומר ‪ -‬סביב כל אופרטור ושני האופרנדים שעליהם‬
‫הוא פועל‪ ,‬מופיעים סוגריים‪ .‬נסכים גם כי האופרנדים תמיד יהיו אי‪-‬שליליים‪.‬‬
‫קבעו אילו מהביטויים החשבוניים‬
‫הבאים הם "ממוסגרים לחלוטין"‪:‬‬
‫עץ ביטוי בינארי‬
‫‪‬‬
‫נגדיר באופן פורמלי‪:‬‬
‫‪A‬‬
‫ביטוי חשבוני הוא‪:‬‬
‫)‪(X op Y‬‬
‫או‪:‬‬
‫‪‬‬
‫‪‬‬
‫כאשר ‪ A‬הוא אופרנד‬
‫כאשר ‪ X‬ו‪ Y-‬הם ביטויים חשבוניים ו‪ op-‬הוא‬
‫אופרטור‪.‬‬
‫נשים לב כי זו הגדרה רקורסיבית‪ X .‬ו‪ Y-‬הם ביטויים חשבוניים בעצמם‪.‬‬
‫כיצד נייצג ביטויים כאלה?‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫אם נעיין בהגדרה של עץ בינארי‪ ,‬נראה דימיון ברור להגדרה של ביטוי חשבוני‪ .‬לכן‪,‬‬
‫טבעי לייצג ביטוי חשבוני באמצעות עץ בינארי‪.‬‬
‫צומת בעץ יוכל להכיל אחד משני סוגי נתונים‪ :‬אופרטור או אופרנד‪.‬‬
‫צומת עם בנים יכיל אופרטור‪ ,‬שאותו צריך להפעיל על הביטויים‬
‫המיוצגים על‪-‬ידי התת‪-‬עצים השמאלי והימני של אותו הצומת‪.‬‬
‫עלים בעץ יכילו אופרנדים‪.‬‬
‫עץ ביטוי בינארי‬
‫‪‬‬
‫נביט בדוגמאות הבאות‪ ,‬לעצים בינאריים המייצגים ביטויים חשבוניים‪:‬‬
‫‪‬‬
‫כיצד ייוצג הביטוי ) ) ‪? ( ( 4 + ( 7 * 8 ) ) – ( 9 / 3‬‬
‫עץ ביטוי בינארי‬
‫‪‬‬
‫נכתוב אלגוריתם רקורסיבי המקבל עץ בינארי מאותחל ולא ריק ‪ ,T‬המייצג‬
‫ביטוי חשבוני‪ ,‬ומחשב את ערכו של הביטוי‪ .‬האלגוריתם יעשה שימוש‬
‫במשתנים ‪ r_val‬ו‪ l_val-‬שיאחסנו ערכים מספריים‪ ,‬ובמשתנה ‪op‬‬
‫שיאחסן אופרטור‪.‬‬
‫חשב‪-‬ערך‪-‬ביטוי (‪)T‬‬
‫אם עלה? (‪ , )T‬אזי‪:‬‬
‫החזר את אחזר‪-‬שורש (‪)T‬‬
‫אחרת‪:‬‬
‫חשב‪-‬ערך‪-‬ביטוי (תת‪-‬עץ‪-‬שמאלי (‪l_val  ) )T‬‬
‫חשב‪-‬ערך‪-‬ביטוי (תת‪-‬עץ‪-‬ימני (‪r_val  ) )T‬‬
‫אחזר‪-‬שורש (‪op  )T‬‬
‫החזר את )‪)l_val op r_val‬‬
‫עץ ביטוי בינארי‬
‫‪‬‬
‫מהו ערכו של עץ הביטוי הבא?‬
‫*‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪1‬‬
‫‪+‬‬
‫*‬
‫‪8‬‬
‫‪1‬‬
‫‪4‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪1‬‬
‫‪+‬‬
‫*‬
‫‪8‬‬
‫‪1‬‬
‫‪4‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪1‬‬
‫‪+‬‬
‫*‬
‫‪8‬‬
‫‪1‬‬
‫‪4‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪1‬‬
‫‪+‬‬
‫*‬
‫‪8‬‬
‫‪1‬‬
‫‪4‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪1‬‬
‫‪+‬‬
‫*‬
‫‪8‬‬
‫‪1‬‬
‫‪4‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪1‬‬
‫‪+‬‬
‫*‬
‫‪8‬‬
‫‪1‬‬
‫‪4‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪1‬‬
‫‪+‬‬
‫‪8‬‬
‫‪4‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪1‬‬
‫‪+‬‬
‫‪8‬‬
‫‪4‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪12‬‬
‫‪1‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪12‬‬
‫‪1‬‬
‫עץ ביטוי בינארי‬
‫‪12‬‬
‫עץ ביטוי בינארי‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫לאחר שראינו כיצד אפשר לחשב את ערכו של ביטוי חשבוני המיוצג באמצעות‬
‫עץ‪ ,‬נפנה לאלגוריתם הבונה עץ שכזה‪.‬‬
‫האלגוריתם הרקורסיבי בנה‪-‬עץ‪-‬ביטוי מקבל כקלט ביטוי חשבוני בתור מחרוזת‬
‫תווים‪ ,‬ומחזיר את העץ הבינארי המתאים‪.‬‬
‫האלגוריתם יקרא את תווי הקלט זה אחרי זה‪.‬‬
‫‪‬‬
‫‪‬‬
‫אם התו הנקרא הוא אופרנד‪ ,‬נבנה עלה המכיל אותו‪.‬‬
‫אם התו הוא סוגר שמאלי‪ ,‬זוהי תחילתו של ביטוי חשבוני מהצורה (‪ ,)X op Y‬ואז‬
‫יבוצעו הפעולות האלה‪:‬‬
‫‪ .1‬בניית עץ המתאים לביטוי החשבוני השמאלי ‪ ,X‬באמצעות קריאה רקורסיבית לבנה‪-‬עץ‪-‬ביטוי‪.‬‬
‫‪ .2‬קריאת התו הבא (שחייב להיות אופרטור)‪.‬‬
‫‪ .3‬בניית עץ המתאים לביטוי החשבוני הימני ‪ ,Y‬באמצעות קריאה רקורסיבית לבנה‪-‬עץ‪-‬ביטוי‪.‬‬
‫‪ .4‬בניית עץ ששורשו ‪ op‬והתת‪-‬עצים השמאלי והימני שלו הם‪ ,‬בהתאמה‪ ,‬העצים שנבנו על פי‬
‫הביטויים החשבוניים ‪ X‬ו‪.Y-‬‬
‫‪‬‬
‫משנסתיימה בניית העץ המתאים לביטוי שבתוך הסוגריים‪ ,‬התו הבא במחרוזת צריך‬
‫להיות סוגר ימני‪.‬‬
‫עץ ביטוי בינארי‬
‫‪‬‬
‫נניח כי הביטוי שמתקבל בקלט הוא ביטוי חשבוני תקין‪ .‬האלגוריתם יעשה שימוש‬
‫במשתנים ‪ T1 ,T‬ו‪ T2-‬שהם עצים‪ ,‬ובתו ‪.ch‬‬
‫בנה‪-‬עץ‪-‬ביטוי‬
‫קרא תו ‪ch‬‬
‫אם ‪ ch‬הוא ספרה‪ ,‬אזי‪:‬‬
‫בנה‪-‬עץ (‪ ,ch‬אתחל‪-‬עץ‪ ,‬אתחל‪-‬עץ) ‪T ‬‬
‫אחרת‪ ,‬אם ‘(‘ = ‪ ,ch‬אזי‪:‬‬
‫בנה‪-‬עץ‪-‬ביטוי ‪T1 ‬‬
‫קרא תו ‪ch‬‬
‫בנה‪-‬עץ‪-‬ביטוי ‪T2 ‬‬
‫בנה‪-‬עץ (‪T  )T1, T2, ch‬‬
‫קרא תו ‪ch‬‬
‫החזר את ‪T‬‬
‫‪‬‬
‫האם התנאי שמופיע מיד לאחר ה‪"-‬אחרת" הוא הכרחי?‬
‫עץ ביטוי בינארי‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫= ‪ch‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫(= ‪ch‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫(==‪ch‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫((==‪ch‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫( (==‬
‫‪ch‬‬
‫= ‪ch‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫( (==‬
‫‪ch‬‬
‫‪ch =3‬‬
‫‪3‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫((==‪ch‬‬
‫‪3‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫(‪ch==-‬‬
‫‪3‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫ (==‬‫‪ch‬‬
‫= ‪ch‬‬
‫‪3‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫ (==‬‫‪ch‬‬
‫‪ch =2‬‬
‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫(‪ch==-‬‬
‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫(‪ch==-‬‬
‫‬‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫(= ‪ch‬‬
‫‬‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*= ‪ch‬‬
‫‬‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫*==‪ch‬‬
‫‬‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫*(==‪ch‬‬
‫‬‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫(*==‬
‫‪ch‬‬
‫= ‪ch‬‬
‫‬‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫(= ‪ch‬‬
‫‬‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫‪ch‬‬
‫(==‪ch‬‬
‫‬‫‪2‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫‪ch‬‬
‫(‬
‫‪ch==4‬‬
‫‬‫‪2‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫(= ‪ch‬‬
‫‬‫‪2‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫*= ‪ch‬‬
‫‬‫‪2‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫‪ch‬‬
‫*==‪ch‬‬
‫‬‫‪2‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫‪ch‬‬
‫*‬
‫‪ch==1‬‬
‫‬‫‪2‬‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫*= ‪ch‬‬
‫‬‫‪2‬‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫**==‬
‫‪ch‬‬
‫*= ‪ch‬‬
‫‬‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫*(==‪ch‬‬
‫‬‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫*‬
‫‪ch==+‬‬
‫‬‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫‪==*+‬‬
‫‪ch‬‬
‫= ‪ch‬‬
‫‬‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫‪==*+‬‬
‫‪ch‬‬
‫‪ch =8‬‬
‫‬‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫*‬
‫‪ch==+‬‬
‫‬‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪ch‬‬
‫*‬
‫‪ch==+‬‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*= ‪ch‬‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫*= ‪ch‬‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫*‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫))‪((3-2)*((4*1)+8‬‬
‫‪3‬‬
‫עץ ביטוי בינארי‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫נביט בעץ הביטוי הבינארי הבא‪.‬‬
‫הביטוי שיתקבל בעקבות סריקה בסדר תחילי (‪ )preorder traversal‬של העץ‪,‬‬
‫הוא ביטוי תחילי (‪ )prefix expression‬המתאים לביטוי החשבוני המקורי‪.‬‬
‫הביטוי שיתקבל בעקבות סריקה בסדר תוכי (‪ )inorder traversal‬של העץ‪ ,‬הוא‬
‫ביטוי תוכי (‪ )infix expression‬הזהה לביטוי המקורי (אך ללא סוגריים)‪.‬‬
‫הביטוי שיתקבל בעקבות סריקה בסדר סופי‬
‫*‬
‫(‪ )postorder traversal‬של העץ‪ ,‬הוא ביטוי‬
‫סופי (‪ )postfix expression‬המתאים לביטוי‬
‫החשבוני המקורי‪.‬‬
‫‪-‬‬
‫‪+‬‬
‫‪8‬‬
‫‪2‬‬
‫*‬
‫‪1‬‬
‫‪4‬‬
‫‪3‬‬
‫עץ בינארי‬
‫‪‬‬
‫בעיה אלגוריתמית‪ :‬פתחו אלגוריתם המקבל ביטוי חשבוני ממוסגר‬
‫לחלוטין ומחשב את ערכו‪.‬‬
‫‪‬‬
‫‪‬‬
‫בעיה אלגוריתמית‪ :‬פתחו אלגוריתם המקבל ביטוי חשבוני‪ ,‬ממוסגר‬
‫לחלוטין‪ ,‬ומחזיר ביטוי סופי (‪ )postfix‬מתאים‪.‬‬
‫‪‬‬
‫‪‬‬
‫האם תוכלו להיעזר באלגוריתמים שכבר הכרנו כדי להרכיב אלגוריתם הפותר בעיה‬
‫זו?‬
‫האם תוכלו להיעזר באלגוריתמים שכבר הכרנו כדי להרכיב אלגוריתם הפותר בעיה‬
‫זו?‬
‫בעיה אלגוריתמית‪ :‬פתחו אלגוריתם המקבל ביטוי חשבוני‪ ,‬ממוסגר‬
‫לחלוטין‪ ,‬ומחזיר ביטוי תחילי (‪ )prefix‬מתאים‪.‬‬
‫‪‬‬
‫האם תוכלו להיעזר באלגוריתמים שכבר הכרנו כדי להרכיב אלגוריתם הפותר בעיה‬
‫זו?‬
‫רמות בעץ בינארי ‪ -‬תזכורת‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫רמה (‪ )level‬של צומת מסוים בעץ היא אורך המסלול מהשורש אל צומת זה‪,‬‬
‫כלומר – המרחק של הצומת מהשורש‪.‬‬
‫רמת השורש היא ‪ ,0‬והרמה של כל צומת אחר בעץ גדולה באחד מהרמה של‬
‫ההורה שלו‪.‬‬
‫גובה עץ (‪ )tree height‬הוא המרחק הגדול ביותר מהשורש לעלה כלשהו של‬
‫העץ‪ ,‬כלומר – זוהי הרמה הגבוהה ביותר של העץ‪.‬‬
‫מעוניינים‬
‫לסרוק את‬
‫איברי העץ‬
‫לרוחב‪ ,‬ולא‬
‫לעומק‪.‬‬
‫כלומר –‬
‫לסרוק לפי‬
‫רמות‪.‬‬
‫סריקה לפי רמות‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫תחילה נבקר ב‪ ,A-‬ואחר כך בשני בניו‪ D ,‬ו‪.H-‬‬
‫לאחר הביקור ב‪ H-‬עלינו לבקר ב‪ ,E-‬איך כיצד נעבור מהצומת ‪ H‬ל‪ ?E-‬הרי באמצעות‬
‫פעולות הממשק שהגדרנו‪ ,‬ניתן לגשת לבן רק מאביו‪.‬‬
‫כדי לבצע את המעברים הללו‪ ,‬נשמור את הצמתים שטיפלנו בהם בתור‪ ,‬המכיל את‬
‫תת‪-‬העצים שטרם נסרקו‪.‬‬
‫תחילה נכניס לתור הריק את העץ כולו‪ .‬נמשיך על‪-‬ידי הוצאת העץ שבראש התור‪,‬‬
‫והכנסת שני התת‪-‬עצים של עץ זה לסוף התור‪ ,‬ונמשיך כך עד שיתרוקן התור‪.‬‬
‫בכל פעם שנוציא‬
‫עץ מהתור‪ ,‬נבקר‬
‫בשורשו‪.‬‬
‫סריקה לפי רמות‬
‫‪‬‬
‫להלן האלגוריתם המקבל עץ בינארי ‪ ,T‬וסורק את צמתי העץ‪ ,‬לפי רמות‪,‬‬
‫משמאל לימין‪ .‬האלגוריתם עושה שימוש בתור ‪ Q‬של עצים‪.‬‬
‫סרוק‪-‬לפי‪-‬רמות (‪)T‬‬
‫אתחל‪-‬תור ‪Q ‬‬
‫אם לא עץ‪-‬ריק? (‪ , )T‬אזי‪:‬‬
‫הכנס‪-‬לתור (‪)Q,T‬‬
‫כל עוד לא תור‪-‬ריק? (‪ , )Q‬בצע‪:‬‬
‫הוצא‪-‬מתור (‪T1  )Q‬‬
‫בקר בשורש של ‪T1‬‬
‫אם לא עץ‪-‬ריק? (תת‪-‬עץ‪-‬שמאלי (‪ , ))T1‬אזי‪:‬‬
‫הכנס‪-‬לתור (תת‪-‬עץ‪-‬שמאלי (‪)Q,)T1‬‬
‫אם לא עץ‪-‬ריק? (תת‪-‬עץ‪-‬ימני (‪ , ))T1‬אזי‪:‬‬
‫הכנס‪-‬לתור (תת‪-‬עץ‪-‬ימני (‪)Q,)T1‬‬
‫‪‬‬
‫הסבירו מדוע סיבוכיות זמן הריצה של אלגוריתם זה היא לינארית‪.‬‬
‫סריקה לפי רמות‬
‫‪A‬‬
‫‪H‬‬
‫‪Y‬‬
‫‪D‬‬
‫‪G‬‬
‫‪B‬‬
‫‪E‬‬
‫‪Z‬‬
‫‪T‬‬
‫סריקה לפי רמות‬
‫‪A‬‬
‫‪H‬‬
‫‪Y‬‬
‫‪D‬‬
‫‪G‬‬
‫‪B‬‬
‫‪A‬‬
‫‪E‬‬
‫‪Z‬‬
‫‪T‬‬
‫סריקה לפי רמות‬
A
D
D,H
E
T
A
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
H,E,G
E
T
A,D
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
E,G,Y
E
T
A,D,H
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
G,Y,T
E
T
A,D,H,E
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
Y,T,Z,B
E
T
A,D,H,E,G
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
T,Z,B
E
T
A,D,H,E,G,Y
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
Z,B
E
T
A,D,H,E,G,Y,T
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
B
E
T
A,D,H,E,G,Y,T,Z
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
E
T
A,D,H,E,G,Y,T,Z,B
H
G
Z
Y
B
‫סריקה לפי רמות‬
A
D
E
T
A,D,H,E,G,Y,T,Z,B
H
G
Z
Y
B
‫מציאת זוג איברים במערך שסכומם נתון‬
‫‪‬‬
‫נתון מערך ממוין ‪ a‬המכיל ‪ n‬מספרים‪ ,‬ונתון מספר נוסף ‪ .x‬המטרה היא‬
‫לפתח אלגוריתם שייקבע האם קיימים במערך שני איברים שונים שסכומם‬
‫הוא ‪ .x‬לדוגמא‪ ,‬עבור המערך ‪ a‬הבא (שמקיים ‪:)n = 8‬‬
‫‪20‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪18‬‬
‫‪15‬‬
‫‪8‬‬
‫‪7‬‬
‫‪4‬‬
‫אם ‪ ,x = 11‬אז האלגוריתם ידפיס תשובה חיובית‪.‬‬
‫אם ‪ ,x = 13‬אז האלגוריתם ידפיס תשובה שלילית‪.‬‬
‫אם ‪ ,x = 35‬אז האלגוריתם ידפיס תשובה חיובית‪.‬‬
‫‪3‬‬
‫‪1‬‬
‫מציאת זוג איברים במערך שסכומם נתון‬
‫פתרון ראשון‪ :‬נעבור‪ ,‬בעזרת שתי לולאות ‪ ,for‬על כל זוגות האיברים‬
‫במערך‪ ,‬ונבדוק עבור כל זוג אם סכומו הוא ‪.x‬‬
‫‪‬‬
‫)‪void find_sum (int a[], int n, int x‬‬
‫{‬
‫;‪int i,j‬‬
‫)‪for (i = 0; i < n; i++‬‬
‫)‪for (j = i+1; j < n; j++‬‬
‫{ )‪if (a[i]+a[j] == x‬‬
‫;)‪printf (“The sum of %d and %d is %d”, a[i],a[j],x‬‬
‫;‪return‬‬
‫}‬
‫;)‪printf (“There are no two elements whose sum is %d”, x‬‬
‫}‬
‫מהי סיבוכיות זמן הריצה של האלגוריתם?‬
‫‪‬‬
‫)‪(n-1) + (n-2) + (n-3) + ... + 1 = n*(n-1)/2 = Θ(n2‬‬
‫אלגוריתם זה כלל לא משתמש בעובדה שהמערך ממוין! מה נעשה?‬
‫‪‬‬
‫‪‬‬
‫אם נתקלנו בזוג ‪ i‬ו‪ j-‬שעבורו ‪ ,a[i]+a[j] > x‬אין טעם לבדוק את שאר ה‪-j-‬ים‪ ,‬ואפשר לעצור את‬
‫הלולאה הפנימית‪ ,‬להגדיל את ‪ ,i‬ולהריץ את הפנימית שוב‪.‬‬
‫מציאת זוג איברים במערך שסכומם נתון‬
‫‪‬‬
‫פתרון שני‪ :‬אם נתקלנו בזוג איברים שסכומם עולה על ‪ ,x‬נשבור מהלולאה‬
‫הפנימית‪ ,‬ונתקדם לאיטרציה הבאה בלולאה החיצונית‪:‬‬
‫)‪void find_sum (int a[], int n, int x‬‬
‫{‬
‫;‪int i,j‬‬
‫)‪for (i = 0; i < n; i++‬‬
‫)‪for (j = i+1; j < n; j++‬‬
‫{ )‪if (a[i]+a[j] == x‬‬
‫;)‪printf (“The sum of %d and %d is %d”, a[i],a[j],x‬‬
‫;‪return‬‬
‫;‪} else if (a[i]+a[j] > x) break‬‬
‫;)‪printf (“There are no two elements whose sum is %d”, x‬‬
‫}‬
‫‪‬‬
‫‪‬‬
‫אלגוריתם זה אכן חוסך בצעדים עבור קלטים מסוימים‪ ,‬אבל האם‬
‫מה שהושג הוא שיפור בקבוע או שיפור בסדר גודל?‬
‫השיפור שהושג הוא רק שיפור בקבוע‪ .‬סיבוכיות זמן הריצה‬
‫של האלגוריתם נותרה )‪.Θ(n2‬‬
‫מציאת זוג איברים במערך שסכומם נתון‬
‫פתרון שלישי‪ :‬ננצל בצורה משמעותית את העובדה שהמערך ממוין‪ .‬עבור כל איבר‬
‫]‪ ,a[i‬נחפש בעזרת חיפוש בינארי איבר במערך ‪ a‬שערכו ]‪ .x-a[i‬אם נמצא איבר‬
‫כזה‪ ,‬ברור שסכומם של שני האיברים שווה ל‪.x-‬‬
‫‪‬‬
‫)‪void find_sum (int a[], int n, int x‬‬
‫{‬
‫;‪int i, index‬‬
‫{ )‪for (i = 0; i < n; i++‬‬
‫‪ */‬פונקציה לחיפוש בינארי *‪index = binary(a,0,n-1,x-a[i]); /‬‬
‫&& )‪if (index != -1‬‬
‫{ )‪{ index != i‬‬
‫;)‪printf (“The sum of %d and %d is %d”, a[i],a[index],x‬‬
‫;‪return‬‬
‫}‬
‫}‬
‫;)‪printf (“There are no two elements whose sum is %d”, x‬‬
‫}‬
‫ישנה טעות באלגוריתם‪ ...‬מהי?‬
‫מה סיבוכיות זמן הריצה של אלגוריתם זה?‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫זמן הריצה של ‪ binary‬הוא )‪.Θ(logn‬‬
‫לולאת ה‪ for-‬מתבצעת ‪ n‬פעמים במקרה הגרוע ביותר‪.‬‬
‫)‪Θ(nlogn‬‬
‫מציאת זוג איברים במערך שסכומם נתון‬
‫‪‬‬
‫פתרון רביעי‪ :‬ניתן לכתוב גרסה יעילה מעט יותר‪ ,‬המסתמכת על כך שבהינתן ]‪,a[i‬‬
‫אנחנו יודעים באיזה תת‪-‬מערך יש להפעיל חיפוש בינארי על מנת למצוא את ]‪.x-a[i‬‬
‫)‪void find_sum (int a[], int n, int x‬‬
‫{‬
‫;‪int i, index‬‬
‫{ )‪for (i = 0; i < n; i++‬‬
‫‪index = (x-a[i] < a[i]) ? binary(a,0,i-1,x-a[i]) :‬‬
‫;)]‪binary(a,i+1,n-1,x-a[i‬‬
‫{ )‪if (index != -1‬‬
‫;)‪printf (“The sum of %d and %d is %d”, a[i],a[index],x‬‬
‫;‪return‬‬
‫}‬
‫}‬
‫;)‪printf (“There are no two elements whose sum is %d”, x‬‬
‫}‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫מדוע בפתרון זה לא היה צורך לבצע את הבדיקה ‪? index != i‬‬
‫האם השיפור בזמן הריצה הוא שיפור בקבוע או שיפור בסדר גודל?‬
‫יעילות האלגוריתם נותרה )‪.Θ(nlogn‬‬
‫האם ייתכן ובכלל נאלץ להפעיל את החיפוש הבינארי על המחצית השמאלית של המערך?‬
‫מציאת זוג איברים במערך שסכומם נתון‬
‫‪‬‬
‫‪‬‬
‫פתרון חמישי‪ :‬נבנה מערך דו‪-‬מימדי בן ‪ n‬שורות ו‪ n-‬עמודות‪ ,‬אשר התא ה‪-‬‬
‫)‪ (i,j‬שלו‪ ,‬יכיל את הערך ]‪ .a[i]+a[j‬מכיוון שהמערך ‪ a‬ממוין‪ ,‬הרי שכל שורה‬
‫וכל עמודה במערך הדו‪-‬מימדי תהיה אף היא ממוינת‪.‬‬
‫מדובר בטבלת יאנג (‪ .)Young Tableau‬אנחנו מכירים אלגוריתם יעיל‬
‫למציאת איבר בטבלת יאנג‪ ,‬ונוכל להפעיל אלגוריתם זה עם הערך ‪.x‬‬
‫)‪void find_sum (int a[], int n, int x‬‬
‫{‬
‫;‪int i,j‬‬
‫‪ */‬מקצה זיכרון למערך דו‪-‬מימדי *‪int **b = init_matrix(n,n); /‬‬
‫)‪for (i = 0; i < n; i++‬‬
‫)‪for (j = 0; j < n; j++‬‬
‫;]‪b[i][j] = a[i] + a[j‬‬
‫;)‪find_in_young_tableau(b,n,n,x,&i,&j‬‬
‫)‪if (i != -1‬‬
‫;)‪printf (“The sum of %d and %d is %d”, a[i], a[j], x‬‬
‫‪else‬‬
‫;)‪printf (“There are no two elements whose sum is %d”, x‬‬
‫‪ */‬האם זה מספיק כדי לשחרר את כל הזיכרון שהוקצה? *‪free(b); /‬‬
‫}‬
‫מציאת זוג איברים במערך שסכומם נתון‬
‫‪‬‬
‫בפתרון האחרון ישנה שגיאה‪ ...‬מהי?‬
‫‪ ‬איברי האלכסון הראשי של המטריצה ‪ b‬אינם מייצגים סכום של שני‬
‫איברים שונים (אלא של איבר עם עצמו)‪ ,‬ולכן איננו מעוניינים שהם יוחזרו‬
‫על‪-‬ידי הפונקציה ‪.find_in_young_tableau‬‬
‫‪ ‬כיצד ניתן לפתור זאת?‬
‫כמה זמן אורכת בניית טבלת היאנג המתאימה?‬
‫‪Θ(n2) ‬‬
‫‪‬‬
‫כמה זמן אורך חיפוש בטבלת היאנג?‬
‫‪Θ(n) ‬‬
‫‪‬‬
‫לכן‪ ,‬האם משתלם ליישם פתרון זה על פני הפתרון הרביעי שסיבוכיות‬
‫זמן הריצה שלו היא )‪?Θ(nlogn‬‬
‫‪‬‬
‫‪‬‬
‫אם ידוע לנו כי יתבצעו שאילתות רבות על אותו המערך‪ ,‬אז במקום לבצע‬
‫פעמים רבות קטע קוד של )‪ ,Θ(nlogn‬ייתכן וישתלם לבנות פעם אחת‬
‫טבלת יאנג בזמן )‪ Θ(n2‬ואח"כ לבצע כל שאילתא בזמן יעיל של )‪.Θ(n‬‬
‫מציאת זוג איברים במערך שסכומם נתון‬
‫‪‬‬
‫‪‬‬
‫פתרון שישי‪ :‬באלגוריתם זה נבצע מעבר אחד בלבד על איברי המערך‪ ,‬אבל נעשה‬
‫שימוש בשני אינדקסים‪ i :‬ינוע מ‪ 0-‬ומעלה‪ ,‬ו‪ j-‬ינוע מ‪ n-1-‬ומטה‪.‬‬
‫נניח‪ ,‬שנתון המערך הבא‪ ,‬ושמחפשים שני איברים שסכומם ‪.x = 78‬‬
‫‪1 2 3 20 25 26 38 40 45 50 55 60 65‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫נקדם את ‪ i‬כל עוד מתקיים ‪.a[i]+a[j] < x‬‬
‫מרגע שנתקלנו בזוג איברים המקיימים ‪ ,a[i]+a[j] > x‬ברור שאין טעם להמשיך‬
‫ולהגדיל את ‪ ,i‬שכן המערך ממוין וגם אז יתקיים ‪.a[i]+a[j] > x‬‬
‫לכן‪ ,‬נקטין את הערך של ‪ j‬כל עוד מתקיים ‪.a[i]+a[j] > x‬‬
‫אם במהלך ריצת האלגוריתם ניתקל בזוג איברים שסכומם ‪ – x‬אזי סיימנו‪ .‬אחרת –‬
‫יכילו ‪ i‬ו‪ j-‬בשלב מסוים את אותו הערך‪ ,‬ואז נדווח על כשלון ונעצור‪.‬‬
‫עקבו בעצמכם אחרי ריצת האלגוריתם עבור המערך הנ"ל‪.‬‬
‫מציאת זוג איברים במערך שסכומם נתון‬
void find_sum (int a[], int n, int x)
{
int i = 0, j = n-1;
while (i < j) {
if (a[i] + a[j] == x) {
printf (“The sum of %d and %d is %d”, a[i],a[j],x);
return;
}
if (a[i] + a[j] < x)
i++;
else
j--;
}
printf (“There are no two elements whose sum is %d”, x);
}
‫ אז‬,‫ ובכל איטרציה ההפרש קטן באחד‬,n ‫ הוא‬j-‫ ל‬i ‫מאחר שההפרש ההתחלתי בין‬
‫ ועל כן סיבוכיות זמן הריצה של‬,‫ פעמים‬n ‫ תתבצע לכל היותר‬while-‫לולאת ה‬
.Θ(n) ‫האלגוריתם היא‬

‫מציאת זוג איברים במערך שסכומם נתון‬
‫)‪Θ(n2‬‬
‫)‪Θ(n2‬‬
‫)‪Θ(n‬‬
‫)‪Θ(nlogn‬‬
‫)‪Θ(nlogn‬‬
‫)‪Θ(n2)+Θ(n‬‬