Chapter 3 Recursion 1 Iterative algorithm for n



















![Recursive binary search int binsrch(int a[], int x, int low, int high) { int Recursive binary search int binsrch(int a[], int x, int low, int high) { int](https://slidetodoc.com/presentation_image_h2/a9972523db9e352336be985adec5eb17/image-20.jpg)



![void main() { char str[MAXSTRINGSIZE]; int length, pos; readstr(str, &length); pos = 0; if void main() { char str[MAXSTRINGSIZE]; int length, pos; readstr(str, &length); pos = 0; if](https://slidetodoc.com/presentation_image_h2/a9972523db9e352336be985adec5eb17/image-24.jpg)
![int expr(char str[], int length, int *ppos) { /* look for a term if int expr(char str[], int length, int *ppos) { /* look for a term if](https://slidetodoc.com/presentation_image_h2/a9972523db9e352336be985adec5eb17/image-25.jpg)
![int term(char str[], int length, int *ppos) { if (factor(str, length, ppos) == FALSE) int term(char str[], int length, int *ppos) { if (factor(str, length, ppos) == FALSE)](https://slidetodoc.com/presentation_image_h2/a9972523db9e352336be985adec5eb17/image-26.jpg)
![int getsymb(char str[], int length, int *ppos) { char c; if (*ppos < length) int getsymb(char str[], int length, int *ppos) { char c; if (*ppos < length)](https://slidetodoc.com/presentation_image_h2/a9972523db9e352336be985adec5eb17/image-27.jpg)







![Recursive program for conversion void convert(char prefix[], char postfix[]) { char opnd 1[MAXLENGTH], opnd Recursive program for conversion void convert(char prefix[], char postfix[]) { char opnd 1[MAXLENGTH], opnd](https://slidetodoc.com/presentation_image_h2/a9972523db9e352336be985adec5eb17/image-35.jpg)

![int find(char str[]) /* 找到最後合法的prefix */ { m n char temp[MAXLENGTH]; int length; +( int find(char str[]) /* 找到最後合法的prefix */ { m n char temp[MAXLENGTH]; int length; +(](https://slidetodoc.com/presentation_image_h2/a9972523db9e352336be985adec5eb17/image-37.jpg)











![Eliminating unnecessary gotos: struct stack { int top; int param[MAXSTACK]; }; int simfact(int n); Eliminating unnecessary gotos: struct stack { int top; int param[MAXSTACK]; }; int simfact(int n);](https://slidetodoc.com/presentation_image_h2/a9972523db9e352336be985adec5eb17/image-49.jpg)




- Slides: 53
Chapter 3 Recursion 1
Iterative algorithm for n factorial n n 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); 2
Recursive definition for n factorial n recursive definition: n! = 1 if n = 0 n! = n * (n-1)! if n > 0 3
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 */ 4
Stack and function call in C e. g. printf(“%d”, fact(3)) 3 n x y (a)(initially) 1 2 3 * 1 2 * * * n x y (d)fact(1) * * n x y (b)fact(3) 0 1 2 3 * 0 1 2 * * n x y (e)fact(0) 2 3 * 2 * * n x y (c)fact(2) 1 2 3 0 1 2 1 * * n x y (f)y=fact(0) 5
2 3 1 2 1 * n x y (g)y=fact(1) n 3 2 2 n x y (h)y=fact(2) n x y (i)printf(“%d”, fact(3)) The stack varies during execution. (from (a) to (i)) (An asterisk indicates an uninitialized value. ) 6
Common errors n Calling printf(“%d”, fact(-1)) would cause infinite loops n It is invalid to define there must be a boundary condition. n Concise code: int fact(int n) { return( n == 0 ? 1 : n * fact(n-1)); } /* end fact */ 7
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 */ 8
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 */ 9
n Concise code: int mult(int a, int b) { return(b == 1 ? a : mult(a, b-1) + a); } /* end mult */ n Invalid definition: a * b = a * (b+1) - a 10
Fibonacci sequence (1) n 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . . . n 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 11
Fibonacci sequence (2) n 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . . . 12
Fibonacci sequence and golden number n 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, . . . fn = 0 if n = 0 fn = 1 if n = 1 fn = fn-1 + fn-2 if n >= 2 1 x-1 x 13
Iterative algorithm for Fibonacci sequence int fib(int n) { int i, x, logib, hifib; } fn = 0 if n = 0 fn = 1 if n = 1 fn = fn-1 + fn-2 if n 2 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); 14
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 */ n fn = 0 if n = 0 fn = 1 if n = 1 fn = fn-1 + fn-2 if n 2 Concise code: int fib(int n) { if (n <= 1) return(n); return (fib(n-1) + fib(n-2)); } 15
Stack simulation for fib(4)=3 n 4 x * y * n 3 4 (a) x * * y * * 2 3 4 (b) x y n x y 0 2 3 4 * 1 * * * 2 3 4 1 * * 0 * * (g) x * * * y n x y * * * 1 2 3 4 * * * * 2 3 4 1 * * * (c) n (f) n n 3 4 x 1 * (h) (d) (e) y n x y * * 1 3 4 * 1 * * 3 4 1 * (i) (j) 16
n 4 x 2 y * n 2 4 (k) x * 2 y n x y * * 1 2 4 * * 2 * * * (l) (m) n x y 2 4 1 2 0 * 4 2 1 (p) (q) n 2 4 x 1 2 (n) y n x y * * 0 2 4 * 1 2 * * * (o) 17
The computation tree f 5 f 4 f 3 f 2 f 1 n n f 2 f 1 f 2 f 0 f 1 f 0 Much computation is duplicated. The iterative algorithm for generating Fibonacci sequence is better. 18
Binary search n 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) e. g. 1 4 7 8 10 11 14 return(-1); while (high >= low){ mid = (low+high)/2; if (x == a[mid]) return(mid); if (x < a[mid]) high = mid-1; else Search 6 low = mid+1; } return(-1); /* 未找到 */ 19 }
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 */ 20
Recursive chains a(formal parameters) { b(arguments); } /* end a */ b(formal parameters) { a(arguments); } /* end b */ n A recursive function need not call itself directly. 21
Algebraic expressions expression term factor letter e. g A : (A) : A+B : (A+B) : A*B : A*(B+C): (A+B*)C: A+B+C : term + term | term factor * factor | factor letter | (expresssion) A | B | C | D |. . . | Z ** 22
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 term(char *, int *); int getsymb(char *, int *); int factor(char *, int *); 23
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 */ 24
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 */ */ */ 25
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 */ 26
int getsymb(char str[], int length, int *ppos) { char c; if (*ppos < length) c = str[*ppos]; else c = ‘ ‘; (*ppos)++; return(c); } /* end getsymb */ 27
The Towers of Hanoi problem A B C 1 2 3 4 5 The initial setup of the Towers of Hanoi. n n n 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. 28
Strategy for moving disks n how to move 3 disks? ** n how to move n disks? ** 29
Recursive program for the Tower of Hanoi problem #include <stdio. h> void towers(int, char, char); void main() { int n; scanf(“%d”, &n); towers(n, ‘A’, ‘C’, ‘B’); } /* end main */ 30
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”, “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”, “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 */ 31
Number of movements T(n) : # of movements with n disks boundary condition 已知 T(1) = 1 T(2) = 3 T(3) = 7 T(n) = T(n-1) + 1 + T(n-1) = 2 T(n-1) + 1 = 2(2 T(n-2) + 1 = 4 T(n-2) + 2 + 1 = 8 T(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 32
Translation from prefix to postfix infix A+B*C A*B+C A+B*C+D–E*F n prefix +A*BC +*ABC -++A*BCD*EF postfix ABC*+ AB*C+ ABC*+D+EF*- example for translation: 1. +A*BC + (A) prefix + (A) postfix prefix (*BC) prefix (BC*) + * A postfix (A)(BC*)+ ABC*+ postfix B C 33
2. - + + A * BCD * EF prefix - ( + + A * BCD)(*EF) prefix - prefix + -(+(+A * BC)(D))(*EF) prefix -(+(ABC * + )(D))(*EF) postfix prefix + * D E F * A -(ABC * + D +)(EF*) postfix ABC * + D + EF * - postfix B C 演算法: ** 34
Recursive program for conversion void convert(char prefix[], char postfix[]) { char opnd 1[MAXLENGTH], opnd 2[MAXLENGTH]; char post 1[MAXLENGTH], post 2[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] = ‘ ’; return; } /* end if */ printf(“nillegal prefix string”); exit(1); } /* end if */ 35
/* The prefix string is longer than a single */ /* character. Extract the operator and the */ /* two operand lengths. */ op[0] = prefix[0]; op[1] = ‘ ’; 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, opnd 1); substr(prefix, m+1, n, opnd 2); convert(opnd 1, post 1); convert(opnd 2, post 2); strcat(post 1, op); substr(post 1, 0, length, postfix); } /* end convert */ 36
int find(char str[]) /* 找到最後合法的prefix */ { m n char temp[MAXLENGTH]; int length; +( )( ) int i, j, m, n; 0 1 m+1 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); 37
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 */ */ 38
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 c procedure d Return address call on d call on c procedure b Return address (a) procedure c Return address call on d Control call on c (b) A Series of procedures calling one another. 39
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. 40
. . . e. g. int f 1(int x) { int i, j; . . . } int f 2(float s, float t) { local char a, b; variables f 1(4). . . for f 1 temporary b a t s return address for f 2 . . . } int f 3() { parameters j i x return address for f 3 f 2(2. 4, 7. 5); n . . . } Stack Some programming languages do not allow recursive programs, e. g. FORTRAN, COBAL. 41
Stack simulation with C n 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 */ n Stack simulation struct dataarea{ int param; int x; long int y; short int retaddr; }; struct stack{ int top; struct dataarea item[MAXSTACK]; }; 42
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; 43
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 label 1; case 2: goto label 2; } /* 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; */ label 2: /* This is the point to which we return /* from the recursive call. Set currarea. y */ /* to the returned value. */ currarea. y = result; 44
/* simulation of return(n*y) */ result = currarea. param * currarea. y; i = currarea. retaddr; popsub(&s, &currarea); switch(i){ case 1: goto label 1; case 2: goto label 2; } /* end switch */ label 1: /* At this point we return to the main routine. */ return(result); } /* end simfact */ 45
Improving the simulation routine n 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; 46
/* 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 label 2; case TRUE : goto label 1; } /* end switch */ } /* end if */ /* currparam !=0 */ x = currparam - 1; /* simulation of recursive call to fact */ push(&s, currparam); currparam = x; goto start; label 2: /* This is tje point to which we return */ /* from the recursive call. Set */ /* y to the returned value. */ y = result; start: 47
/* simulation of return ( n*y); */ result = currparam * y; popandtest(&s, &currparam, &und); switch(und){ case TRUE : goto label 1; case FALSE: goto label 2; } /* end switch */ label 1: /* At this point we return to the main */ /* routine. */ return(result); } /*end simfact*/ 48
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; 49
start: 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 */ label 1: popandtest(&s, &x, &und); if (und == TRUE) return(y); label 2: y *= x; goto label 1; } /* end simfact */ 50
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 */ 51
Recursion and nonrecursion n recursion: (1) need more time and space when executing (machine efficiency) (2) easy to write a program (programmer efficiency) n nonrecursion: 正好相反 52
Machine efficiency and programmer efficiency n n n 如果一個program 常用, 應寫成 nonrecursive program. 目前 compiler 技術很好, recursive program 亦 可很快 前題: 使用nonrecursion時, 若需用stack, 如 Towers of Hanoi, 則使用 recursion, 否則, 使用nonrecursion, 如 n!, Fibonacci numbers. 53