דוגמא

‫תרגול מספר ‪6‬‬
‫רקורסיות‬
‫נושאי התרגול‪:‬‬
‫‪.1‬‬
‫‪.2‬‬
‫‪.3‬‬
‫‪.4‬‬
‫‪.5‬‬
‫‪.6‬‬
‫דוגמא ‪ :1‬הדפסת שעון חול‬
‫דוגמא ‪ :2‬פלינדרום‬
‫דוגמא ‪ :3‬מציאת משקל נתון ע"י צירוף משקלות‬
‫דוגמא ‪ :4‬מטריצה משופעת‬
‫דוגמא ‪ :5‬המבוך‬
‫דוגמא ‪ :6‬הפיכת מחרוזת‬
‫דוגמא ‪:1‬‬
‫נכתוב פונקציה רקורסיבית שמציירת משולש הפוך בגובה של ‪ n‬שורות‪.‬‬
‫לדוגמא‪ ,‬עבור ‪ n=7‬נקבל את המשולש‪:‬‬
‫*******‬
‫******‬
‫*****‬
‫****‬
‫***‬
‫**‬
‫*‬
‫דרך פעולה‬
‫נדפיס ‪ n‬כוכביות בשורה‪ ,‬ואז נדפיס משולש בגובה ‪.n-1‬‬
‫תנאי העצירה יהיה כאשר נגיע להדפיס משולש בגובה ‪.0‬‬
‫נדפיס משולש בגובה ‪ n-1‬ונוסיף עוד שורת כוכביות באורך ‪.n‬‬
‫הקוד‬
‫{ )‪public static void drawTriangle(int n‬‬
‫;‪int i‬‬
‫{ )‪if (n > 0‬‬
‫)‪for (i=0; i<n; i=i+1‬‬
‫;)'*'(‪System.out.print‬‬
‫;)(‪System.out.println‬‬
‫;)‪drawTriangle(n-1‬‬
‫}‬
‫}‬
‫‪Page 1‬‬
‫‪Practical session #6‬‬
??‫מה היה קורה אם היינו רוצים להדפיס משולש ישר‬
:n ‫ ואז להדפיס שורה של כוכביות באורך‬,n-1 ‫ עם‬drawTriangle -‫היינו צריכים קודם לקרוא ל‬
public static void drawTriangle2(int n) {
int i;
if (n > 0) {
drawTriangle2(n-1);
for (i=0; i<n; i=i+1)
System.out.print('*');
System.out.println();
}
}
‫ניתן להבחין שהפונקציה הראשונה הינה רקורסיית זנב היות והשורה אחרונה של הפונקציה היא הקריאה‬
.‫הרקורסיבית‬
?‫מה יקרה אם נשלב בין שני החלקים‬
public static void drawHourGlass(int n) {
int i;
if (n > 0) {
for (i=0; i<n; i=i+1)
System.out.print('*');
System.out.println();
drawHourGlass(n-1);
for (i=0; i<n; i=i+1)
System.out.print('*');
System.out.println();
}
}
:‫נקבל‬
*****
****
***
**
*
*
**
***
****
*****
Practical session #6
Page 2
‫דוגמא ‪:2‬‬
‫כתבו פונקציה רקורסיבית שמקבלת מחרוזת ומחזירה ‪ true‬אם היא פָ לִינְדְ רֹום ו‪ false -‬אחרת‬
‫)‪public static boolean isPalindrome (String pal‬‬
‫תזכורת‪ :‬פָ לִינְדְ רֹום היא מחרוזת שניתן לקרוא משני הכיוונים‪ ,‬משמאל לימין ומימין לשמאל‪ ,‬ולקבל אותה מילה‪.‬‬
‫דוגמא‪ :‬המחרוזות ‪ madam‬ו‪ noon-‬הן פָ לִינְדְ רֹום (וגם "ילד כותב בתוך דלי")‪ ,‬לעומת זאת המחרוזת ‪ hello‬אינה‬
‫פָ לִינְדְ רֹום‪.‬‬
‫הנחת יסוד‪ :‬מחרוזת ריקה (ללא תווים) ומחרוזת בעלת תו אחד הן ָפלִינְדְ רֹום‪.‬‬
‫דרך פעולה‬
‫מקרה הבסיס‪:‬‬
‫אם מדובר במחרוזת ריקה (ללא תווים) או במחרוזת בעלת תו אחד ניתן להחזיר ‪,true‬‬
‫אחרת‪ ,‬נבדוק עבור מחרוזת קטנה יותר (הקטנת הבעיה) ע"י צמצום המחרוזת בתו אחד מכל צד‬
‫אם הפעלת הפונקציה הרקורסיבית על המחרוזת המוקטנת תחזיר ‪ true‬וגם שני התווים הקיצוניים שהורדנו‬
‫מהמחרוזת המקורית שווים‪ ,‬נחזיר ‪ ,true‬אחרת נחזיר ‪.false‬‬
‫הקוד‬
‫{ )‪public static boolean isPalindrome(String pal‬‬
‫;‪boolean isPal = false‬‬
‫;)(‪int length = pal.length‬‬
‫‪if (length == 0 || length == 1) // can be “if (length <= 1)” instead‬‬
‫;‪isPal = true‬‬
‫{ ‪else‬‬
‫&& )‪isPal = (pal.charAt(0) == pal.charAt(length - 1‬‬
‫;)))‪isPalindrome(pal.substring(1, length - 1‬‬
‫}‬
‫;‪return isPal‬‬
‫}‬
‫דוגמא ‪:3‬‬
‫בהינתן מערך של משקולות ומשקל נוסף‪ ,‬נרצה לבדוק האם ניתן להרכיב מהמשקולות משקל השווה למשקל‬
‫הנתון‪.‬‬
‫דוגמא לקלט‪:‬‬
‫}‪weights={1,7,9,3‬‬
‫‪Sum = 12‬‬
‫במקרה זה הפונקציה תחזיר ‪ true‬כי ניתן לחבר את המשקולות ‪ 9‬ו ‪ 3‬ולקבל את הסכום ‪.12‬‬
‫דוגמא לקלט‪:‬‬
‫}‪weights={1,7,9,3‬‬
‫‪Sum = 15‬‬
‫במקרה זה הפונקציה תחזיר ‪ false‬כי לא ניתן לחבר משקולות לקבלת הסכום ‪.15‬‬
‫‪Page 3‬‬
‫‪Practical session #6‬‬
‫דרך פעולה‬
‫קיימים שני מקרי בסיס‪:‬‬
‫‪ .1‬הגענו לסכום הדרוש או במילים אחרות הסכום הנותר הינו אפס‪.‬‬
‫הגענו לסוף המערך – עברנו על כל האיברים ולא מצאנו צירוף של איברים שסכומם שווה‬
‫‪.2‬‬
‫לסכום הנדרש‪.‬‬
‫נתבונן באיבר הראשון במערך‪ .‬ייתכן שהוא ייבחר לקבוצת המשקולות שתרכיב את ‪ sum‬ויתכן שלא‪.‬‬
‫‪ ‬אם הוא לא ייבחר – אזי נותר לפתור בעיה קטנה יותר והיא האם ניתן להרכיב את הסכום‬
‫‪ sum‬מבין המשקולות שבתאים ]‪weights[1..length - 1‬‬
‫‪ ‬אם הוא ייבחר – אזי נותר לפתור בעיה קטנה יותר והיא האם ניתן להרכיב את הסכום‬
‫]‪ sum  weights[0‬מבין המשקולות שבתאים ‪weights[1..length - 1] .‬‬
‫וכנ"ל לגבי יתר האיברים בצורה רקורסיבית‪.‬‬
‫פתרון זה קל נותר להציג כפונקציה רקורסיבית )‪ , calcWeight s(int[] weights ,int i, int sum‬אשר‬
‫מקבלת בנוסף על ‪ sum‬ו ‪ weights‬פרמטר נוסף ‪ i‬ומחזירה האם ניתן להרכיב את הסכום ‪ sum‬מבין‬
‫קבוצת המשקולות שבתת המערך ]‪weights [i..length  1‬‬
‫הקוד‬
‫{ )‪public static boolean calcWeights(int[] weights, int sum‬‬
‫;)‪return calcWeights(weights, 0, sum‬‬
‫}‬
‫{ )‪public static boolean calcWeights(int[] weights, int i, int sum‬‬
‫;‪boolean res = false‬‬
‫)‪if (sum == 0‬‬
‫;‪res = true‬‬
‫)‪else if (i >= weights.length‬‬
‫;‪res = false‬‬
‫‪else‬‬
‫|| )]‪res = (calcWeights(weights, i + 1, sum - weights[i‬‬
‫;))‪calcWeights(weights, i + 1, sum‬‬
‫;‪return res‬‬
‫}‬
‫עבור כל משקולת יש את האפשרות לבחור אותה לסכום או לא לבחור אותה‪ .‬עובדה זו באה לידי ביטוי‬
‫בקריאה הרקורסיבית‪.‬‬
‫‪Page 4‬‬
‫‪Practical session #6‬‬
‫דוגמא ‪:4‬‬
‫מטריצה ריבועית תקרא משופעת אם‪:‬‬
‫‪ .1‬כל איברי האלכסון הראשי שווים לאפס‪.‬‬
‫‪ .2‬כל האיברים שנמצאים מתחת לאלכסון הראשי הם שליליים‪.‬‬
‫‪ .3‬כל האיברים שנמצאים מעל לאלכסון הראשי הם חיוביים‪.‬‬
‫כתבו פונקציה רקורסיבית המקבלת מטריצה ריבועית מלאה במספרים‪ ,‬ומחזירה ‪ true‬אם היא משופעת ו‪false-‬‬
‫אחרת‪.‬‬
‫מטריצה משופעת‪:‬‬
‫‪4‬‬
‫‪2‬‬
‫‪1‬‬
‫‪0‬‬
‫‪7‬‬
‫‪5‬‬
‫‪0‬‬
‫‪-2‬‬
‫‪3‬‬
‫‪0‬‬
‫‪-1‬‬
‫‪-8‬‬
‫‪0‬‬
‫‪-6‬‬
‫‪-9‬‬
‫‪-3‬‬
‫מטריצה לא משופעת‪:‬‬
‫‪4‬‬
‫‪2‬‬
‫‪1‬‬
‫‪0‬‬
‫‪7‬‬
‫‪5‬‬
‫‪0‬‬
‫‪-2‬‬
‫‪3‬‬
‫‪6‬‬
‫‪-1‬‬
‫‪-8‬‬
‫‪0‬‬
‫‪-6‬‬
‫‪9‬‬
‫‪-3‬‬
‫דרך פעולה‬
‫שלב ‪ :I‬ראשית נשים לב כי אם ניקח מטריצה משופעת ונחסיר ממנה את השורה הראשונה ואת העמודה‬
‫הראשונה‪ ,‬נקבל מטריצה משופעת‪.‬‬
‫כעת נרצה לבדוק האם השורה והעמודה שהחסרנו מקיימות את התנאים של מטריצה משופעת‪.‬‬
‫מהם תנאים אלו? כיצד ניתן לבצע זאת בצורה רקורסיבית?‬
‫פתרון רקורסיבי‪:‬‬
‫בהינתן מטריצה ריבועית ‪ data‬ואינדקס מסוים ‪( i‬שיהיה מספר של שורה‪/‬עמודה חוקית)‪ ,‬נרצה לבדוק האם‬
‫השורה והעמודה של תת המטריצה המתחילה במיקום ]‪ [i][i‬מקיימות את התנאים‪.‬‬
‫(הרעיון‪ :‬נתחיל מאינדקס ]‪ ,[i][i‬וכל פעם נתקדם תא אחד ימינה ותא אחד למטה ונבדוק האם הם מקיימים את‬
‫התנאים‪ .‬נעצור כאשר התנאים לא מתקיימים או כאשר סיימנו לעבור על כל תאי השורה והעמודה)‪.‬‬
‫‪Page 5‬‬
‫‪Practical session #6‬‬
‫הקוד‬
public static boolean check(int[][] data, int index) {
return (data[index][index] == 0 &&
check(data, index, 1));
}
public static boolean check(int[][] data, int index, int diff) {
boolean flag = false;
if (index+diff == data.length)
flag = true;
else if (data[index][index+diff] <= 0 ||
data[index+diff][index] >= 0)
flag = false;
else
flag = check(data, index, diff+1);
return flag;
}
:)I ‫פתרון איטרטיבי (לשלב‬
// Check if row index, in data array, contains positive numbers and column
index contains negative numbers (starting from index to the right && down)
public static boolean check(int[][] data, int index) {
boolean flag = (data[index][index] == 0);
for ( int diff = 1;
(diff < data.length - index) && flag;
diff = diff + 1) {
if (data[index][index+diff] <= 0 || data[index+diff][index] >= 0)
flag = false;
}
return flag;
}
.‫ בדיקה האם המטריצה כולה משופעת‬:II ‫שלב‬
.‫ כעת נצטרך לבדוק האם כל המטריצה היא משופעת‬.‫ מצאנו האם שורה ועמודה הן חוקיות‬I ‫בשלב‬
‫בכל שלב של הרקורסיה נתייחס למטריצה קטנה יותר (נתקדם לאורך האלכסון) ונבדוק אם תת המטריצה היא‬
.‫שיפועית וגם שאר התנאים עבור המטריצה הנוכחית מתקיימים‬
?‫מהו מקרה הבסיס? ומה נבצע עבורו‬
.‫ ולכן נבדוק אם מכילה אפס‬1x1 ‫ תת המטריצה בגודל‬:‫תשובה‬
Practical session #6
Page 6
‫הקוד‬
‫{ )‪public static boolean slope(int[][] data‬‬
‫;)‪return slope(data, 0‬‬
‫}‬
‫{ )‪public static boolean slope(int[][] data, int index‬‬
‫;‪boolean isSlope = false‬‬
‫‪// end of array – last cell, if it’s 0 than it’s OK‬‬
‫{ )‪if (index == data.length - 1‬‬
‫{ )‪if (data[index][index] == 0‬‬
‫;‪isSlope = true‬‬
‫}‬
‫{ ‪else‬‬
‫;‪isSlope = false‬‬
‫}‬
‫}‬
‫‪else‬‬
‫;))‪isSlope = (check(data,index) && slope(data, index+1‬‬
‫;‪return isSlope‬‬
‫}‬
‫‪ ‬כפי שציינו בתרגולים‪ ,‬הרעיון ברקורסיה הוא שאנו מניחים שהפונקציה יודעת לפתור בעיה קטנה יותר‬
‫מהבעיה המקורית ומבצעים צעד למציאת הפתרון לבעיה הגדולה יותר‪.‬‬
‫דוגמא ‪ :5‬המבוך‬
‫המבוך‪" :‬דני הקטן הלך לאיבוד‪ ,‬אנא עזרו לו למצוא את דרכו הביתה"‪.‬‬
‫נתון מערך דו‪-‬מימדי ‪ n x m‬של שלמים‪ ,‬המתאר מבוך‪:‬‬
‫נקודת ההתחלה היא )‪ ,(0,0‬נקודת הסיום היא )‪ ,(n-1,m-1‬במצב ההתחלתי לכל תא ערך ‪ 0‬או ‪ ,1‬כאשר ‪ 1‬מסמל‬
‫"דרך פנויה" ו‪ 0-‬מסמל "דרך חסומה" (קיר)‪ .‬בנוסף‪ ,‬נסמן ב‪ 3-‬את התאים שבהם כבר ביקרנו כדי שלא נחזור‬
‫אליהם שנית וכן נסמן ב‪ 7-‬את הדרך מההתחלה אל הסיום‪ .‬הכיוונים המותרים הם למטה‪ ,‬ימינה‪ ,‬למעלה‬
‫ושמאלה‪.‬‬
‫‪Page 7‬‬
‫‪The Solution:‬‬
‫‪The Maze:‬‬
‫‪7770110001111‬‬
‫‪3077707771001‬‬
‫‪0000707070300‬‬
‫‪7770777070333‬‬
‫‪7070000773003‬‬
‫‪7077777703333‬‬
‫‪7000000000000‬‬
‫‪7777777777777‬‬
‫‪1110110001111‬‬
‫‪1011101111001‬‬
‫‪0000101010100‬‬
‫‪1110111010111‬‬
‫‪1010000111001‬‬
‫‪1011111101111‬‬
‫‪1000000000000‬‬
‫‪1111111111111‬‬
‫‪Practical session #6‬‬
‫לפני שנממש את הפונקציה נתאר את אלגוריתם הפתרון הרקורסיבי‪ .‬האלגוריתם נעזר בפונקציה‬
‫)‪ valid(grid, row, col‬המקבלת כקלט מבוך‪ ,‬שורה וטור ומחזירה ערך בוליאני – ‪ true‬אם התא במבוך המוגדר‬
‫ע"י השורה והטור הוא תא חוקי (כלומר לא חורג מגבולות המבוך)‪ ,‬פנוי ולא ביקרנו בו כבר (כלומר‪ ,‬מסומן ב‪ ,)1-‬ו‪-‬‬
‫‪ false‬אחרת‪ .‬קריאות לפונקציות מודגשות בקו‪.‬‬
‫)‪solve(grid, row, col‬‬
‫‪ ‬הגדר משתנה בוליאני בשם ‪ done‬ואתחל אותו ל‪false-‬‬
‫‪ ‬אם ( )‪,) valid(grid, row, col‬‬
‫‪ o‬סמן ב‪ grid-‬את תא ]‪ [row][col‬במספר ‪ */ 3‬סימון שביקרנו בתא ואין צורך לבקר בו שוב *‪/‬‬
‫‪ o‬אם ( ‪ row‬היא השורה התחתונה ב‪ grid-‬וגם ‪ col‬הוא הטור הימני ב‪ */ ,) grid-‬תנאי עצירה *‪/‬‬
‫‪ ‬שנה את ערכו של ‪ done‬ל‪ */ true-‬הגענו ליציאה *‪/‬‬
‫‪ o‬אחרת‪,‬‬
‫‪ ‬שנה את ערכו של ‪ done‬ל‪ */ solve(grid, row+1, col)-‬נסה למטה *‪/‬‬
‫‪ ‬אם ( ‪ done‬הינו ‪,) false‬‬
‫שנה את ערכו של ‪ done‬ל‪ */ solve(grid, row, col+1)-‬נסה ימינה *‪/‬‬
‫‪ ‬אם ( ‪ done‬הינו ‪,) false‬‬
‫שנה את ערכו של ‪ done‬ל‪ */ solve(grid, row-1, col)-‬נסה למעלה *‪/‬‬
‫‪ ‬אם ( ‪ done‬הינו ‪,) false‬‬
‫שנה את ערכו של ‪ done‬ל‪ */ solve(grid, row, col-1)-‬נסה שמאלה *‪/‬‬
‫‪ o‬אם ( ‪ done‬הינו ‪,) true‬‬
‫‪ ‬סמן ב‪ grid-‬את תא ]‪ [row][col‬במספר ‪ */ 7‬תא זה הוא חלק מהפתרון *‪/‬‬
‫‪ ‬החזר את ‪done‬‬
‫הערה‪ :‬המשימה שלנו היא למצוא מעבר מנקודת ההתחלה לנקודת הסיום‪ ,‬אך נשים לב שהאלגוריתם למעלה אינו‬
‫מתחיל דווקא בנקודת ההתחלה‪ ,‬אלא ימצא את הדרך ליציאה מכל נקודה במבוך‪ .‬הקריאה הראשונה לאלגוריתם‬
‫תעביר כקלט את הכניסה בתור שורה ‪ 0‬וטור ‪.0‬‬
‫הקוד‬
‫{ )‪public static boolean solve(int[][] grid, int row, int col‬‬
‫;‪boolean done = false‬‬
‫{ ))‪if (valid(grid, row, col‬‬
‫;‪grid[row][col] = 3‬‬
‫‪// cell has been tried‬‬
‫)‪if (row == grid.length - 1 && col == grid[0].length - 1‬‬
‫‪done = true; // maze is solved‬‬
‫{ ‪else‬‬
‫‪done = solve(grid, row + 1, col); // try down‬‬
‫)‪if (!done‬‬
‫‪done = solve(grid, row, col + 1); // try right‬‬
‫)‪if (!done‬‬
‫‪done = solve(grid, row - 1, col); // try up‬‬
‫)‪if (!done‬‬
‫‪done = solve(grid, row, col - 1); // try left‬‬
‫}‬
‫)‪if (done‬‬
‫‪grid[row][col] = 7; // part of the final path‬‬
‫}‬
‫;‪return done‬‬
‫‪} // function solve‬‬
‫‪Page 8‬‬
‫‪Practical session #6‬‬
‫דוגמת הרצה ( ‪ +‬הסבר)‪:‬‬
‫לפני הקריאה הראשונה לפונקציה הרקורסיבית המבוך נראה כך‪:‬‬
‫‪1110110001111‬‬
‫‪1011101111001‬‬
‫‪0000101010100‬‬
‫‪1110111010111‬‬
‫‪1010000111001‬‬
‫‪1011111101111‬‬
‫‪1000000000000‬‬
‫‪1111111111111‬‬
‫בשלב כלשהו בריצה‪ ,‬אנו נמצאים בקריאה אשר סימנה ב‪ 3-‬את התא המודגש‪:‬‬
‫‪3330110001111‬‬
‫‪3033301111001‬‬
‫‪0000301010100‬‬
‫‪1110333010111‬‬
‫‪1010000111001‬‬
‫‪1011111101111‬‬
‫‪1000000000000‬‬
‫‪1111111111111‬‬
‫בשלב זה תהיה קריאה רקורסיבית על המשבצת מתחתיה‪ ,‬משבצת בה המסומנת ב‪ ,0-‬כלומר קיר‪.‬‬
‫בדיקת ה‪ valid-‬תחזיר ‪ false‬ואותה קריאה תסתיים‪.‬‬
‫תתבצע קריאה נוספת מהמשבצת המסומנת‪ ,‬הפעם ימינה‪ ,‬ובדיקת ה‪ valid-‬תיכשל שוב‪.‬‬
‫בקריאה הבאה מהמשבצת המסומנת‪ ,‬הפעם למעלה‪ ,‬בדיקת ה‪ valid-‬תחזיר ‪.true‬‬
‫המשבצת תסומן ב‪ 3-‬והריצה תמשיך‪.‬‬
‫‪3330110001111‬‬
‫‪3033301111001‬‬
‫‪0000303010100‬‬
‫‪1110333010111‬‬
‫‪1010000111001‬‬
‫‪1011111101111‬‬
‫‪1000000000000‬‬
‫‪1111111111111‬‬
‫בסיום הריצה‪ ,‬כשהגענו אל היציאה‪ ,‬הדרך תסומן ב‪ 7-‬והמבוך יראה כך‪:‬‬
‫‪:‬‬
‫‪Maze solved!:‬‬
‫‪7770110001111‬‬
‫‪3077707771001‬‬
‫‪0000707070300‬‬
‫‪7770777070333‬‬
‫‪7070000773003‬‬
‫‪7077777703333‬‬
‫‪7000000000000‬‬
‫‪7777777777777‬‬
‫דיון‪:‬‬
‫שאלה‪ :‬מה היה יכול לקרות אם לא היינו מסמנים כל תא שבדקנו (כאן סימון זה היה המספר ‪?)3‬‬
‫שאלה‪ :‬האם תמיד יש פתרון אחד? אם לא‪ ,‬איזה פתרון נמצא?‬
‫‪Page 9‬‬
‫‪Practical session #6‬‬
:main-‫ ו‬valid, print_maze ‫ כולל פונקציות‬,‫קוד המחלקה המלאה‬
public class Maze {
public static boolean solve(int[][] grid, int row, int col) {
boolean done = false;
if (valid(grid, row, col)) {
grid[row][col] = 3; // cell has been tried
if (row == grid.length - 1 && col == grid[0].length - 1)
done = true; // maze is solved
else {
done = solve(grid, row + 1, col); //try down
if (!done)
done = solve(grid, row, col + 1);// try right
if (!done)
done = solve(grid, row - 1, col);// try up
if (!done)
done = solve(grid, row, col - 1);// try left
}
if (done)
grid[row][col] = 7; // part of the final path
}
return done;
}
private static boolean valid(int[][] grid, int row, int col) {
boolean result = false;
// check if cell is in the bounds of the matrix
if (row >= 0 && row < grid.length && col >= 0 && col < grid[0].length)
// check if cell is not blocked and not previously tried
if (grid[row][col] == 1)
result = true;
return result;
}
public static void print_maze(int[][] maze) {
for (int i = 0; i < maze.length; i = i + 1) {
for (int j = 0; j < maze[0].length; j = j + 1)
System.out.print(maze[i][j]);
System.out.println();
}
System.out.println();
}
Practical session #6
Page 10
‫{ )‪public static void main(String[] args‬‬
‫‪int[][] grid = {{1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1},‬‬
‫‪{1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1},‬‬
‫‪{0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0},‬‬
‫‪{1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1},‬‬
‫‪{1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1},‬‬
‫‪{1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1},‬‬
‫‪{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},‬‬
‫;}}‪{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1‬‬
‫;)"‪System.out.println("The labyrinth:\n‬‬
‫;)‪print_maze(grid‬‬
‫;)‪boolean ans = solve(grid, 0, 0‬‬
‫{ )‪if (ans‬‬
‫;)"‪System.out.println("Maze solved!:\n‬‬
‫;)‪print_maze(grid‬‬
‫}‬
‫‪else‬‬
‫;)"‪System.out.println("There is no solution‬‬
‫}‬
‫}‬
‫דוגמא ‪:6‬‬
‫כתבו פונקציה רקורסיבית שמקבלת מחרוזת ומחזירה את המחרוזת הפוכה‪.‬‬
‫דוגמא‪ :‬עבור הקלט ”‪ “hello‬הפונקציה תחזיר את הפלט ”‪.“olleh‬‬
‫דרך פעולה‬
‫מקרה הבסיס‪:‬‬
‫אם מדובר במחרוזת ריקה (ללא תווים) או במחרוזת בעלת תו אחד ניתן להחזיר את התו עצמו (ובמקרה‬
‫של ריקה להחזיר ""(‬
‫אחרת‪ ,‬נמצא את המחרוזת ההפוכה של מחרוזת קטנה יותר (הקטנת הבעיה) ע"י צמצום המחרוזת בתו אחד‬
‫השמאלי‪ ,‬ונוסיף את התו השמאלי מימין למחרוזת ההפוכה שנקבל מהקריאה הרקורסיבית‪.‬‬
‫הקוד‬
‫{)‪public static String reverse(String s‬‬
‫;"" = ‪String res‬‬
‫)‪if (s.length()==0‬‬
‫;‪res = s‬‬
‫‪else‬‬
‫;)‪res = reverse(s.substring(1)) + s.charAt(0‬‬
‫;‪return res‬‬
‫}‬
‫שימו לב‪ :‬הפונקציה )‪ s.substring(i‬מחזירה את המחרוזת ‪ s‬ממקום ‪.i‬‬
‫‪ ‬ניתן להבחין שהפונקציה הזו אינה פונקצית זנב מכיוון שיש הוספת תו לאחר הקריאה הרקורסיבית‪.‬‬
‫‪Page 11‬‬
‫‪Practical session #6‬‬