3 -1 chapter 3 recursion. 3 -2 iterative algorithm for n factorial n factorial n! = 1 if n = 0 n! =...
TRANSCRIPT
3 -2
Iterative algorithm for n factorial
n factorial n! = 1 if n = 0n! = 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
Recursive definition for n factorial
recursive definition:
n! = 1 if n = 0n! = n * (n-1)! if n > 0
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 */
3 -5
Stack and function call in C
e.g. printf(“%d”, fact(3))
n x y(a)(initially) (b)fact(3) (c)fact(2)
3 *
*
n x y
2
3
*
2
*
*
n x y
1
2
3
*
1
2
*
*
*
n x y
0
1
2
3
*
0
1
2
*
*
*
*
n x y
1
2
3
0
1
2
1
*
*
n x y
(d)fact(1) (e)fact(0) (f)y=fact(0)
3 -6
n x y
(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.)
2
3
1
2
1
*
n x y
3 2
2
n x y
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 */
1
)!1(!
n
nn
Common errors
3 -8
Error checking for n < 0int 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 */
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 */
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
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
3 -13
Fibonacci sequence and golden number
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
numberGolden 2
51lim
1
n
nn f
f
1 x-1
x
2
51
01
1
1
12
x
xx
x
x
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);}
fn = 0 if n = 0 fn = 1 if n = 1
fn = fn-1 + fn-2 if n 2
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));}
fn = 0 if n = 0 fn = 1 if n = 1
fn = fn-1 + fn-2 if n 2
3 -16
Stack simulation for fib(4)=3n
4
x
*
y
*
n
3
4
x
*
*
y
*
*
n
2
3
4
x
*
*
*
y
*
*
*
n
1
2
3
4
x
*
*
*
*
y
*
*
*
*
n
2
3
4
x
1
*
*
y
*
*
*
n
0
2
3
4
x
*
1
*
*
y
*
*
*
*
n
2
3
4
x
1
*
*
y
0
*
*
n
3
4
x
1
*
y
*
*
n
1
3
4
x
*
1
*
y
*
*
*
n
3
4
x
1
*
y
1
*
(a) (b) (c) (d) (e)
(f) (g) (h) (i) (j)
3 -17
n
4
x
2
y
1
n
4
x
2
y
*
n
2
4
x
*
2
y
*
*
n
1
2
4
x
*
*
2
y
*
*
*
n
0
2
4
x
*
1
2
y
*
*
*
n
2
4
x
1
2
y
0
*
(k) (l) (m) (n) (o)
(p) (q)
n
2
4
x
1
2
y
*
*
3 -18
The computation tree
Much computation is duplicated. The iterative algorithm for generating Fibonacci sequence is better.
f5
f1f2
f2f3
f4 f3
f2 f1
f0f1 f0 f1
f0f1
3 -19
Binary search It is used for finding a given element in a sor
ted 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
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 */
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.
3 -22
Algebraic expressionsexpression term + term | termterm factor * factor | factorfactor 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 :
**
3 -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 *);
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 */
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 */
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 */
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 */
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
12345
The initial setup of the Towers of Hanoi.
3 -30
#include <stdio.h>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
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 */
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
= 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 conditionT(2) = 3T(3) = 7
Number of movements
3 -33
Translation from prefix to postfix
infixA+B*CA*B+CA+B*C+D–E*F
prefix+A*BC+*ABC-++A*BCD*EF
postfixABC*+AB*C+ABC*+D+EF*-
example for translation:1. +A*BC prefix + (A) (*BC)
+ (A) (BC*) (A)(BC*)+ ABC*+ postfix
prefix prefix
postfix postfix
+
*A
B C
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 prefix
-
*+
+
*A
B C
演算法 :
**
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
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 */
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); // 假設第一個為 operato
r m = find(temp);
+( )( )
m n
0 1 m+1
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 */
3 -39
Action of calling a function in C
1. Passing arguments2. Allocating and initializing local variables3. Transferring control to the functionmain 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
Control
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.
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);
}
...
...
...
...
...
jix
return address
temporarybats
return address
for f3
for f2
for f1
local variables
parameters
Stack
Some programming languages do not allow recursive programs, e.g. FORTRAN, COBAL.
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];
};
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;
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:
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:
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 50struct 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;
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:
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:
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;
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:
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 */
3 -52
Recursion and nonrecursion recursion: (1) need more time and space when executing (ma
chine efficiency) (2) easy to write a program (programmer efficiency)
nonrecursion: 正好相反