Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "3 -1 Chapter 3 Recursion. 3 -2 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."— Presentation transcript:

1 3 -1 Chapter 3 Recursion

2 3 -2 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);

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

4 3 -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 3 -5 Stack and function call in C e.g. printf(“%d”, fact(3)) nxy (a)(initially) (b)fact(3) (c)fact(2) 3* * nxy 2323 *2*2 **** nxy 123123 *12*12 ****** nxy 01230123 *012*012 ******** nxy 123123 012012 1**1** nxy (d)fact(1) (e)fact(0) (f)y=fact(0)

6 3 -6 nxy (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.) 2323 1212 1*1* nxy 32 2 nxy

7 3 -7 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 */ Common errors

8 3 -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 3 -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 3 -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 3 -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 3 -12 Fibonacci sequence (2) 0,1,1,2,3,5,8,13,21,34,...

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

14 3 -14 Iterative algorithm for Fibonacci sequence 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); } f n = 0 if n = 0 f n = 1 if n = 1 f n = f n-1 + f n-2 if n  2

15 3 -15 Recursive algorithm for Fibonacci sequence 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)); } f n = 0 if n = 0 f n = 1 if n = 1 f n = f n-1 + f n-2 if n  2

16 3 -16 Stack simulation for fib(4)=3 n4n4 x*x* y*y* n34n34 x**x** y**y** n234n234 x***x*** y***y*** n1234n1234 x****x**** y****y**** n234n234 x1**x1** y***y*** n0234n0234 x*1**x*1** y****y**** n234n234 x1**x1** y0**y0** n34n34 x1*x1* y**y** n134n134 x*1*x*1* y***y*** n 34n 34 x 1*x 1* y 1*y 1* (a) (b) (c) (d) (e) (f) (g) (h) (i) (j)

17 3 -17 n4n4 x2x2 y1y1 n4n4 x2x2 y*y* n 24n 24 x *2x *2 y **y ** n 124n 124 x **2x **2 y***y*** n024n024 x*12x*12 y***y*** n 24n 24 x 12x 12 y 0*y 0* (k) (l) (m) (n) (o) (p) (q) n24n24 x12x12 y**y**

18 3 -18 The computation tree Much computation is duplicated. The iterative algorithm for generating Fibonacci sequence is better. f5 f1f2 f3 f4f3 f2f1 f0f1f0f1 f0f1

19 3 -19 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); /* 未找到 */ } e.g. 1 4 7 8 10 11 14 Search 6

20 3 -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 3 -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 3 -22 Algebraic expressions expression term + term | term term factor * factor | factor factor letter | (expresssion) letter A | B | C | D |... | Z e.g A : (A) : A+B : (A+B) : A*B : A*(B+C): (A+B*)C: A+B+C : **

23 3 -23 C program for checking expression #include #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 3 -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 3 -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 3 -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 3 -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 3 -28 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. A B C 1 2 3 4 5 The initial setup of the Towers of Hanoi.

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

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

31 3 -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 3 -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 = 2 n-1 T(n-(n-1)) + 2 n-2 + 2 n-3 + … + 1 = 2 n-1 T(1) + 2 n-2 + 2 n-3 + … + 1 = 2 n-1 + 2 n-2 + … + 1 = 2 n - 1 T(1) = 1 boundary condition T(2) = 3 T(3) = 7 Number of movements

33 3 -33 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: 1. +A*BC prefix + (A) (*BC) + (A) (BC*) (A)(BC*)+ ABC*+ postfix prefix postfix + * A B C

34 3 -34 D E F 2. - + + A * BCD * EF prefix - ( + + A * BCD)(*EF) -(+(+A * BC)(D))(*EF) -(+(ABC * + )(D))(*EF) -(ABC * + D +)(EF*) ABC * + D + EF * - postfix postfix postfix postfix postfix prefix prefix prefix prefix prefix - *+ + * A B C 演算法 : **

35 3 -35 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 */ Recursive program for conversion

36 3 -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 3 -37 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); +( )( ) m n 0 1 m+1

38 3 -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 3 -39 Action of calling a function in C 1.Passing arguments 2.Allocating and initializing local variables 3.Transferring control to the function main program call on b procedure b Return address call on c procedure c Return address call on d procedure d Return address main program call on b procedure b Return address call on c procedure c Return address call on d (a) (b) A Series of procedures calling one another. Control

40 3 -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 3 -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); }... j i x return address temporary b a t s return address for f3 for f2 for f1 local variables parameters Stack Some programming languages do not allow recursive programs, e.g. FORTRAN, COBAL.

42 3 -42 Stack simulation with C 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; long int y; short int retaddr; }; struct stack{ int top; struct dataarea item[MAXSTACK]; };

43 3 -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 3 -44 /* 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; start: label2:

45 3 -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 3 -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; short int und; long int result, y; int currparam, x; s.top = -1; currparam = n;

47 3 -47 /* 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; start: label2:

48 3 -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 3 -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 3 -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:

51 3 -51 The final simulation program simfact(n) int n; { int x; long int y; for (y = x =1; x <= n; x++) y = y*x; return(y); } /* end simfact */

52 3 -52 Recursion and nonrecursion recursion: (1) need more time and space when executing (machine efficiency) (2) easy to write a program (programmer efficiency) nonrecursion: 正好相反

53 3 -53 Machine efficiency and programmer efficiency 如果一個 program 常用, 應寫成 nonrecursive program. 目前 compiler 技術很好, recursive program 亦 可很快 前題 : 使用 nonrecursion 時, 若需用 stack, 如 Towers of Hanoi, 則使用 recursion, 否則, 使用 nonrecursion, 如 n!, Fibonacci numbers.


Download ppt "3 -1 Chapter 3 Recursion. 3 -2 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."

Similar presentations


Ads by Google