1 / 36

קורס תכנות

קורס תכנות. שיעור תשיעי: רקורסיה. מודל הזיכרון של התכנית. הקוד פקודות התכנית Data מחרוזות שהוגדרו ע"י המתכנת מחסנית ( Stack ) משמש לאיחסון משתנים לוקאליים Last In First Out (LIFO) בשליטת התכנית ערימה ( Heap ) בשליטת המתכנת (בהמשך הקורס). קוד. קריאה בלבד. Data. מחסנית. קריאה

kaycee
Download Presentation

קורס תכנות

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. קורס תכנות שיעור תשיעי: רקורסיה

  2. מודל הזיכרון של התכנית • הקוד • פקודות התכנית • Data • מחרוזות שהוגדרו ע"י המתכנת • מחסנית (Stack) • משמש לאיחסון משתנים לוקאליים • Last In First Out (LIFO) • בשליטת התכנית • ערימה (Heap) • בשליטת המתכנת (בהמשך הקורס) קוד קריאה בלבד Data מחסנית קריאה וכתיבה ערימה

  3. הרצת התכנית - שלבים • טעינת התכנית מהדיסק לזיכרון • הקוד לחלק הקוד, המחרוזות הקבועות לחלק הקבוע • הקצאת Stack Frame עבור הפונקציה main • הקצאת מקום במחסנית עבור המשתנים המקומיים של main • קריאה לפונקציה main • ביצוע סדרתי של פקודות התכנית • קריאה לפונקציה – הקצאה של Stack Frame עבור הפונקציה וביצוע הקוד שלה • חזרה מקריאה – ביטול ה Stack Frame וחזקה להמשך ביצוע הפקודות ממקום הקריאה

  4. קריאה ל strlen main strstr if (*needle == '\0') return (char *) haystack; needlelen = strlen(needle); for ( ; (haystack = strchr(haystack, *needle)) != NULL; haystack++) if (strncmp(haystack, needle, needlelen) == 0) return (char *) haystack; return NULL; strlen

  5. n פעמים רקע: הגדרת נוסחאות • דרך מקובלת להגדיר נוסחה או פעולה מתמטית היא לרשום את שלבי החישוב שלה: n! = 1*2*3*….*n an = a*a*…..*a • מקובל גם לחשב את ערך הנוסחה שלב-אחר-שלב למשל: 4! = 1*2*3*4 = 2*3*4 = 6*4 = 24

  6. דוגמא - עצרת הגדרה איטרטיבית n! = n * (n-1) * (n-2) * ...* 3 * 2 * 1 n! = n * (n-1)! 1! = 1 הגדרה רקורסיבית 5! = 5 * 4! 4! = 4 * 3! 3! = 3 * 2! 2! = 2 * 1!

  7. דוגמא - חזקה הגדרה איטרטיבית an = a * a * a * ...* a * a * a an = a * an-1 a0 = 1 הגדרה רקורסיבית 25 = 2 * 24 24 = 2 * 23 23 = 2 * 22 22 = 2 * 21

  8. הגדרה רקורסיבית • מקרה קצה פשוט (תנאי עצירה) • כלל כיצד לצמצם את כל המקרים האחרים ב"כיוון" מקרה הקצה

  9. יתרונות • קצר • בהרבה מקרים, ההגדרה הרקורסיבית קצרה בהרבה מהאיטרטיבית • נוח • במקרים מסוימים, ההגדרה הרקורסיבית היא ההגדרה הטבעית והנוחה ביותר של מה שרוצים לחשב

  10. דוגמא - סדרת פיבונאצ'י • איברי הסדרה • שני האיברים הראשונים הם 1 ו- 1. • שאר האיברים מוגדרים כסכום שני האיברים שלפניהם 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ... Fib(1) = 1 Fib(2) = 1 Fin(n) = Fin(n-1) + Fib(n-2)

  11. אז... • זה נורא מעניין, אבל איך זה קשור אלינו? • פונקציות ב C קוראות לפונקציות אחרות בפרט לעצמן! • עצרת • פיבונאצ'י • int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intfibonaci(int n) /* n > 0 */ { return (n == 1 || n == 2) ? 1 : fibonacci(n-1) + fibonacci(n-2); }

  12. סדרת פיבונאצ'י - איטרטיבי int fib(int n) { inti, next, fib1 = 1, fib2 = 1; if (n == 1 || n == 2) return 1; for (i = 3; i <= n; i++) { next = fib1 + fib2; fib1 = fib2; fib2 = next; } return fib2; }

  13. דוגמת הרצה int main() { printf("%d\n", factorial(3)); return0; { 3 2 1 0 main factorial factorial factorial factorial 3*2 2*1 1*1 1

  14. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • {

  15. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • {

  16. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • {

  17. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • {

  18. בסיס הרקורסיה • int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • { 1

  19. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • { 1

  20. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • { 2

  21. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • { 6

  22. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • {

  23. int factorial(int n) /* n >= 0 */ { return (n == 0) ? 1 : n * factorial(n - 1); } • intmain() • { • printf("%d\n", factorial(3)); • return0; • {

  24. נקודות לתשומת-לב: משתנים • כשקוראים לפונקציה מתוך עצמה, משתנים שהוגדרו בפונקציה הקוראת נשארים בזיכרון. • כי המשתנים נשארים בזיכרון עד שהפונקציה מסתיימת. • הרבה מאוד קריאות רקורסיביות עלולות למלא את הזיכרון של המחשב

  25. שימוש ברקורסיה • מצד אחד: • לפעמים לשימוש ברקורסיה יש יתרון - קל יותר לכתוב באמצעותו את החישוב • מצד שני: • לא תמיד קל למצוא הגדרה רקורסיבית לפונקציה • לא תמיד קל להבין תוכניות שנכתבו באופן רקורסיבי • לכן נבחר להשתמש ברקורסיה במקרים שבאמת נוחים לכך.

  26. רקורסיה – שימושים נוספים • לא רק לחישוב נוסחאות • אפשר להשתמש בה עבור כל בעיה שניתן לפתור על-ידי פתרון של מקרה יותר קטן/פשוט שלה • סכום מערך (האיבר הראשון וסכום שאר המערך) • strchr (התו הנוכחי או חיפוש בשאר המחרוזת) • ...

  27. סכום מערך intsum_array(int array[], int size) { if (size == 0) return 0; return array[0] + sum_array(array + 1, size - 1); }

  28. עוד דוגמאות • strchr • strlen char* strchr(const char *str, char c) { if (*str == '\0') return NULL; if (*str == c) return str; return strchr(str + 1, c); } intstrlen(const char *str) { if (*str == '\0') return 0; return 1 + strlen(str + 1); {

  29. חיפוש בינארי במערך ממויין int binarySearch(int *arr, int size, int num) { int mid = size/2; if ( size == 0 ) return 0; if ( size == 1 ) return (arr[0] == num); if ( arr[ mid ] == num ) return 1; if ( arr[ mid ] > num ) return binarySearch( arr, mid, num ); return binarySearch( arr+mid+1, size-mid-1, num ); } • תנאי עצירה: • מערך בגודל 0. • מערך בגודל 1. • המספר נמצא באמצע המערך. נחפש בחצי השמאלי נחפש בחצי הימני

  30. Towers of Hanoi • משימה: • העבירו את כל הדיסקיות ממגדל A למגדל C A B C

  31. Towers of Hanoi • חוקים: • מותר להזיז רק את הדיסקית העליונה • אסור להניח דיסקית גדולה על דיסקית קטנה A B C

  32. Towers of Hanoi • הזזת מגדל בין nדיסקיות שקולה ל- • הזזת מגדל בין n-1דיסקיות A B C

  33. Towers of Hanoi • הזזת מגדל בין nדיסקיות שקולה ל- • הזזת דיסקית אחת A B C

  34. Towers of Hanoi • הזזת מגדל בין nדיסקיות שקולה ל- • הזזת מגדל בין n-1דיסקיות A B C

  35. Towers of Hanoi - C voidmove_disk(char from, char to) { printf("move disk from %c to %c\n", from, to); } voidmove_tower(int height, char from, char to, char temp) { if (height == 1) { move_disk(from, to); } else { move_tower(height - 1, from, temp, to); move_disk(from, to); move_tower(height - 1, temp, to, from); } }

  36. רקורסיה - סיכום • פונקציה רקורסיבית היא פונקציה שקוראת לעצמה • מוגדרת בעזרת הפעלתה עבור פרמטרים יותר קטנים/פשוטים, • נדרש תנאי התחלה עבור פרמטר כלשהו, שמובטח שנגיע אליו במהלך החישוב. • קל לתרגם נוסחה רקורסיבית לפונקציה רקורסיבית • לא תמיד קל למצוא ניסוח רקורסיבי אם הוא לא נתון

More Related