1 / 53

Chapter 3

Chapter 3. Recursion. Iterative algorithm for n factorial. n factorial n! = 1 if n = 0 n! = n*(n-1)*(n-2)*...*1 if n>0 Iterative algorithm prod = 1; for (x = n; x > 0; x--) prod *= x; return (prod);. Recursive definition for n factorial. recursive definition:

indiya
Télécharger la présentation

Chapter 3

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. Chapter 3 Recursion

  2. Iterative algorithm for n factorial • n factorial n! = 1 if n = 0n! = n*(n-1)*(n-2)*...*1 if n>0 • Iterative algorithmprod = 1; for (x = n; x > 0; x--) prod *= x; return(prod);

  3. Recursive definition for n factorial • recursive definition: n! = 1 if n = 0 n! = n * (n-1)! if n > 0

  4. Recursive program for n factorial int fact(int n) { int x, y; if (n == 0) //boundary condition return(1); x = n-1; y = fact(x); return(n*y); } /* end fact */

  5. Stack and function call in C e.g. printf(“%d”, fact(3)) (a)(initially) (b)fact(3) (c)fact(2) (d)fact(1) (e)fact(0) (f)y=fact(0)

  6. (g)y=fact(1) (h)y=fact(2) (i)printf(“%d”, fact(3)) • The stack varies during execution. (from (a) to (i)) • (An asterisk indicates an uninitialized value.)

  7. Common errors • Calling printf(“%d”, fact(-1)) would cause infinite loops • It is invalid to define there must be a boundary condition. • Concise code: int fact(int n) { return( n == 0 ? 1 : n * fact(n-1)); } /* end fact */

  8. Error checking for n < 0 int fact(int n) { int x, y; if (n < 0) { printf(“%s”, “negative parameter in the factorial function”); exit(1); } /* end if */ if (n == 0) return(1); x = n-1; y = fact(x); return(n*y); } /* end fact */

  9. Multiplication of natural numbers a * b = a if b = 1 a * b = a * (b-1) + a if b > 1 int mult(int a, int b) { int c, d, sum; if (b == 1) return(a); c = b-1; d = mult(a, c); sum = d+a; return(sum); } /* end mult */

  10. Concise code: int mult(int a, int b) { return(b == 1 ? a : mult(a, b-1) + a); } /* end mult */ • Invalid definition: a * b = a * (b+1) - a

  11. Fibonacci sequence (1) • 0,1,1,2,3,5,8,13,21,34,... • Leonardo Fibonacci (1170 -1250)用來計算兔子的數量每對每個月可以生產一對兔子出生後, 隔一個月才會生產, 且永不死亡 生產0 1 1 2 3 ... 總數 1 1 2 3 5 8 ... http://www.mcs.surrey.ac.uk/Personal/R.Knott/Fibonacci/fibnat.html

  12. Fibonacci sequence (2) • 0,1,1,2,3,5,8,13,21,34,...

  13. fn = 0 if n = 0 fn = 1 if n = 1 fn = fn-1 + fn-2 if n >= 2 Fibonacci sequence and golden number • 0,1,1,2,3,5,8,13,21,34,... 1 x-1 x

  14. Iterative algorithm for Fibonacci sequence fn = 0 if n = 0 fn = 1 if n = 1 fn = fn-1 + fn-2 if n  2 int fib(int n) { int i, x, logib, hifib; if (n <= 1) return(n); lofib = 0; hifib = 1; for (i = 2; i <= n; i++){ x = lofib; /* hifib, lofib*/ lofib = hifib; hifib = x + lofib; /* hifib = lofib + x */ } /* end for */ return(hifib); }

  15. Recursive algorithm for Fibonacci sequence fn = 0 if n = 0 fn = 1 if n = 1 fn = fn-1 + fn-2 if n  2 int fib(int n) { int x, y; if (n <= 1) return(n); x = fib(n-1); y = fib(n-2); return(x+y); } /* end fib */ • Concise code: int fib(int n) { if (n <= 1) return(n); return (fib(n-1) + fib(n-2)); }

  16. Stack simulation for fib(4)=3 (a) (b) (c) (d) (e) (f) (g) (h) (i) (j)

  17. (k) (l) (m) (n) (o) (p) (q)

  18. f5 f4 f3 f3 f2 f2 f1 f2 f1 f1 f0 f1 f0 f1 f0 The computation tree • Much computation is duplicated. • The iterative algorithm for generating Fibonacci sequence is better.

  19. e.g. 1 4 7 8 10 11 14 Search 6 Binary search • It is used for finding a given element in a sorted sequence stored in an array. binsrch(int a[],int x,int low,int high) { int mid; if (low > high) return(-1); while (high >= low){ mid = (low+high)/2; if (x == a[mid]) return(mid); if (x < a[mid]) high = mid-1; else low = mid+1; } return(-1); /* 未找到 */ }

  20. Recursive binary search int binsrch(int a[], int x, int low, int high) { int mid; if (low > high) return(-1); mid = (low+high) /2; return(x == a[mid] ? mid : x < a[mid] ? binsrch(a, x, low, mid-1) : binsrch(a, x, mid+1, high)); } /* end binsrch */

  21. Recursive chains a(formal parameters) { b(arguments); } /* end a */ b(formal parameters) { a(arguments); } /* end b */ • A recursive function need not call itself directly.

  22. expression term + term | term term factor * factor | factor factor letter | (expresssion) letter A | B | C | D | ... | Z Algebraic expressions e.g A : (A) : A+B : (A+B) : A*B : A*(B+C): (A+B*)C: A+B+C : **

  23. C program for checking expression #include <stdio.h> #include <ctype.h> #define TRUE 1 #define FALSE 0 #define MAXSTRINGSIZE 100 void readstr(char *, int); int expr(char *, int, int *); int term(char *, int, int *); int getsymb(char *, int, int *); int factor(char *, int, int *);

  24. void main() { char str[MAXSTRINGSIZE]; int length, pos; readstr(str, &length); pos = 0; if (expr(str, length, &pos) == TRUE && pos >= length) printf(“%s”, “valid”); else printf(“%s”, “invalid”); /* The condition can fail for one (or both) of two */ /* reasons. If expr(str, length, &pos) == FALSE */ /* then there is no valid expression beginning at */ /* pos. If pos < length, there may be a valid */ /* expression starting at pos but it does not */ /* occupy the entire string. */ } /* end main */

  25. int expr(char str[], int length, int *ppos) { /* look for a term */ if (term(str, length, ppos) == FALSE) return(FALSE); /* We have found a term; look at the */ /* next symbol. */ if (getsymb(str, length, ppos) != ‘+’){ /* We have found the longest expression */ /* (a single term). Reposition pos so */ /* it refers to the last position of */ /* the expression */ (*ppos)--; return(TRUE); } /* end if */ /* At this point, we have found a term */ /* and a plus sign. We must look for */ /* another term. */ return(term(str, length, ppos)); } /* end expr */

  26. int term(char str[], int length, int *ppos) { if (factor(str, length, ppos) == FALSE) return(FALSE); if (getsymb(str, length, ppos) != ‘*’){ (*ppos)--; return(TRUE); } /* end if */ return(factor(str, length, ppos)); } /* end term */ int factor(char str[], int length, int *ppos) { int c; if ((c = getsymb(str, length, ppos)) != ‘(‘) return(isalpha(c)); return(expr(str, length, ppos) && getsymb(str, length, ppos) == ‘)’); } /* end factor */

  27. int getsymb(char str[], int length, int *ppos) { char c; if (*ppos < length) c = str[*ppos]; else c = ‘ ‘; (*ppos)++; return(c); } /* end getsymb */

  28. A B C 1 2 3 4 5 The initial setup of the Towers of Hanoi. The Towers of Hanoi problem • Disks are of different diameters • A larger disk must be put below a smaller disk • Object: to move the disks, one each time, from peg A to peg C, using peg B as auxiliary.

  29. Strategy for moving disks • how to move 3 disks? • how to move n disks? ** **

  30. Recursive program for the Tower of Hanoi problem #include <stdio.h> void towers(int, char, char, char); void main() { int n; scanf(“%d”, &n); towers(n, ‘A’, ‘C’, ‘B’); } /* end main */

  31. void towers(int n, char frompeg, char topeg, char auxpeg) { if ( n == 1){ // If only one disk, make the move and return. printf(“\n%s%c%s%c”, “move disk 1 from peg ”, frompeg, “ to peg “, topeg); return; } /* end if */ /*Move top n-1 disks from A to B, using C as auxiliary*/ towers(n-1, frompeg, auxpeg, topeg); /* move remaining disk from A to C */ printf(“\n%s%d%s%c%s%c”, “move disk “, n, “ from peg “, frompeg, “ to peg “, topeg); /* Move n-1 disk from B to C using A as auxiliary */ towers(n-1, auxpeg, topeg, frompeg); } /* end towers */

  32. T(n) : # of movements with n disks 已知 T(n) = T(n-1) + 1 + T(n-1) = 2T(n-1) + 1 = 2(2T(n-2) + 1) + 1 = 4T(n-2) + 2 + 1 = 8T(n-3) + 4 + 2 + 1 = 2n-1 T(n-(n-1)) + 2n-2 + 2n-3 + … + 1 = 2n-1 T(1) + 2n-2 + 2n-3 + … + 1 = 2n-1 + 2n-2 + … + 1 = 2n - 1 T(1) = 1 boundary condition T(2) = 3 T(3) = 7 Number of movements

  33. 1. +A*BC prefix + (A) (*BC) + (A) (BC*) (A)(BC*)+ ABC*+ postfix + prefix prefix * A postfix postfix BC Translation from prefix to postfix infix A+B*C A*B+C A+B*C+D–E*F prefix +A*BC +*ABC -++A*BCD*EF postfix ABC*+ AB*C+ ABC*+D+EF*- • example for translation:

  34. 2. - + + A * BCD * EF prefix - ( + + A * BCD)(*EF) -(+(+A * BC)(D))(*EF) -(+(ABC * + )(D))(*EF) -(ABC * + D +)(EF*) ABC * + D + EF * - postfix - prefix prefix + * prefix prefix prefix + DEF postfix postfix prefix A * postfix postfix BC 演算法: **

  35. Recursive program for conversion void convert(char prefix[], char postfix[]) { char opnd1[MAXLENGTH], opnd2[MAXLENGTH]; char post1[MAXLENGTH], post2[MAXLENGTH]; char temp[MAXLENGTH]; char op[1]; int length; int i, j, m, n; if ((length = strlen(prefix)) == 1){ if (isalpha(prefix[0])){ /* The prefix string is a single letter. */ postfix[0] = prefix[0]; postfix[1] = ‘\0’; return; } /* end if */ printf(“\nillegal prefix string”); exit(1); } /* end if */

  36. /* The prefix string is longer than a single */ /* character. Extract the operator and the */ /* two operand lengths. */ op[0] = prefix[0]; op[1] = ‘\0’; substr(prefix, 1, length-1, temp); m = find(temp); substr(prefix, m+1, length-m-1, temp); n = find(temp); if ((op[0] != ‘+’ && op[0] != ‘-’ && op[0] != ‘*’ && op[0] != ‘/’) || (m == 0) || (n == 0) || (m+n+1 != length)){ printf(“\nillegal prefix string”); exit(1); } /* end if */ substr(prefix, 1, m, opnd1); substr(prefix, m+1, n, opnd2); convert(opnd1, post1); convert(opnd2, post2); strcat(post1, post2); strcat(post1, op); substr(post1, 0, length, postfix); } /* end convert */

  37. m n +( )( ) 0 1 m+1 int find(char str[]) /* 找到最後合法的prefix */ { char temp[MAXLENGTH]; int length; int i, j, m, n; if ((length = strlen(str)) == 0) return(0); if (isalpha(str[0]) != 0) /* First character is a letter. */ / That letter is the initial substring. */ return(1); /* otherwise find the first operand */ if (strlen(str) < 2) return(0); substr(str, 1, length-1, temp); // 假設第一個為operator m = find(temp);

  38. if (m == 0 || strlen(str) == m) /* no valid prefix operand or no second operand */ return (0); substr(str, m+1, length-m-1, temp); n = find(temp); if (n == 0) return(0); return(m+n+1); } /* end find */

  39. Action of calling a function in C • Passing arguments • Allocating and initializing local variables • Transferring control to the function (a) Control Control (b) A Series of procedures calling one another.

  40. Storage allocation for a C compiler (1) dynamic allocation: storage for local variables, parameters are allocated when a function is called. (2) A function call is maintained by using a stack.

  41. e.g. int f1(int x) { int i, j; } int f2(float s,float t) { char a, b; f1(4) } int f3() { f2(2.4, 7.5); } for f1 ... local variables ... for f2 parameters ... ... for f3 ... Stack • Some programming languages do not allow • recursive programs, e.g. FORTRAN, COBAL.

  42. Recursive program of factorial int fact(int n) { int x, y; if (n == 0) return(1); x = n-1; y = fact(x); return(n*y); } /* end fact */ Stack simulation struct dataarea{ int param; int x; longint y; short int retaddr; }; struct stack{ int top; struct dataarea item[MAXSTACK]; }; Stack simulation with C

  43. int simfact(int n) { struct dataarea currarea; struct stack s; short int i; long int result; s.top = -1; /* initialize a dummy data area */ currarea.param = 0; currarea.x = 0; currarea.y = 0; currarea.retaddr = 0; /* push the dummy data area onto the stack */ push(&s, &currarea); /* set the parameter and the return address of */ /* the current data area to their proper values. */ currarea.param = n; currarea.retaddr = 1;

  44. start: /* this is the beginning of the simulated */ /* factorial routine. */ if (currarea.param == 0){ /* simulation of return(1); */ result = 1; i = currarea.retaddr; popsub(&s, &currarea); switch(i){ case 1: goto label1; case 2: goto label2; } /* end switch */ } /* end if */ currarea.x = currarea.param –1; /* simulation of recursive call to fact */ push(&s, &currarea); currarea.param = currarea.x; currarea.retaddr = 2; goto start; /* This is the point to which we return */ /* from the recursive call. Set currarea.y */ /* to the returned value. */ currarea.y = result; label2:

  45. /* simulation of return(n*y) */ result = currarea.param * currarea.y; i = currarea.retaddr; popsub(&s, &currarea); switch(i){ case 1: goto label1; case 2: goto label2; } /* end switch */ /* At this point we return to the main routine. */ return(result); } /* end simfact */ label1:

  46. Improving the simulation routine • The old value of n must be used after returning from the recursive call. Thus, the value of n must be kept on the stack. But, x and y need not be stacked. #define MAXSTACK 50 struct stack{ int top; int param[MAXSTACK]; // Only n is kept; }; int simfact(int n) { struct stack s; shortint und; long int result, y; int currparam, x; s.top = -1; currparam = n;

  47. start: /* This is the beginning of the simulated */ /* factorial routine. */ if (currparam == 0){ /* simulation of return(1) */ result = 1; popandtest(&s, &currparam, &und); switch(und){ case FALSE: goto label2; case TRUE : goto label1; } /* end switch */ } /* end if */ /* currparam !=0 */ x = currparam - 1; /* simulation of recursive call to fact */ push(&s, currparam); currparam = x; goto start; /* This is tje point to which we return */ /* from the recursive call. Set */ /* y to the returned value. */ y = result; label2:

  48. /* simulation of return ( n*y); */ result = currparam * y; popandtest(&s, &currparam, &und); switch(und){ case TRUE : goto label1; case FALSE: goto label2; } /* end switch */ /* At this point we return to the main */ /* routine. */ return(result); } /*end simfact*/ label1:

  49. Eliminating unnecessary gotos: struct stack { int top; int param[MAXSTACK]; }; int simfact(int n); { struct stack s; short int und; int x; long int y;

  50. s.top = -1; x = n; /* This is the beginning of */ /* the simulated factorial routine. */ if (x == 0) y = 1; else{ push(&s, x--); goto start; } /* end else */ label1: popandtest(&s, &x, &und); if (und == TRUE) return(y); label2: y *= x; goto label1; } /* end simfact */ start:

More Related