Download presentation
1
Discrete Maths 3. Recursion Objective
, Semester 3. Recursion Objective to show the close connection between recursive definitions, recursive functions, and recursive (inductive) proofs
2
Overview 1. Recursive Definitions 2. Recursive Functions
3. Lists Recursively 4. Trees Recursively 5. Hilbert Curves 6. Proving Recursive Programs Work 7. Further Information
3
1. Recursive Definitions
A recursive definition involves: 1. One or more basis rules, in which simple things are defined, and 2. One or more recursive (inductive) rules, where larger things are defined in terms of ‘smaller’ versions of those things.
4
the leaves are the basis
Examples A tree is made from left and right subtrees. 23 5 4 left subtree right subtree 7 19 5 the leaves are the basis
5
Use recursion to create
Sierpinski Gasket Use recursion to create strange shapes Start with a triangle and cut out the middle piece as shown. This results in three smaller triangles to which the process is continued.
6
3D Sierpinski Gasket
7
Menger Sponge remove center square repeat for the 8 small squares
8
Why Bother with Recursive Definitions?
For many problems, recursive definitions are the natural way of specifying the problems e.g. search over trees/graphs, parsing, Recursive definitions are very close to inductive statements, and so are usually easier to prove than loop invariants.
9
1.1. Factorial, Recursively
Remember that n! is 1*2*3*...*n. A recursive definition of n!: Basis. 1! = 1 Induction. n! = n * (n-1)! it's inductive because the meaning of n! is defined using the smaller (n-1)!
10
Prove the Specification Correct
Prove the inductive statement S(n): the recursive definition of n!, as defined on the last slide, equals 1*2*3*...*n Basis. S(1) is clearly true. Show recursive n! is the same as a series of multiplications. continued
11
Induction. Assume that S(n) is true, which means that n! = 1*2*3...*n
The recursive definition states that: (n+1)! = (n+1) * n! so, (n+1)! = n! * (n+1) substitute in n! value from S(n), so (n+1)! = 1*2*3*...n*(n+1) This is S(n+1), so S(n) --> S(n+1) is true. continued
12
This means that S(n) is true for all n >= 1:
In summary: we have shown S(1) to be true we have shown S(n) --> S(n+1) to be true This means that S(n) is true for all n >= 1: the recursive definition of n! equals 1*2*3*...*n Why is this useful? the correct recursive definition can be easily converted into a correct recursive function
13
1.2. Recursive Definition of Expressions
We will look at expressions involving binary operators (e.g. +, *, /) e.g X*2, (Y/3)*(W+2), X The variables/numbers in an expressions are called operands. Basis. An operand on its own is an expression (e.g. X). continued
14
Inductive Rules 1. If E1 and E2 are expression, is a binary operator (e.g., +, *), then is an expression. 2. If E is an expression, then (E) is an expression. Examples: 5, X, 2+s, (X*Y) - 1
15
An Induction Proof Using Length
S(n): A binary operator expression E of length n has one more operand than operators. For example: len operands ops X (2*y) continued
16
the length of the expression
Examples: S(1) y X a S(3) 2+a X*Y s (x) S(5) (1+d) *6-2 Note: the examples suggest that S(2), S(4), S(6), etc. may not exist. continued
17
The proof of S(n) is by complete induction on the length of the expression:
length is counted as the number of operators, operands and parentheses Basis. n=1. E must be a single operand (e.g. X). Since there are no operators, the basis holds. e.g. the first examples on the last slide continued
18
Induction: Assume S(1), S(2),..., S(n), and show that:
(S(1) or S(2) or … or S(n)) --> S(n+1) this is complete induction. Let the expression for S(n+1) be called E. How can E be constructed? there are two cases, corresponding to the two inductive rules continued
19
So S(n+1) holds when E has the form (E1)
a) If by rule (2), E = (E1) Assume true: no of operands no of ops| E1 x+1 x Prove E E = (E1) x+1 x So S(n+1) holds when E has the form (E1) continued
20
b) If by rule (1), then E = E1@E2
Assume true: no of operands no of ops| E1 a+1 a E2 b+1 b Prove E E = a+b+2 a+b+1 So S(n+1) holds when E has the form continued
21
S(n+1) is true for both forms of E
this was proved by assuming that smaller expressions (E1, E2) were true any smaller expression can be used since we are using complete induction continued
22
This means that S(n) is true for all n >= 1:
In summary: shown S(1) to be true shown (S(1) or S(2) .. or S(n)) --> S(n+1) true This means that S(n) is true for all n >= 1: a binary operator expression E of length n has one more operand than operators Why is this useful? the correct recursive definition can be easily converted into a correct recursive function, which can be used in compilers complete induction
23
Notes We used all of S(1), ...S(n) in the inductive step, since we considered the subexpressions that made up E. Using subexpressions was only possible because expression was defined recursively in terms of subexpressions.
24
2. Recursive Functions A recursive function is one that is called from within its own body direct call: a function F() has a call to F() within itself indirect call: a function F1() calls F2() which calls F3(), ... and eventually F1() is called Recursive definitions map easily to recursive functions.
25
2.1. Factorial Code The recursive definition of n! was: As a function:
Basis. 1! = 1 Induction. n! = n * (n-1)! As a function: int fact(int n) { if (n <= 1) return 1; /* basis */ else return n * fact(n-1); /*induction*/ } a simple translation
26
Understanding Recursive Execution
Draw function calls as boxes, each containing the variables (and values) in that function call. Example: void main() { int res = fact(4); printf(“%d”, res); }
27
fact Diagram n 4 return... fact main n 3 return... res=fact(4) fact n 2 return... The trick is to remember that there are multiple calls to fact(). fact n 1 return...
28
2.2. Convert int to binary The simplest algorithm for converting an integer to binary is recursive. It will translate: 610 to 1102 1310 to 11012 continued
29
For an integer i > 0, convert it to binary as:
last bit is i%2 '%' gives the remainder, so 9%4 == 1 leading bits are obtained by converting i/2 until i == 0 '/' is integer division, so 9/2 == 4
30
Typical Looping Solution
void main() { int i; scanf(“%d”, &i); while (i > 0) { putchar(‘0’ + i%2); i = i/2; } putchar(‘\n’); } i at start i/2 i% Input: 6 Output: 011
31
Major problem: the answer comes out backwards:
610 is converted to 0112 Fixing the looping version is much harder than writing a recursive definition of the algorithm.
32
Recurive Definition Convert i to binary. Basis. If i == 0, do nothing
Induction. If i > 0, then convert i/2 , then print the bit i%2 it's inductive because the convert definition for i is defined using convert of i/2
33
Recursive Code void convert(int i) { if (i > 0) { convert(i/2); putchar(‘0’ + i%2); } } void main() { int i; scanf(“%d”, &i); convert(i); putchar(‘\n’); }
34
Diagram convert i 6 convert main i 3 i 6 convert(6) convert i 1
convert(i/2); putchar(i%2) convert main i 3 i 6 convert(i/2); putchar(i%2) convert(6) convert i 1 convert(i/2); putchar(i%2) Input: 6 Output: 110 convert i do nothing; return
35
2.3. Walking Robot A robot can take steps of 1 meter or 2 meters.
Develop an algorithm to calculate the number of ways the robot can walk n meters. More complex versions of this problem occur in real robot controllers.
36
Examples Distance n Seq. of Steps No. of Ways to walk n meters ,1 or ,1,1 or 1,2 or 2, ,1,1,1 or 1,1,2 or 1,2,1 or 2,1,1 or 2,2 5
37
Recursive Definition Basis. No. of ways to walk 1 meter = No. of ways to walk 2 meters = 2. Induction. No. of ways to walk n meters (n > 2) is the sum of: no. of ways to walk n-1 (after a 1-step), plus no. of ways to walk n-2 (after a 2-step)
38
Recursive Code int numWays(int n) { if ((n == 1) || (n == 2)) return n; else return numWays(n-1) numWays(n-2)); }
39
Table of Results Distance to Walk No. of Ways 1 1 2 2 3 3 4 5 5 8 6 13
This sequence of number of ways is a Fibonacci sequence. It appears in many places in maths (and computing).
40
3. Lists Recursively The list data structure has a natural recursive definition (and implementation). When a data structure is recursive, functions for manipulating it are naturally recursive as well. e.g. length of a list e.g. is an element in a list?
41
3.1. Recursive Definition A list can be: Example: Basis. Empty
Induction. A non-empty list consists of one node (the head), followed by a list (the tail). Example: 23 5 7 19 5 4 head tail
42
3.2. Recursive Implementation
Unfortunately, recursive data structures in C have to be implemented with pointers. this is not true in many other languages, such as Java, Haskell, Prolog, etc. Also, empty pointer data structures are usually coded using NULL. continued
43
The LIST Type Note. LIST can only hold integer elements.
struct CELL { int element; struct CELL *next; } typedef struct CELL *LIST; Note. LIST can only hold integer elements.
44
Diagrams of C Lists a 3-element list 19 5 4 w NULL NULL w
an empty list
45
Example void main() { LIST w = NULL; /* an empty list */ w = makeList(); /* build a list */ : if (w != NULL) printList(w); : :
46
3.3. The length of a list The recursive definition of length follows the recursive definition of the list d.s: Basis. The length of an empty list is 0. Induction. The length of a non-empty list is 1 + the length of the list tail.
47
length() int length(LIST w) { if (w == NULL) /* is w empty? */ return 0; else return 1 + length(w->next); }
48
3.4. Is element x in the list? A recusive definition:
Basis. If the list is empty, then x is not in the list. Return False (0). Induction. If the list is non-empty then: 1. If x is the same as the list head, return True (1). 2. If x is not the same as the head, then return the result of examining the list tail.
49
hasElement() int hasElement(LIST w, int x) { if (w == NULL) /* empty? */ return 0; /* false */ else if (x == w->element) return 1; /* true */ else return hasElement(w->next, x); }
50
3.5. A General Recursive Format
Most list functions have the “shape”: ResultType fun(LIST w, ...) { if (w == NULL) return somethingSimple; else { use w->element; fun(w->next, ...); return result; } } Learn (and understand) this.
51
4. Trees Recursively The tree data structure has a natural recursive definition (and implementation). Tree functions are naturally recursive: e.g. the number of elements in a tree e.g. is an element in a tree? Using loops in tree functions usually means BIG CODING MISTAKES.
52
4.1. Recursive Definition A binary tree can be: Basis. Empty
Induction. A non-empty tree consists of a node, and left and right sub-trees (which may be empty). 23 right subtree 5 4 left subtree 7 19 5
53
4.2. The TREE Type Note. TREE can only hold integer element.
struct CELL { int element; struct CELL *left; struct cell *right; } typedef struct CELL *TREE; Note. TREE can only hold integer element.
54
Diagrams of C Trees NULL p 2 p an empty tree 1 4 N N N 5
a 4-element tree (N means NULL) N N
55
Example void main() { TREE p = NULL; /* an empty tree */ p = makeTree(); /* build a tree */ : if (p != NULL) printTree(p); : :
56
4.3. The number of elements in a tree
The recursive definition of numElem follows the recursive definition of the tree d.s: Basis. The numElem of an empty tree is 0. Induction. The numElem of a non-empty tree is: numElem of left subtree numElem of right subtree
57
numElem() int numElem(TREE w) { if (w == NULL) /* is w empty? */ return 0; else return 1 + numElem(w->left) numElem(w->right); }
58
4.4. Is element x in the tree? A recusive definition:
Basis. If the tree is empty, then x is not in the tree. Return False (0). Induction. If the tree is non-empty then: 1. If x is the same as the element, return True (1), or 2. If x is in the left subtree, return True (1), or 3. If x is in the right subtree, return True (1), or 4. Return False.
59
hasElement() Note: the last else combines cases 3 and 4.
int hasElement(TREE w, int x) { if (w == NULL) /* empty? */ return 0; /* false */ else if (x == w->element) return 1; else if (hasElement(w->left, x)) return 1; /* true */ else return hasElement(w->right, x); } Note: the last else combines cases 3 and 4.
60
4.5. A General Recursive Format
Most tree functions will have the “shape”: ResultType fun(TREE w, ...) { if (w == NULL) return somethingSimple; else { use w->element; fun(w->left, ...); fun(w->right, ...); return result; } } Learn (and understand) this.
61
5. Hilbert Curves Hilbert Curves are one kind of curve based on fractals. Fractals are complex-looking shapes that are constructed by combining smaller basic shapes fractals appear in nature (e.g. mountain/river shapes), and in computer games! They are easy to program recursively.
62
Hilbert Curves of order 1, 2, and 3
drawing starts at the top right corner
63
drawing starts here Hilbert Curve, order 6 This shows why curves of this type are often called “space-filling”. H6
64
5.1. Recursively Defining Hi
H1 is Hi is obtained by the composition of four instances of Hi-1 of half size and appropriate rotation, and by tieing together the four Hi-1’s by three connecting lines. Four possible rotations: any of these can be used to build H2, H3, etc.
65
Hilbert Curves Again Y H1 H2 X H3 For each curve, drawing starts at top right hand corner.
66
From Specification to Code
Instead of recursively defining Hi using Hi-1, we will use a different approach. Four recursive drawing functions will be defined: Ai, Bi, Ci, Di Hi will be drawn by calling Ai
67
Drawing Function Ai, Bi, Ci, Di have recursive definitions using Ai-1, Bi-1, Ci-1, Di-1. There are also basis drawings A1, B1, C1, D1
68
Basis Drawings B1 A1 C1 D1 the arrow is the drawing direction
on the screen D1
69
Recursive Drawings Ai-1 Di-1 Bi-1 Bi-1 Ai: Bi: Ai-1 Bi-1 Ci-1 Ai-1
these are the connecting lines between the drawing operations Di-1 Ci-1 Ci-1 Ai-1 Ci: Di: Bi-1 Ci-1 Di-1 Di-1
70
5.2. Hilbert Curve Drawing Pseudo-code
Draw Hlevel #define WIDTH /* global variables */ int incr, x, y; void main() { int level; x = WIDTH; y = WIDTH; scanf(“%d”, &level); incr = WIDTH/pow(2,level); setplot(x,y); /* top right of plotter */ a(level); /* start with A */ } : y x
71
Ai-1 Di-1 Ai: Ai-1 Bi-1 void a(int i) { if (i > 0) { d(i-1); x -= incr; plot(x,y); a(i-1); y -= incr; plot(x,y); a(i-1); x += incr; plot(x,y); b(i-1); } }
72
Bi-1 Bi-1 Bi: Ci-1 Ai-1 void b(int i) { if (i > 0) { c(i-1); y += incr; plot(x,y); b(i-1); x += incr; plot(x,y); b(i-1); y -= incr; plot(x,y); a(i-1); } }
73
Di-1 Ci-1 Ci: Bi-1 Ci-1 void c(int i) { if (i > 0) { b(i-1); x += incr; plot(x,y); c(i-1); y += incr; plot(x,y); c(i-1); x -= incr; plot(x,y); d(i-1); } }
74
Ci-1 Ai-1 Di: Di-1 Di-1 void d(int i) { if (i > 0) { a(i-1); y -= incr; plot(x,y); d(i-1); x -= incr; plot(x,y); d(i-1); y += incr; plot(x,y); c(i-1); } }
75
Notes The basis drawings A1, B1, C1, D1 are coded by calling a(1), b(1), c(1), d(1) the calls a(0), b(0), c(0), d(0) do nothing setplot(x,y) sets the plotter coordinates to (x,y) plot(x,y) draws a line from the current plotter coordinates to (x,y), and updates the plotter coordinates
76
5.3. Hilbert Curve URLs Java applets for generating fractals
the Hilbert curve applet has a nice GUI The Shodor Education Foundation lots of maths-related applets continued
77
Includes a Java applet in Peano.java
Peano/Peano.html Some discussion, and a Hilbert screen saver hilbert.html
78
5.4. Some Fun Stuff Look at other fractal-based curves
e.g. Sierpinski curves, Koch curves snowflakes, Levy dragons
79
6. Proving Recursive Programs Work
Proofs involving (recursive) functions usually say how input arguments affect the return value e.g fact(i) --> i! Induction proofs usually involve the “size” of the argument, and how it changes as the function is recursively called.
80
Different Kinds of Size
Argument “size” can be things like: the argument value. e.g. i in fact(i) the length of a list passed as an argument the number of nodes in a tree argument etc.
81
6.1. Proving fact() A reminder of the code: Inductive statement S(i):
int fact(int n) { if (n <= 1) return 1; else return n * fact(n-1); } Inductive statement S(i): when fact() is called with the value i for the argument n, fact() returns i! when i >= 1 continued
82
Basis. For i=1, the first if-test results in a return value 1, which is 1!
Induction. Assume S(i) : fact(i) == i! s(i+1): fact(i+1) returns (i+1) * fact(i) , which is: (i+1) * i! , which is (i+1)! , so the inductive step is true
83
6.2. Proving convert() A reminder of the code:
void convert(int i) { if (i > 0) { convert(i/2); putchar(‘0’ + i%2); } } Inductive statement S(k): convert(k) produces the binary representation of integer k >= 1 e.g. convert(6) == binary of 6 == 1102 e.g. 610 --> 1102 > 11012 continued
84
Basis. k == 1. The program executes:
convert(0); // does nothing putchar('0'+ 1); // prints '1' this is the correct output S(1) is true Induction. Assume S(k/2) and prove S(k) for k >= 2, when k is even, and when k is odd show S(k/2) --> S(k) is true
85
Graphically convert convert convert i i i k k/2 . . . . Assume correct
convert(i/2); putchar(i%2) convert(i/2); putchar(i%2) convert(i/2); putchar(i%2) Assume correct
86
Inductive Cases If k is even (e.g. 30), then output is:
convert(k/2) then putchar(k%2) which is “binary of k/2” 0 which is 2 * “binary of k/2” which is “binary of k” which is true If k == 30 then the output is: convert(15) putchar(0) which is “binary of 15” which is 2 * “binary of 15” which is 2 * == continued
87
If k is odd (e.g. 31), then output is:
convert(k/2) then putchar(k%2) which is “binary of (k-1)/2” which is 2 * “binary of (k-1)/2” which is “binary of k” If k == 31 then the output is: convert(15) putchar(1) which is “binary of 15” which is 2 * “binary of 15” which is ( 2 * ) + 1 ==
88
7. Further Information DM: section 3.4
Algorithms + Data Structures = Programs Niklaus Wirth Prentice-Hall, 1976, Chapter 3
89
“Drawing Hands” M.C. Escher, 1948
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.