You are on page 1of 27

‫מבוא‪  

‬לשפת‪  C  ‬‬

‫תרגול‪  :8  ‬מערכים‪  ‬רב­‪-‬ממדיים‪  ‬‬


‫תרגילים‪  ‬בנושא‪  ‬מערכים‪  ‬ורקורסיה‪  ‬‬

‫מבוסס‪  ‬על‪  ‬השקפים‪  ‬שחוברו‪  ‬ע"י‪  ‬שי‪  ‬ארצי‪  ,‬גיתית‪  ‬רוקנשטיין‪  ,‬איתן‪    ‬‬
‫אביאור‪  ‬וסאהר‪  ‬אסמיר‪  ‬עבור‪  ‬הקורס‪"  ‬מבוא‪  ‬למדעי‪  ‬המחשב"‪  ‬‬

‫נכתב‪  ‬ע"י‪  ‬טל‪  ‬כהן‪  ,‬עודכן‪  ‬ע"י‪  ‬יורי‪  ‬פקלני‪  ©  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ‬לטכניון‪  –  ‬מכון‪  ‬טכנולוגי‪  ‬לישראל‪  ‬‬
‫תוכנייה‪  ‬‬

‫• מערכים‪  ‬רב­‪-‬ממדיים‪  ‬‬


‫• תרגילים‪  ‬בנושא‪  ‬מערכים‪  ‬דו­‪-‬ממדיים‪  ‬‬
‫• תרגילים‪  ‬בנושא‪  ‬מערכים‪  ‬ורקורסיה‪  ‬‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  2‬‬
‫מערכים‪  ‬רב­‪-‬ממדיים‪  ‬‬
‫‪  ‬‬
‫מערכים‪  ,‬וקטורים‪  ‬ומטריצות‪  ‬‬

‫• המערכים‪  ‬שהכרנו‪  ‬עד­‪-‬כה‪  ‬הם‪  ‬חד‪  ‬ממדיים‪  .‬‬


‫יש‪  ‬במערך‪  ‬תא‪  ‬‬
‫‪  ‬‬ ‫• בהינתן‪  ‬אינדקס‪)  ‬מספר‪  ‬שלם‪  ‬בין‪  0  ‬לגודל‪  ‬המערך(‪  ,‬‬
‫מתאים‪  ‬לאינדקס‪  ‬זה‪  .‬‬
‫• אפשר‪  ‬לייצג‪  ‬בעזרת‪  ‬המערך‪  ‬וקטורים\שורות‪  .‬‬
‫– ואכן‪  ,‬בשפות‪  ‬תכנות‪  ‬שונות‪  ‬אומרים‪"  ‬וקטור"‪  ‬במקום‪"  ‬מערך"‪  .‬‬
‫• אבל‪  ...‬איך‪  ‬אפשר‪  ‬לייצג‪  ‬בעזרת‪  ‬מערך‪  ‬מטריצה\טבלאות?‪  ‬‬
‫‪3‬‬ ‫‪12 19‬‬
‫‪8 1 5‬‬
‫‪A‬‬ ‫‪78 36 65‬‬
‫‪0‬‬ ‫‪4‬‬ ‫‪9‬‬
‫‪7‬‬ ‫‪2‬‬ ‫‪6‬‬
‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  4‬‬
‫מערכים‪  ‬דו­‪-‬ממדיים‪  ‬‬

‫כדי‪  ‬‬
‫• התשובה‪  :‬אם‪"  ‬מערך"‪  ‬הוא‪"  ‬וקטור"‪  ,‬אז‪  ‬נשתמש‪  ‬במערך‪  ‬דו­‪-‬ממדי‪    ‬‬
‫=‪  ‬‬
‫מספר‪  ‬שורות‪    ‬‬ ‫מספר‪  ‬עמודות‪  =  ‬‬ ‫לייצג‪  ‬מטריצה!‪  ‬‬
‫גובה‪  ‬של‪  ‬מטריצה‪  ‬‬ ‫רוחב‪  ‬של‪  ‬מטריצה‪  ‬‬ ‫• למשל‪  :‬‬
‫‪int a[5][3] = {{ 3, 12, 19},‬‬
‫‪{ 8, 1, 5},‬‬
‫‪  ‬‬
‫‪{78, 36, 65},‬‬ ‫‪  ‬‬
‫‪{ 0, 4, 9},‬‬
‫;}}‪{ 7, 2, 6‬‬ ‫‪  ‬‬
‫‪  ‬‬
‫– מגדיר‪  ‬ומאתחל‪  ‬מערך‪  ‬דו‪  ‬מימדי‪  ‬בעל‪  5  ‬שורות‪  ‬ו­‪  3-‬עמודות‪  .‬‬
‫• כדי‪  ‬לגשת‪  ‬לאיבר‪  ‬במערך‪  ‬דו­‪-‬ממדי‪  ‬משתמשים‪  ‬בשני‪  ‬אינדקסים‪  .‬‬
‫• למשל‪  ,‬בדוגמא‪  ‬לעיל‪  ‬מתקיים‪  a[1][2] == 5  :‬‬

‫אינדקס‪  ‬שורה‪  ‬‬ ‫אינדקס‪  ‬עמודה‪  ‬‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  5‬‬
‫תמונת‪  ‬זיכרון‪  ‬‬

‫לכן‪  ‬צריך‪  ‬לקבוע‪  ‬את‪  ‬הסדר‪  ‬בו‪  ‬נשמור‪  ‬‬


‫‪  ‬‬ ‫כזכור‪  ‬זיכרון‪  ‬מחשב‪  ‬הוא‪  ‬לינארי‪  ,‬‬ ‫•‬
‫את‪  ‬איברי‪  ‬המטריצה‪  ‬בזיכרון‪  .‬‬
‫ב­‪  C-‬פורשים‪  ‬את‪  ‬המטריצה‪  ‬בזיכרון‪  ‬שורה­‪-‬אחר­‪-‬שורה‪  .‬‬ ‫•‬
‫‪int a[5][3] = {{ 3, 12, 19},‬‬ ‫כלומר‪  ‬המטריצה‪  ‬הבאה‪  :‬‬ ‫•‬
‫‪{ 8, 1, 5},‬‬
‫‪{78, 36, 65},‬‬ ‫‪  ‬‬
‫‪{ 0, 4, 9},‬‬ ‫‪  ‬‬
‫;}}‪{ 7, 2, 6‬‬
‫‪  ‬‬
‫‪  ‬‬ ‫‪  ‬‬ ‫)‪    :sizeof(int‬‬
‫‪  ‬‬ ‫‪  ‬‬ ‫תיראה‪  ‬בזיכרון‪  ‬כך‪  ‬בהנחה‪  ‬שמתקיים‪   = 2    ‬‬
‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫•‬
‫‪  100  102  104  106  108  110  112  114  116  118  120  122  124  126  128‬‬
‫‪  ‬‬
‫‪  3  12  19  8‬‬ ‫‪  1‬‬ ‫‪  5  78  36  65  0‬‬ ‫‪  4‬‬ ‫‪  9‬‬ ‫‪  7‬‬ ‫‪  2‬‬ ‫‪  6‬‬
‫‪  ‬‬
‫• איך‪  ‬יראה‪  ‬הזיכרון‪  ‬עבור‪  ?  sizeof(int) = 4  ‬‬
‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  6‬‬
‫גישה‪  ‬למערך‪  ‬דו­‪-‬ממדי‪  ‬בעזרת‪  ‬מצביעים‪  ‬‬

‫• בדיוק‪  ‬כמו‪  ‬עבור‪  ‬מערכים‪  ‬חד­‪-‬ממדיים‪  ,‬גם‪  ‬עבור‪  ‬מטריצות‪  ‬אפשר‪  ‬להגדיר‪  ‬‬
‫‪int a[5][3] = {{ 3, 12, 19},‬‬ ‫מצביע‪  ‬לאיבר‪  ‬הראשון‪  :‬‬
‫‪{ 8, 1, 5},‬‬
‫‪{78, 36, 65},‬‬ ‫‪  ‬‬
‫‪{ 0, 4, 9},‬‬ ‫‪  ‬‬
‫;}}‪{ 7, 2, 6‬‬
‫;]‪int *p = &a[0][0‬‬ ‫‪  ‬‬
‫• כעת‪  ‬ניתן‪  ‬לגשת‪  ‬לנתונים‪  ‬של‪  ‬מטריצה‪  a  ‬גם‪  ‬בעזרת‪  ‬המצביע‪  :p  ‬‬
‫שקולים‬
‫;]‪int x = a[i][j‬‬ ‫‪  ‬‬
‫;)‪int x = *(p + 3*i + j‬‬
‫‪  ‬‬
‫– ”‪  “i*3‬כי‪  ‬כדי‪  ‬להגיע‪  ‬לתחילת‪  ‬שורה‪  i  ‬יש‪  ‬לקדם‪  ‬את‪  p  ‬ב­‪  :i*width-‬‬
‫‪p‬‬ ‫‪p+3‬‬ ‫‪p+6‬‬ ‫‪p+9‬‬ ‫‪p+12‬‬ ‫‪  ‬‬
‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬ ‫‪  ‬‬
‫‪  100  102  104  106  108  110  112  114  116  118  120  122  124  126  128‬‬
‫‪  3  12  19  8‬‬ ‫‪  1‬‬ ‫‪  5  78  36  65  0‬‬ ‫‪  4‬‬ ‫‪  9‬‬ ‫‪  7‬‬ ‫‪  2‬‬ ‫‪  6‬‬ ‫‪  ‬‬
‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬
‫מערך‪  ‬דו­‪-‬ממדי‪  ‬כפרמטר‪  ‬לפונקציה‪  ‬‬

‫ניתן‪  ‬להעביר‪  ‬את‪  ‬‬


‫‪  ‬‬ ‫• אם‪  ‬רוצים‪  ‬לכתוב‪  ‬פונקציה‪  ‬שמניחה‪  ‬אורך‪  ‬שורה‪  ‬קבוע‪  ,‬‬
‫המטריצה‪  ‬בצורה‪  ‬הבאה‪  :‬‬
‫חייבים‪  ‬לציין‪  ‬את‪  ‬מספר‪  ‬העמודות‪)  ‬אורך‪  ‬השורה(‪  ‬‬ ‫‪  ‬‬
‫)‪void f(int a[][4], int height‬‬ ‫‪  ‬‬
‫מותר‪  ‬גם‪  ‬לציין‪  ‬את‪  ‬מספר‪  ‬השורות‪  ,‬אך‪  ‬‬
‫‪  ‬‬
‫הקומפיילר‪  ‬יתעלם‪  ‬ממנו‪  .‬‬ ‫‪  ‬‬
‫– פרמטר‪)  height  ‬מספר‪  ‬השורות(‪  ‬מועבר‪  ‬כדי‪  ‬שבתוך‪  ‬הפונקציה‪  ‬לא‪  ‬נחרוג‪  ‬מגבולות‪    ‬‬
‫המטריצה‪  .‬‬
‫לכן‪  ‬מותר‪  ‬בתוך‪  ‬הפונקציה‪  ‬לגשת‪  ‬‬
‫‪  ‬‬ ‫• פונקציה‪  ‬זו‪  ‬יודעת‪  ‬ש­‪  a-‬היא‪  ‬מטריצה‪  ,‬‬
‫]‪a[i][j‬‬ ‫לאיבר‪  i,j  ‬בעזרת‪  :‬‬
‫– ‪  0 ≤  i  ≤  height-1, 0 ≤  j  ≤  3‬‬
‫;]‪int m[9][4‬‬
‫;)‪f(m, 9‬‬ ‫• הקריאה‪  ‬לפונקציה‪  ‬זו‪  ‬תראה‪  ‬כך‪  :‬‬
‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬
‫מערך‪  ‬דו­‪-‬ממדי‪  ‬כפרמטר‪  ‬לפונקציה‪  ‬‬

‫• אבל‪  ‬אם‪  ‬רוצים‪  ‬לכתוב‪  ‬פונקציה‪  ‬שעובדת‪  ‬עבור‪  ‬מטריצה‪  ‬בגודל‪  ‬כלשהו‪  ‬‬
‫גובה‪  ‬ורוחב‪  ‬של‪  ‬‬
‫‪  ‬‬ ‫חייבים‪  ‬להעביר‪  ‬לפונקציה‪  ‬מצביע‪  ‬לאיבר‪  ‬הראשון‪  ,‬‬
‫המטריצה‪  :‬‬
‫)‪void f(int *p, int height, int width‬‬
‫‪  ‬‬
‫• כעת‪  ,‬מבחינת‪  ‬הפונקציה‪  p  ,‬הוא‪  ‬לא‪  ‬מטריצה‪  ,‬אלא‪  ‬מצביע‪  .‬‬
‫אלא‪  ‬יש‪  ‬לגשת‪  ‬לאיבר‪  ‬‬
‫‪  ‬‬ ‫• לכן‪  ‬בתוך‪  ‬הפונקציה‪  ‬לא‪  ‬ניתן‪  ‬להשתמש‪  ‬ב­‪  ,p[i][j]-‬‬
‫)‪*(p + i*width + j‬‬ ‫‪  i,j‬בעזרת‪  :‬‬
‫– ‪  0 ≤  i  ≤  height-1, 0 ≤  j  ≤  width-1‬‬
‫‪  ‬‬
‫;]‪int m[9][4‬‬ ‫• הקריאה‪  ‬לפונקציה‪  ‬זו‪  ‬תראה‪  ‬כך‪  :‬‬
‫;)‪f(&m[0][0], 9, 4‬‬ ‫‪  ‬‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬


‫מערכים‪  ‬רב­‪-‬ממדיים‪  ‬‬

‫מערכים‪  ‬מכל‪  ‬טיפוס‪  ‬‬


‫‪  ‬‬ ‫• למעשה‪  ,‬ניתן‪  ‬להגדיר‪  ‬בשפת‪  C  ‬‬
‫בכל‪  ‬מימד‪  ‬שהוא‪  .‬‬
‫• למשל‪  ,‬מערך‪  ‬תלת­‪-‬ממדי‪  ‬של‪  :double  ‬‬
‫;]‪double array[5][3][6‬‬ ‫‪  ‬‬
‫‪  ‬‬
‫ממדיים‪  ‬לכל‪  ‬היותר‪  ‬בקורס‪  ‬‬
‫‪  ‬‬ ‫• אנו‪  ‬נסתפק‪  ‬במערכים‪  ‬דו­‪-‬‬
‫זה‪  .‬‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  7‬‬
‫תרגיל‪  :1  ‬מערכים‪  ‬ומטריצות‪  ‬‬

‫• כתבו‪  ‬פונקציה )‪    void num2(int arr[ ] , int len‬‬


‫– המקבלת‪  ‬מערך‪  arr  ‬ואת‪  ‬אורכו‪    len  ‬‬
‫– ומדפיסה‪  ‬את‪  ‬צמד‪  ‬המספרים‪  ‬המופיע‪  ‬מספר‪  ‬פעמים‪  ‬הרב‪  ‬ביותר‪    .‬‬
‫– אם‪  ‬יש‪  ‬יותר‪  ‬מצמד‪  ‬אחד‪  ‬אזי‪  ‬יודפסו‪  ‬כל‪  ‬הצמדים‪  .‬‬
‫• צמד‪  ‬מספרים‪  ‬הינם‪  2  ‬מספרים‪  ‬הנמצאים‪  ‬במקומות‪  ‬עוקבים‪  .‬‬
‫• הנח‪  ‬כי‪  ‬כל‪  ‬המספרים‪  ‬קטנים‪  ‬ממש‪  ‬מ­‪  500  -‬וגדולים‪  ‬או‪  ‬שווים‪  ‬ל­‪  .0-‬‬
‫• דוגמא‪  :‬עבור‪  ‬מערך‪  4   5   7   88   2   3   4   5  2   3  ‬‬
‫‪  ‬הצמדים‪  ‬הם‪  (4,5) (5,7) (7,88) (88,2) (2,3) (3,4) (4,5) (5,2) (2,3):‬‬
‫‪      ‬לכן‪  ‬יודפס‪  4  5    :  ‬‬
‫‪  2 3                                          ‬‬
‫‪  ‬‬
‫הערה‪  :‬הסדר‪  ‬בתוך‪  ‬הצמד‪  ‬חשוב‪  ,‬כלומר‪  :‬הצמד‪  5  4  ‬שונה‪  ‬מהצמד‪   .4  5  ‬‬ ‫•‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  8‬‬
‫הדרך‪  ‬לפתרון‪  ‬‬

‫• בשביל‪  ‬למצוא‪  ‬מהו‪  ‬צמד‪  ‬שמופיע‪  ‬הכי‪  ‬הרבה‪  ‬פעמים‪  ,‬צריכים‪  ‬לספור‪  ‬כמה‪  ‬‬
‫פעמים‪  ‬מופיע‪  ‬כל‪  ‬צמד‪  .‬‬
‫אפשרויות‪  ‬‬
‫‪  ‬‬ ‫• כיוון‪  ‬שיש‪  500  ‬אפשרויות‪  ‬לכל‪  ‬מספר‪  ‬במערך‪  ,‬יש‪  500*500  ‬‬
‫שונות‪  ‬של‪  ‬צמדים‪  :‬‬
‫– ‪  500‬צמדים‪  ‬שהמספר‪  ‬הראשון‪  ‬שלהם‪  0  ‬‬
‫– ‪  500‬צמדים‪  ‬שהמספר‪  ‬הראשון‪  ‬שלהם‪  1  ‬‬
‫– ‪  ...‬‬
‫– ‪  500‬צמדים‪  ‬שהמספר‪  ‬הראשון‪  ‬שלהם‪  499  ‬‬
‫– סה"כ‪  .500*500  ‬‬
‫‪  ‬‬
‫שכל‪  ‬איבר‪  ‬‬
‫‪  ‬‬ ‫• כדי‪  ‬לספור‪  ‬את‪  ‬מספר‪  ‬הצמדים‪  ,‬נגדיר‪  ‬מטריצה‪  m[500][500]  ‬‬
‫]‪  m[i][j‬סופר‪  ‬כמה‪  ‬פעמים‪  ‬הצמד‪  (i,j)  ‬מופיע‪  ‬במערך‪  .arr  ‬‬
‫‪  ‬‬
‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  ‬‬ ‫‪  9‬‬
‫תרגיל‪  –  1  ‬פתרון‪  ‬‬

‫) ‪void num2( int arr[], int len‬‬


‫{‬ ‫‪  .1‬נגדיר‪  ‬מטריצה‪  500*500  ‬‬
‫;}}‪int m[500][500] = {{0‬‬ ‫‪        ‬ונאתחל‪  ‬אותה‪  ‬באפסים‪  .‬‬
‫;‪int i , j , max = 0‬‬
‫) ‪if ( len < 2‬‬
‫;‪return‬‬ ‫‪  .2‬נספור‪  ‬כמה‪  ‬פעמים‪  ‬מופיע‪  ‬‬
‫‪        ‬כל‪  ‬צמד‪  (arr[i], arr[i+1])  ‬‬
‫) ‪for ( i = 0 ; i < len-1 ; i++‬‬
‫;‪m[arr[i]][arr[i+1]]++‬‬
‫‪  .3‬נמצא‪  ‬את‪  ‬מקסימום‪  ‬של‪  ‬‬
‫) ‪for ( i = 0 ; i < 500 ; i++‬‬ ‫‪        ‬מספר‪  ‬ההופעות‪  .‬‬
‫) ‪for ( j = 0 ; j < 500 ; j++‬‬
‫) ‪if ( m[i][j] > max‬‬
‫‪  ‬‬
‫;]‪                                max = m[i][j‬‬
‫‪  .4‬נדפיס‪  ‬את‪  ‬כל‪  ‬הצמדים‪  ‬‬
‫) ‪for ( i = 0 ; i < 500 ; i++‬‬ ‫‪        ‬שמספר‪  ‬ההופעות‪  ‬שלהם‪  ‬‬
‫) ‪for ( j = 0 ; j < 500 ; j++‬‬ ‫‪        ‬שווה‪  ‬למקסימום‪  ‬שמצאנו‪  .‬‬
‫) ‪if ( m[i][j] == max‬‬
‫;;)‪printf(“\n  max  appearance:  %d,  %d”,  i  ,  j  ‬‬
‫}‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  10‬‬
‫תרגיל‪  :2  ‬מטריצות‪  ‬‬

‫• ריבוע‪  ‬חצי­‪-‬קסם‪  ‬הוא‪  ‬מערך‪  ‬דו­‪-‬מימדי‪  ‬שבו‪  ‬סכומי‪  ‬השורות‪  ‬הם‪  ‬שווים‪  .‬‬
‫– )אין‪  ‬שום‪  ‬דרישה‪  ‬לגבי‪  ‬העמודות‪  ‬או‪  ‬האלכסונים(‪  ‬‬
‫‪5‬‬ ‫‪6‬‬ ‫לדוגמה‪    :‬מערך‪  ‬הבא‪  :‬‬
‫‪3‬‬ ‫•‬
‫‪3 8 3‬‬ ‫‪  ‬‬
‫‪7 -1 8‬‬ ‫‪  ‬‬
‫‪  ‬הוא‪  ‬ריבוע‪  ‬חצי­‪-‬קסם‪  ,‬כיוון‪  ‬שסכום‪  ‬המספרים‪  ‬בכל‪  ‬שורה‪  ‬הוא‪  .14  ‬‬
‫‪  ‬‬
‫כתבו‪  ‬פונקציה‪  int is_magic(int A[N][N])  ‬‬ ‫•‬
‫‪  ,‬‬
‫המקבלת‪  ‬מערך‪  ‬דו‪  ‬מימדי‪  ‬ומחזירה‪  1  ‬במידה‪  ‬וזהו‪  ‬ריבוע‪  ‬חצי­‪-‬קסם ‪  ‬‬ ‫•‬
‫ואחרת‪  ‬מחזירה‪  .0  ‬‬
‫יש‪  ‬להניח‪  ‬ש‪  N  ‬מוגדר‪  ‬ב‪   .#define  ‬‬ ‫•‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  11‬‬
‫תרגיל‪  –  2  ‬פתרון‪  ‬‬

‫)]‪int is_magic(int A[][N‬‬


‫{‬
‫;‪int curr_row_sum, i, j‬‬ ‫נחשב‪  ‬את‪  ‬הסכום‪  ‬‬
‫;‪int first_row_sum  =  0‬‬ ‫‪  ‬של‪  ‬השורה‪  ‬הראשונה‪  ‬‬

‫‪for (j=0;  j<N;  j++) {  ‬‬


‫;]‪first_row_sum += A[0][j‬‬ ‫נבדוק‪  ‬שסכום‪  ‬של‪  ‬כל‪  ‬‬
‫}‬ ‫השורות‪  ‬שווה‪  ‬לסכום‪  ‬של‪  ‬‬
‫השורה‪  ‬הראשונה‪  ‬‬
‫{‪for (i=1;  i<N;  i++)  ‬‬
‫;‪curr_row_sum=0‬‬
‫‪for (j=0;  j<N;  j++) {  ‬‬ ‫נחשב‪  ‬את‪  ‬הסכום‪  ‬של‪  ‬השורה‪    ‬‬
‫;]‪curr_row_sum += A[i][j‬‬ ‫‪  i‬‬
‫}‬
‫{ )‪if (curr_row_sum != first_row_sum‬‬ ‫אם‪  ‬הסכום‪  ‬שונה‪ ,‬זה‪  ‬לא‪  ‬‬
‫;‪return 0‬‬ ‫ריבוע‪  ‬חצי­‪-‬קסם‪  .‬אין‪  ‬טעם‪  ‬‬
‫}‬ ‫לבדוק‪  ‬את‪  ‬שאר‪  ‬השורות‪  .‬‬
‫}‬
‫;‪return 1‬‬
‫}‬ ‫אם‪  ‬הגענו‪  ‬עד‪  ‬לכאן‪      ,‬‬
‫סכום‪  ‬כל‪  ‬השורות‪  ‬שווה‪  ‬‬
‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  12‬‬
‫תרגיל‪  3  ‬‬

‫• נייצג‪  ‬תמונה‪  ‬בשחור‪  ‬לבן‪  ‬ע"י‪  ‬מערך‪  ‬דו‪  ‬ממדי‪  ,‬שכל‪  ‬תא‪  ‬בו‪  ‬מכיל‪  1  ‬עבור‪  ‬‬
‫נקודה‪  ‬שחורה‪  ‬ו‪  0  ‬עבור‪  ‬נקודה‪  ‬לבנה‪  ‬‬
‫‪  ,‬‬
‫• נגדיר‪  ‬את‪  ‬מטריצת‪  ‬השליטה‪  ‬של‪  ‬תמונה‪  ‬כמערך‪  ‬דו‪  ‬מימדי‪  ‬של‪  ‬שלמים ‪  ‬‬
‫של‪  ‬התמונה‪  ‬‬
‫‪  ‬‬ ‫בו‪  ‬במקום‪  ‬ה­‪  [i][j]-‬מוצב‪  ‬הערך‪  n  ‬אם‪  ‬ורק‪  ‬אם‪  ‬התא‪  ‬ה‪  [i][j]  ‬‬
‫הוא‪  ‬נקודה‪  ‬שחורה‪  ‬וגם‪  n-1  ‬התאים‪  ‬שתחתיו‪  ‬הם‪  ‬נקודות‪  ‬שחורות‪  ‬‬
‫• כתבו‪  ‬פונקציה‪  ‬אשר‪  ‬מקבלת‪  ‬תמונה‪  ‬ובונה‪  ‬את‪  ‬מטריצת‪  ‬השליטה‪  ‬שלה‪  ‬‬
‫‪  ‬‬
‫‪    :‬‬
‫לדוגמה ‪  ‬‬
‫‪  ‬‬
 ‫ פיתרון‬ -­3  ‫תרגיל‬

void compute_dominance (int p[][W] , int d[][W], int h){


int i,j;
for (j=0; j<W; j++) { /* base case: bottom row */
d[h-1][j] = p[h-1][j]; /* d is 1 if p is black, 0 otherwise */
}
for (i=h-2; i>=0; i--) { /* compute upper rows */
for (j=0; j<W; j++) { /* for each column */
d[i][j] = (p[i][j] ? d[i+1][j] + 1 : 0);
}
}
}
‫תרגיל‪  4  ‬‬

‫את‪  ‬מטריצת‪  ‬‬


‫‪  ‬‬ ‫• כתבו‪  ‬פונקציה‪ max_rect_at_point  ‬המקבלת‪  ‬תמונה‪  ,‬‬
‫ומחזירה‪  ‬את‪  ‬שטחו‪  ‬של‪  ‬‬
‫‪  ‬‬ ‫השליטה‪  ‬שלה‪  ‬וקורדינאטות‪  ‬של‪  ‬תא‪  ‬בתמונה‪  ,‬‬
‫המלבן‪  ‬השחור‪  ‬הגדול‪  ‬ביותר‪  ‬שהתא‪  ‬הנתון‪  ‬הוא‪  ‬הקודקוד‪  ‬השמאלי‪  ‬‬
‫‪  ‬‬
‫מהתרגיל‪  ‬‬
‫‪  ‬‬ ‫העליון‪  ‬שלו‪  .‬למשל‪  ‬בהינתן‪  ‬התמונה‪  P  ‬ומטריצת‪  ‬השליטה‪  D  ‬‬
‫הקודם‪  .‬‬

‫‪  ‬‬
 ‫ פיתרון‬ -­4  ‫תרגיל‬

int max_rect_at_point (int p [][M], int d[][M], int i, int j) {


int k, length, width, area;
if (!p[i][j]) {
return 0;
}
area = length = d[i][j]; /* for a rectangle of width 1, area = length */
k = j+1; width = 2; /* try rectangles of increasing width */
while (k < M && p[i][k]) { /* as long as the line is black */
length = MIN (length, d[i][k]);
area = MAX (area, width*length);
k++; width++;
}
return area;
}
‫תרגילים‪  ‬רקורסיה‪  ‬ומערכים‪  ‬‬
‫שאלה‪  1  ‬‬

‫ו‪  ‬‬
‫• ממשו‪  ‬פונקציה‪  ‬רקורסיבית המקבלת‪  ‬מחרוזת‪  A  ‬ושני‪  ‬מערכים‪  ‬ריקים‪    B  ‬‬
‫‪    .‬‬
‫‪   C‬‬
‫)][ ‪void SeparateLetters(char A [], char B [], char C‬‬
‫ואת‪  ‬האותיות‪  ‬‬
‫‪  ‬‬ ‫• הפונקציה‪  ‬מעתיקה‪  ‬את‪  ‬האותיות‪  ‬הגדולות‪  ‬מ­‪  A-‬ל­‪  B-‬‬
‫הקטנות‪  ‬מ­‪  A-‬ל­‪  .C-‬‬
‫• בסוף‪  ‬הריצה‪  B  ‬ו‪  C  ‬צריכות‪  ‬להיות‪  ‬מחרוזות‪  ‬‬
‫– כלומר‪  ‬להסתיים‪  ‬ב­‪  '\0'-‬‬
‫‪    ‬‬ ‫• יש‪  ‬להניח‪  ‬שגודל‪  ‬המערכים‪B  ‬ו‪  C  ‬הוא‪  ‬לפחות‪  ‬כמו‪  ‬הגודל‪  ‬של‪.A  ‬‬
‫• לדוגמא‪  ‬עבור‪  :‬‬
‫‪  A  K  i  1  @  B  j  7  Y  8  \0‬‬ ‫• נקבל‪  :‬‬
‫‪  B  K  B  Y  \0‬‬
‫‪  C‬‬ ‫‪  i‬‬ ‫‪  j‬‬ ‫‪  \0‬‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  18‬‬
‫שאלה‪  –  1  ‬האלגוריתם‪  ‬הרקורסיבי‪  ‬‬

‫הבעיה‪  :‬יש‪  ‬להעביר‪  ‬אותיות‪  ‬ממחרוזת‪  A  ‬ל­‪  B-‬ו­‪  .C-‬‬


‫‪ .1‬הדרך‪  ‬להקטין‪  ‬פרמטר­‪-‬מחרוזת‪  ‬היא‪  ‬להוריד‪  ‬את‪  ‬התו‪  ‬הראשון‪  .‬‬
‫נניח‪  ‬שאנחנו‪  ‬יודעים‪  ‬להעביר‪  ‬אותיות‪  ‬כמבוקש‪  ‬עבור‪  ‬מחרוזת‪  ‬בלי‪  ‬התו‪  ‬‬
‫‪  ‬‬ ‫‪.2‬‬
‫הראשון‪  .‬‬
‫‪ .3‬אם‪  ‬תו‪  ‬הראשון‪  ‬הוא‪  ‬אות‪  ‬גדולה‪  –  ‬נעביר‪  ‬אותו‪  ‬ל­‪  .B-‬‬
‫‪  ‬אם‪  ‬תו‪  ‬הראשון‪  ‬הוא‪  ‬אות‪  ‬קטנה‪  –  ‬נעביר‪  ‬אותו‪  ‬ל­‪  .C-‬‬
‫‪  ‬אחרת‪  ‬נתעלם‪  ‬מהתו‪  ‬הראשון‪  .‬‬
‫‪  ,‬‬
‫‪  ‬אחרי‪  ‬שטיפלנו‪  ‬בתו‪  ‬הראשון‪  ,‬נשאר‪  ‬לטפל‪  ‬במחרוזת‪  ‬בלי‪  ‬התו‪  ‬הראשון ‪  ‬‬
‫והנחנו‪  ‬שאת‪  ‬זה‪  ‬הקריאה‪  ‬הרקורסיבית‪  ‬יודעת‪  ‬לעשות‪  .‬‬
‫סיימנו‪  ‬‬
‫‪  ‬‬ ‫‪ .4‬תנאי‪  ‬עצירה‪  :‬כאשר‪  ‬מחרוזת‪  A  ‬מסתיימת‪)  ‬כלומר‪  ‬מגעים‪  ‬ל­‪  (‘\0’-‬‬
‫להעביר‪  ‬את‪  ‬כל‪  ‬התווים‪  .‬נשאר‪  ‬רק‪  ‬לשים‪  ‘\0’  ‬בסוף‪  ‬של‪  B  ‬ושל‪  .C  ‬‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  19‬‬
 ‫ פתרון‬ -­  2  ‫שאלה‬
void SeparateLetters(char *A, char *B, char *C)
{
if (*A == '\0') {
*B = '\0';
*C = '\0';
return;
}
if (*A >= 'a' && *A <= 'z') { /* copy small letter to B */
*B = *A;
SeparateLetters(A+1, B+1, C);
return;
}
if (*A >= 'A' && *A <= 'Z') { /* copy big letter to C */
*C = *A;
SeparateLetters(A+1, B, C+1);
return;
}
SeparateLetters(A+1, B, C); /* skip non letters */
}

 9  ‫תרגול‬  ©  ‫ שמורות‬ ‫ הזכויות‬ ‫ כל‬ .‫ המחשב‬ ‫ למדעי‬ ‫מבוא‬  1


‫שאלה‪     2  ‬‬

‫‪    .‬‬
‫‪  a‬הוא‪  ‬מערך‪  ‬שלמים‪  ‬באורך‪   n  ‬‬ ‫•‬
‫‪    .‬‬
‫ידוע‪  ‬ש­‪    n  -‬אי­‪-‬זוגי ‪  ‬‬ ‫•‬
‫כתבו‪  ‬פונקציה‪  ‬רקורסיבית‪    ‬‬ ‫•‬
‫)‪void extreme_to_middle(int a[ ], int i, int j‬‬
‫‪  ‬‬
‫שתדפיס‪  ‬את‪  ‬אברי‪  a  ‬בסדר‪  ‬הבא‪  ‬משמאל‪  ‬לימין‪  :‬‬ ‫•‬
‫‪  ‬‬
‫]‪a[0] a[n-1] a[1] a[n-2]  …  a[(n-1)/2‬‬
‫‪  ‬‬
‫‪  ‬‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬ ‫‪  21‬‬
   ‫ פתרון‬ -­  2  ‫שאלה‬
void extreme_to_middle(int a[], int i, int j)
{  
if (j==i) {
printf("%d ", a[i]);
return;
}
printf("%d ", a[i]);
printf("%d", a[j]);
extreme_to_middle(a,i+1 j-1);
return;
}

 9  ‫תרגול‬  ©  ‫ שמורות‬ ‫ הזכויות‬ ‫ כל‬ .‫ המחשב‬ ‫ למדעי‬ ‫מבוא‬  22


‫שאלה‪  3  ‬‬

‫• כתבו‪  ‬פונק'‪  ‬שחתימתה‪  :‬‬


‫)‪  int path_exists(int mat[][N], int i, int j‬‬
‫ותבדוק‪  ‬אם‪  ‬‬
‫‪  ‬‬ ‫• הפונק'‪  ‬תקבל‪  ‬מערך‪  ‬דו­‪-‬מימדי‪  ‬שמכיל‪  ‬אפסים‪  ‬ואחדים‪  ‬בלבד‪  ,‬‬
‫(‪  ‬‬
‫קיים‪  ‬מסלול‪  ‬שכולו‪  ‬אחדים‪  ‬מהפינה‪  ‬השמאלית‪  ‬העליונה‪)  ‬התא‪   0,0  ‬‬
‫לפינה‪  ‬הימנית‪  ‬התחתונה‪)  ‬התא‪  ,(N-1,N-1  ‬ותחזיר‪  1  ‬אם‪  ‬כן‪  ,‬ו­‪  0-‬‬
‫אחרת‪  .‬בסוף‪  ‬הפונק'‪  ‬המערך‪  ‬הדו­‪-‬מימדי‪  ‬צריך‪  ‬להיות‪  ‬זהה‪  ‬להתחלה‪  .‬‬
‫יוחזר‪  1  ‬‬ ‫• למשל‪  :‬‬
‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0  ‬‬
‫יוחזר‪  0  ‬‬
‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬

‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬

‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪0‬‬ ‫‪1‬‬

‫תרגול‪  9  ‬‬ ‫מבוא‪  ‬למדעי‪  ‬המחשב‪  .‬כל‪  ‬הזכויות‪  ‬שמורות‪  ©  ‬‬


 ‫פיתרון‬
int path_exists(int mat[][N], int i, int j){
int i2, j2;
if( i==N-1 && j==N-1 )
if( mat[i][j]==1 )
return 1;
else
return 0;
if( !mat[i][j] )
return 0;
mat[i][j] = 2; /* A sign that we visited the cell */
for(i2=i-1; i2<=i+1; i2++) /*The cells around the current cell*/
for(j2=j-1; j2<=j+1; j2++){
if( i2>=0 && i2<N && j2>=0 && j2<N && mat[i2][j2]==1 )
if( path_exists(mat,i2,j2) ){
mat[i][j]=1;
return 1;
}
}
 ‫ להדפיס‬ ‫ אפשר‬ ‫איך‬
mat[i][j]=1;
return 0;  ?‫ המסלול‬ ‫את‬
}
 ‫תרגול‬9
8  ©  ‫ שמורות‬ ‫ הזכויות‬ ‫ כל‬ .‫ לביולוגים‬ ‫תכנות‬  2

You might also like