תרגיל מס` 4 - WordPress.com

‫מכללת אורט כפר‪-‬סבא‬
‫מבני נתונים ויעילות אלגוריתמים‬
‫תרגיל מס' ‪4‬‬
‫פתרו את השאלות הבאות‪ .‬יש לסיים את התרגיל עד יום א' )‪.(19.10‬‬
‫שאלה ‪1‬‬
‫א‪ .‬ממשו את הפונקציה שכותרתה‪:‬‬
‫)‪void swap (int *a, int *b‬‬
‫הפונקציה תקבל מצביעים לשני משתנים מטיפוס שלם‪ ,‬ותבצע החלפה ביניהם‪.‬‬
‫ב‪ .‬ממשו את הפונקציה שכותרתה‪:‬‬
‫)‪void bubble_sort (int a[], int n‬‬
‫הפונקציה ממיינת בסדר עולה מערך ‪ a‬המכיל ‪ n‬מספרים שלמים‪ ,‬בעזרת האלגוריתם‬
‫למיון בועות )‪ .(Bubble Sort‬היעזרו בפונקציה שכתבתם בסעיף א'‪.‬‬
‫ג‪ .‬איזה שינוי עליכם לעשות בפונקציה המממשת את האלגוריתם למיון בועות‪ ,‬אותה‬
‫כתבתם בסעיף ב'‪ ,‬על מנת שהיא תמיין את המערך בסדר יורד‪ ,‬במקום בסדר עולה?‬
‫שאלה ‪2‬‬
‫בשיעור ראינו כי הן מיון בועות והן מיון בחירה‪ ,‬הם שניהם מסיבוכיות זמן ריצה ) ‪ Θ(n 2‬במקרה‬
‫הגרוע ביותר‪ .‬בשאלה זו ננסה להעריך את סיבוכיות זמן הריצה של שני אלגוריתמים אלו במקרה‬
‫הטוב ביותר‪ .‬כזכור‪ ,‬בשיעור ראינו כי באלגוריתם למיון בועות ניתן להכניס שיפור‪ ,‬בדמות הדגל‬
‫הבוליאני ‪ .sorted‬הניחו שזו הגרסה של מיון בועות בה אנו משתמשים‪.‬‬
‫א‪ .‬כמה פעולות יבצע האלגוריתם למיון בועות )המשופר( אם הוא מקבל בתור קלט מערך‬
‫שהוא כבר ממוין? בטאו את תשובתכם בעזרת הסימן האסימפטוטי ‪. Θ‬‬
‫ב‪ .‬האם קיים קלט אחר מזה שתואר בסעיף א'‪ ,‬שעבורו האלגוריתם למיון בועות יבצע פחות‬
‫פעולות?‬
‫ג‪ .‬בהסתמך על סעיפים א' ו‪-‬ב'‪ ,‬קבעו מהי סיבוכיות זמן הריצה של האלגוריתם למיון‬
‫בועות‪ ,‬במקרה הטוב ביותר‪.‬‬
‫ד‪ .‬כעת‪ ,‬קבעו מהי סיבוכיות זמן הריצה של האלגוריתם למיון בחירה‪ ,‬במקרה הטוב ביותר‪.‬‬
‫לשם כך‪ ,‬יהיה עליכם קודם לקבוע מה יהיה הקלט הטוב ביותר עבור האלגוריתם‪.‬‬
‫ה‪ .‬נניח שברשותכם מערך שהוא כמעט ממוין )כלומר‪ :‬הרוב הגדול של איבריו ממוינים‪ ,‬פרט‬
‫למספר קטן של איברים שלא נמצאים במקומם(‪ .‬באיזה מבין שני האלגוריתמים למיון‬
‫שהכרנו – מיון בחירה ומיון בועות – תעדיפו להשתמש?‬
‫‪1‬‬
‫שאלה ‪3‬‬
‫א‪ .‬מעוניינים לכתוב אלגוריתם המקבל כפרמטר מערך ממוין ‪ a‬המכיל ‪ n‬מספרים שלמים שונים‬
‫מאפס )אך לאו דווקא שונים זה מזה( המורכב מסדרת מס' שליליים ולאחריה סדרת מס' אי‪-‬‬
‫שליליים‪ .‬האלגוריתם יחזיר את האינדקס של האיבר החיובי הקטן ביותר‪ .‬פתחו אלגוריתם‬
‫יעיל הפותר את הבעיה‪ ,‬וחשבו את סיבוכיות זמן הריצה שלו‪.‬‬
‫ב‪ .‬משנים את הגדרת הבעיה מסעיף א'‪ ,‬וכעת המטרה היא לכתוב אלגוריתם המוצא את האיבר‬
‫הקטן ביותר במערך )לאו דווקא חיובי(‪ .‬פתחו אלגוריתם יעיל הפותר את הבעיה‪ ,‬וחשבו את‬
‫סיבוכיות זמן הריצה שלו‪.‬‬
‫שאלה ‪4‬‬
‫סטודנט פיתח אלגוריתם הנקרא חיפוש טרינרי )‪ (ternary search‬לחיפוש איבר במערך ממוין‪.‬‬
‫האלגוריתם דומה לחיפוש בינארי‪ ,‬אך במקום לחצות את המערך לשניים בכל שלב‪ ,‬הוא מחלק‬
‫את המערך לשלושה חלקים שווים ככל האפשר‪ ,‬ומבצע שתי השוואות‪ :‬עבור האיבר במקום ה‪n/3-‬‬
‫ועבור האיבר במקום ה‪ .2n/3-‬לפי השוואות אלו‪ ,‬האלגוריתם יודע באיזה שליש של המערך יש‬
‫להמשיך את החיפוש‪.‬‬
‫א‪ .‬עבור מערך בגודל ‪ n‬תאים‪ ,‬חשבו כמה צעדים יבצע האלגוריתם לחיפוש בינארי‪ ,‬וכמה‬
‫צעדים יבצע האלגוריתם לחיפוש טרינרי‪ .‬הציגו בפירוט את חישוביכם‪.‬‬
‫ב‪ .‬מי מבין שני האלגוריתמים יעיל יותר? הסבירו את תשובתכם‪.‬‬
‫ג‪ .‬האם השיפור ביעילות הוא שיפור בקבוע )‪ (improvement by factor‬או שיפור בסדר גודל‬
‫)‪ ?(order-of-magnitude improvement‬הסבירו את תשובתכם‪.‬‬
‫שאלה ‪5‬‬
‫נתונה הפונקציה הרקורסיבית הבאה‪:‬‬
‫)‪float secret (int x, int y‬‬
‫‪ */‬טענת כניסה‪ x :‬ו‪ y-‬מס' שלמים ‪/* y >= x ,‬‬
‫‪ */‬טענת יציאה‪/* ???????????????????????? :‬‬
‫{‬
‫;‪if (x == y) return x‬‬
‫;‪if (y-x == 1) return x+0.5‬‬
‫;)‪return secret(x+1,y-1‬‬
‫}‬
‫א‪ .‬השלימו את טענת היציאה של הפונקציה‪.‬‬
‫ב‪ .‬בצעו שינויים בפונקציה כך שתבצע את מטרתה עבור כל זוג מספרים ‪ ,x,y‬ולא רק עבור אלו‬
‫שמקיימים ‪. y >= x‬‬
‫‪2‬‬
‫שאלה ‪6‬‬
‫כידוע משיעורי חשבון‪ ,‬ניתן להציג מכפלה של שני מספרים טבעיים על ידי פעולת חיבור בלבד‪.‬‬
‫לדוגמה‪.3 * 4 = 3 + 3 + 3 + 3 = 12 :‬‬
‫ניתן להשתמש בעקרון זה‪ ,‬על מנת לחשב את המכפלה ‪ P * Q‬באופן רקורסיבי‪:‬‬
‫תנאי עצירה‪:‬‬
‫‪P*1=P‬‬
‫צעד רקורסיבי‪) P * Q = P*(Q-1) + P :‬כאשר ‪.(Q > 1‬‬
‫א‪ .‬הסבירו כיצד אפשר להשתמש בכלל רקורסיבי זה על מנת לחשב את ‪.3*4‬‬
‫ב‪ .‬לפניכם פונקציה רקורסיבית )(‪ multiply‬הממומשת באופן חלקי‪ ,‬וחסרים בה שלושה ביטויים‬
‫הממוספרים )‪ .(1)-(3‬השלימו את הביטויים החסרים‪.‬‬
‫)‪int multiply (int p, int q‬‬
‫*‪/‬‬
‫‪ */‬טענת כניסה‪ P :‬ו‪ Q-‬הם שלמים‪ ,‬ו‪0 < Q-‬‬
‫‪ */‬טענת יציאה‪ :‬הפונקציה מחזירה את מכפלתם של ‪ P‬ו‪/* Q-‬‬
‫{‬
‫)‬
‫)‪(1‬‬
‫;‬
‫)‪(2‬‬
‫;‬
‫)‪(3‬‬
‫( ‪if‬‬
‫‪else‬‬
‫}‬
‫שאלה ‪7‬‬
‫לפניכם פונקציה רקורסיבית‪:‬‬
‫)‪int f(int a, int b‬‬
‫‪ */‬טענת כניסה‪ a :‬ו‪ b-‬מס' שלמים *‪/‬‬
‫‪ */‬טענת יציאה‪/* ??????????????? :‬‬
‫{‬
‫;)‪if (b > a) return 1 + f(a+1, b‬‬
‫;‪else if (a > b) return f(a-1, b) + 1‬‬
‫;‪else return 0‬‬
‫}‬
‫א‪ .‬מה מחזירה הפונקציה עבור )‪?f(-3,1) ?f(6,4) ?f(4,7‬‬
‫ב‪ .‬השלימו את טענת היציאה של הפונקציה‪.‬‬
‫שאלה ‪8‬‬
‫לפניכם פונקציה רקורסיבית‪:‬‬
‫)‪int f(unsigned int x‬‬
‫‪ */‬טענת כניסה‪ x :‬מס' שלם חיובי )טבעי( *‪/‬‬
‫‪ */‬טענת יציאה‪/* ?????????????????????? :‬‬
‫{‬
‫;‪if (x == 0) return 0‬‬
‫;))‪return (f(x/2) + (x%2‬‬
‫}‬
‫א‪ .‬מה מחזירה הפונקציה עבור )‪?f(8) ?f(7) ?f(6) ?f(5) ?f(4‬‬
‫ב‪ .‬השלימו את טענת היציאה של הפונקציה‪.‬‬
‫‪3‬‬
‫שאלה ‪9‬‬
‫בכמה דרכים שונות יכולה דבורה לעוף לתא מסוים‪ ,‬אם היא מתחילה משמאל לימין )החל‬
‫מתאים ‪ 1‬או ‪ ?(2‬נתון שהדבורה מתקדמת מתא אל תא סמוך‪ ,‬כך שתמיד היא עפה מתא אל תא‬
‫אחר שמספרו גדול ממנו )לדוגמה דבורה יכול לעוף מתא ‪ 2‬לתא ‪ 3‬אך לא להיפך(‪.‬‬
‫לדבורה יש רק דרך אחת להגיע לתא מס' ‪.1‬‬
‫לדבורה יש שתי דרכים להגיע לתא מס' ‪ :2‬דרך התאים ‪ ,12‬או דרך תא מס' ‪.2‬‬
‫לדבורה יש שלוש דרכים להגיע לתא מס' ‪ :3‬דרך ‪ ,13‬או ‪ ,23‬או ‪.123‬‬
‫בכמה דרכים יכולה הדבורה לעוף כדי להגיע לתא מס' ‪ ?4‬מס' ‪ ?7‬מס' ‪?8‬‬
‫כתבו פונקציה המקבלת כפרמטר מספר טבעי ‪ ,n‬ומחזירה את מספר הדרכים השונות בהן הדבורה‬
‫יכולה לעוף כדי להגיע לתא מספר ‪.n‬‬
‫שאלה ‪10‬‬
‫קבוצת תלמידים המכילה בנים‬
‫ובנות‬
‫משתתפים באירוע בבית ספר‪ .‬המארגנים רוצים‬
‫להושיב חלק מהמשתתפים על שורה של כסאות כך ששני בנים לא ישבו בסמוך זה לזה‪ .‬השאלה‬
‫היא בכמה אפשרויות ניתן לסדר ב‪ n-‬כסאות קבוצה של בנים ובנות בשורה כך ששני בנים לא ישבו‬
‫בסמוך זה לזה‪.‬‬
‫לדוגמה‪:‬‬
‫בכסא אחד ניתן להושיב בן‬
‫או בת‬
‫כלומר ‪ 2‬אפשרויות‬
‫או בת ובן‬
‫בשני כסאות יש ‪ 3‬אפשרויות‪ :‬בן ובת‬
‫בשלוש כסאות יש ‪ 5‬אפשרויות‪:‬‬
‫‪,‬‬
‫‪,‬‬
‫או שתי בנות‬
‫‪,‬‬
‫‪,‬‬
‫‪.‬‬
‫א‪ .‬בכמה אפשרויות ניתן לסדר בנים ובנות על ‪ 4‬כסאות‪ ,‬כך ששני בנים לא ישבו זה ליד זה ?‬
‫ב‪ .‬בכמה אפשרויות ניתן לסדר בנים ובנות על ‪ 5‬כסאות‪ ,‬כך ששני בנים לא ישבו זה ליד זה ?‬
‫ג‪ .‬כתבו פונקציה המקבלת כקלט מס' טבעי ‪ ,n‬ומחזירה את מס' האפשרויות לסדר בנים‬
‫ובנות על ‪ n‬כסאות‪ ,‬כך ששני בנים לא ישבו זה ליד זה‪.‬‬
‫הדרכה‪ :‬בנו נוסחה רקורסיבית )‪ f(n‬בדומה למה שעשינו בשיעור בבעיית בניית קו‬
‫הקרשים‪ .‬עיינו במצגת השיעור האחרון‪.‬‬
‫ד‪) .‬סעיף רשות( כתבו פונקציה המקבלת כקלט מס' טבעי ‪ ,n‬ומחזירה את מס' האפשרויות לסדר‬
‫בנים ובנות על ‪ n‬כסאות‪ ,‬כך ששלושה בנים לא ישבו זה ליד זה )אך שניים כן יוכלו לשבת!(‪.‬‬
‫‪4‬‬
‫שאלה ‪11‬‬
‫בתרגיל קודם נתקלנו במושג של סדרה הנדסית )שאלה ‪ 10‬מתוך תרגיל מס' ‪ 1‬בתכנות מערכות‬
‫בשפת ‪ .(C‬כזכור‪ ,‬מדובר בסדרה שבה קיים יחס קבוע ‪ q‬בין כל שני איברים סמוכים‪:‬‬
‫… ‪a, aq, aq2, aq3, aq4, aq5,‬‬
‫עליכם לכתוב פונקציה רקורסיבית שכותרתה‪:‬‬
‫)‪int geometric_sequence (int a, int q, int n‬‬
‫המקבלת כפרמטר שלושה מספר טבעיים ‪ ,a,q,n‬ומחזירה את האיבר ה‪-n-‬י של הסדרה ההנדסית‬
‫שאיברה הראשון הוא ‪ a‬והמנה הקבועה שלה היא ‪.q‬‬
‫הדרכה‪ :‬חשבו ‪ -‬מה יהיה תנאי העצירה? חשבו גם על הצעד הרקורסיבי ‪ -‬כיצד ניתן לבטא איבר‬
‫בסדרה הנדסית על‪-‬ידי האיבר הקודם לו?‬
‫שאלה ‪12‬‬
‫כתבו תכנית מחשב בשפת ‪ C‬המיישמת את האלגוריתם הבא‪:‬‬
‫קלוט מספר טבעי לתוך ‪X‬‬
‫כל עוד ‪ X‬איננו פלינדרום‪ ,‬בצע‪:‬‬
‫הַ שֵ ם ב‪ Y-‬את המספר ההפוך בסדר ספרותיו ל‪X-‬‬
‫הַ שֵ ם ב‪ X-‬את ‪X + Y‬‬
‫הצג כפלט את ערכו של ‪X‬‬
‫לדוגמא‪ ,‬אם נפעיל את האלגוריתם על ‪ ,X = 87‬אז נקבל‪:‬‬
‫‪87 + 78 = 165‬‬
‫‪165 + 561 = 726‬‬
‫‪726 + 627 = 1353‬‬
‫‪ ,1353 + 3531 = 4884‬ונסיים‪.‬‬
‫אם נפעיל את האלגוריתם על ‪ ,X = 64‬אז נקבל‪:‬‬
‫‪64 + 46 = 110‬‬
‫‪ ,110 + 011 = 121‬ונסיים‪.‬‬
‫‪5‬‬
‫אם נפעיל את האלגוריתם על ‪ ,X = 13‬אז נקבל‪:‬‬
‫‪ ,13 + 31 = 44‬ונסיים‪.‬‬
‫האם תמיד מובטח שהאלגוריתם יעצור? כלומר – האם נגיע בהכרח בשלב מסוים לפלינדרום?‬
‫מסתבר שמדובר בבעיה פתוחה‪ ,‬שהתשובה עליה לא ידועה‪ .‬קראו‪ ,‬למשל‪ ,‬את סיפורו )העגום?( של‬
‫מתכנת שהריץ תכנית זו במחשב במשך שלוש שנים‪ ,‬מבלי שהתכנית תיעצר‪:‬‬
‫‪http://www.fourmilab.ch/documents/threeyears/threeyears.html‬‬
‫רמז‪ :‬האם כתבנו באחד התרגילים בתכנות מערכות בשפת ‪ C‬פונקציה שעשויה להיות שימושית‬
‫בשאלה זו?‬
‫ולשם שעשוע‪ :‬הקומיקאי האמריקאי ‪ Weird Al Yankovic‬הקליט שיר בשם '‪ ,'Bob‬שהוא‬
‫פארודיה על סגנון השירה של הזמר בוב דילן‪ ,‬אך מה שמיוחד בשיר הוא שכל שורה בו היא‬
‫פלינדרום‪https://www.youtube.com/watch?v=UnJdxUwF1Wg :‬‬
‫שאלה ‪13‬‬
‫מעוניינים לכתוב פונקציה רקורסיבית שכותרתה ‪-‬‬
‫)‪void find_min_max (int a[], int *min, int *max, int n‬‬
‫הפונקציה מקבלת מערך ‪ a‬של מס' שלמים שגודלו ‪ ,n‬ומחזירה )דרך הפרמטרים ‪ min‬ו‪,max-‬‬
‫המועברים לפי כתובת( את האיבר המינימלי והאיבר המקסימלי במערך‪.‬‬
‫למשל‪ ,‬נניח ש‪ a-‬הוא המערך הבא‪ ,‬שגודלו ‪ 8‬תאים‪:‬‬
‫‪7‬‬
‫‪6‬‬
‫‪5‬‬
‫‪4‬‬
‫‪3‬‬
‫‪2‬‬
‫‪1‬‬
‫‪0‬‬
‫‪12‬‬
‫‪-3‬‬
‫‪16‬‬
‫‪0‬‬
‫‪44‬‬
‫‪-8‬‬
‫‪0‬‬
‫‪11‬‬
‫אם נזמן את הפונקציה על‪-‬ידי )‪ ,find_min_max(a,&x,&y,8‬כאשר ‪ x‬ו‪ y-‬הם משתנים‬
‫מטיפוס שלם‪ ,‬אזי הם יקבלו את הערכים ‪. x = -8, y = 44‬‬
‫להלן מימוש חלקי של הפונקציה‪ ,‬אשר חסרים בו עשרה ביטויים הממוספרים )‪:(1) - (10‬‬
‫‪6‬‬
void find_min_max (int a[], int *min, int *max, int n)
{
int temp_min, temp_max;
if (
)
(1)
{
(2)
;
(3)
;
}
else
{
find_min_max(a,
if (
(4)
,
(5)
,
(6)
);
)
(7)
*min = temp_min;
else
(8)
if (
(9)
;
)
*max = temp_max;
else
(10)
;
}
}
.‫ שראינו בשיעור האחרון‬max_array ‫ עבדו לפי עיקרון הדומה לזה של הפונקציה‬:‫הדרכה‬
7