Upload
virgil-lynch
View
219
Download
0
Embed Size (px)
Citation preview
Round and round recursion: the good, the bad, the ugly, the hidden
ACSE 2006 Talk
Troy VasigaLecturer, University of WaterlooDirector, CCC
November 18, 2006 ACSE 2006 2
Outline
Recursion definedReal-world examples ("The hidden")Benefits ("The good")ExamplesHow it worksPitfalls ("The bad")Larger pitfalls ("The ugly")
November 18, 2006 ACSE 2006 3
Recursion Defined
See "Recursion"
November 18, 2006 ACSE 2006 4
Real Definition
Recursion is defining a function/procedure/structure using the function/procedure/structure itself in the definition
November 18, 2006 ACSE 2006 5
A better definition of Recursion
If you still don't understand recursion, see "Recursion"
November 18, 2006 ACSE 2006 6
A more formal definition
A recursive definition will rely on a recursive definition and some base case(s)
Example: define object X of size n using objects of type X of size k (1 <= k < n)
November 18, 2006 ACSE 2006 7
Example
Babuska (Russian) dolls
November 18, 2006 ACSE 2006 8
Real-World Example
Shells
November 18, 2006 ACSE 2006 9
Real-World Example
Flowers
November 18, 2006 ACSE 2006 10
Real-World Example
Definition of a human I was created by my parents ... who were created by their parents … (religious/biological discussion
follows)
November 18, 2006 ACSE 2006 11
Using Recursion in CS
Less code implies less errorsNatural way of thinking
mathematical inductive reasoning allows both top-down and bottom-up
approaches
November 18, 2006 ACSE 2006 12
(Linked) Lists
C version of linked lists
typedef struct list_elem {
int val;
struct list_elem * next;
} node;
November 18, 2006 ACSE 2006 13
Recursive Ordered Insert
void insert(node** head, int newValue) {
node* newNode = malloc(sizeof(node));
newNode->val = newValue;
newNode->next = NULL;
if (*head == NULL) {
*head = newNode;
} else if ((*head)->next == NULL) {
(*head)->next = newNode;
} else if ((*head)->next->val > newNode->val) {
newNode->next = (*head)->next;
(*head)->next = newNode;
} else {
insert(&(*head)->next, newValue);
}
}
November 18, 2006 ACSE 2006 14
Recursive Length
int length(node* head) {
if (head == NULL) {
return 0;
} else {
return 1+length(head->next);
}
}
November 18, 2006 ACSE 2006 15
Scheme lists
In Scheme a list is the empty list () or a head element, followed by a list
containing the rest of the elementsExamples:
() (1 2 3 4) ((a b) (c d) (e f))
November 18, 2006 ACSE 2006 16
Scheme lists
How to access elements from a list? car = head cdr = tail (rest of the list)
Examples: (car '(a b c)) => a (cdr '(a b c)) => (b c) (car (cdr '(a b c))) => b (caddr '(a b c)) => c
November 18, 2006 ACSE 2006 17
Length in Scheme
(define reclength
(lambda (L)
(if (eq? L '())
0
(+ 1 (reclength (cdr L)))
)
)
)
November 18, 2006 ACSE 2006 18
Am I right?
Prove it!Base case: (length '()) => 0Assume true for list of length k >= 0If length is k+1, our algorithm
computes1+length(list of size k), which it can do
correctly. Our algorithm is correct. Q.E.D.
November 18, 2006 ACSE 2006 19
Trees
Extend linked lists in two dimensions not just "next" but "left" or "right"
Definition A tree is:
empty, oris a node which contains
• a value• a left tree • a right tree
November 18, 2006 ACSE 2006 20
Binary Search Trees
In fact, we will insist the following property is also true: all nodes in the left subtree of a node
are less than or equal to the value in the node
all nodes in the right subtree of a node are greater than the value in the node
November 18, 2006 ACSE 2006 21
Picture
10
96
158
12 23
194
November 18, 2006 ACSE 2006 22
Java code
public class Node
{ private int value;
private Node left;
private Node right;
// other methods are straightforward
}
November 18, 2006 ACSE 2006 23
Using trees recursively
public void insert(Node root, int newValue) {
if (newValue <= root.getValue())
{
if (root.getLeft() == null)
{ root.setLeft(new Node(newValue));
} else
{ insert(root.getLeft(), newValue);
}
} else {
if (root.getRight() == null)
{ root.setRight(new Node(newValue));
} else
{ insert(root.getRight(), newValue);
}
}
}
November 18, 2006 ACSE 2006 24
Inorder traversal
public static void inOrder(Node n)
{
if (n != null)
{
inOrder(n.getLeft());
System.out.print(n.getValue()+" ");
inOrder(n.getRight());
}
}
November 18, 2006 ACSE 2006 25
Inorder observations
Output on original tree4 6 8 9 10 12 15 19 23
Print out "in" the middleWhat if we change the printing part?Exercise: Try to do this without
recursion(Answer: It is really nasty.)
November 18, 2006 ACSE 2006 26
Preorder traversal
public void preOrder(Node n)
{
if (n != null)
{
System.out.print(n.getValue()+" ");
preOrder(n.getLeft());
preOrder(n.getRight());
}
}
November 18, 2006 ACSE 2006 27
Using traversals
Arithmetic expression trees internal nodes are operators leave nodes are operands+
- /
*
2 7
4 10 5
November 18, 2006 ACSE 2006 28
Using traversals
Notice the inorder traversal gives:2 * 7 - 4 + 10 / 5
Notice the preorder traversal gives:+ - * 2 7 4 / 10 5
TI, anyone?
November 18, 2006 ACSE 2006 29
Recursion always works
Theorem: Every iterative loop can be rewritten as a recursive call
November 18, 2006 ACSE 2006 30
How recursion "works"
Implicit call stackEvery call to a function places an
"activation" record on top of the stack in RAM Activation record remember the current
stateStack is built up, and is empty when
we return to the main caller
November 18, 2006 ACSE 2006 31
Avoiding Recursion is Ugly
Consider quicksort Sorts an array into increasing order
November 18, 2006 ACSE 2006 32
Recursive Quicksort
Recursivevoid quicksort (int[] a, int lo, int hi)
{ int i=lo, j=hi, h;
int x=a[(lo+hi)/2];
do { while (a[i]<x) i++;
while (a[j]>x) j--;
if (i<=j)
{ h=a[i]; a[i]=a[j]; a[j]=h;
i++; j--;
}
} while (i<=j);
if (lo<j) quicksort(a, lo, j);
if (i<hi) quicksort(a, i, hi);
}
November 18, 2006 ACSE 2006 33
Iterative Quicksort
QuickSort(A,First,Last)
{ var v,sp,L,L2,p,r,r2;
sp=0;
Push(First,Last);
while( sp > 0 )
{ Pop(L, r)/2;
while( L < r)
{ p = (L+r)/2;
v = A[p].key;
L2 = L;
r2 = r;
while( L2 < r2 )
{ while( A[L2].key < v )
{ L2 = L2+L;
} // ...
November 18, 2006 ACSE 2006 34
More iterative Quicksort
while( A[r2].key > v )
{ r2 = r2-L;
}
if(L2 <= r2 )
{ if(L2 equals r2)
{ Swap(A[L2],A[r2]);
}
L2 = L2 + L;
r2 = r2 - L;
}
} // ...
November 18, 2006 ACSE 2006 35
Yet more iterative Quicksort
if(r2-L > r-L2)
{ if(L<r2)
{ Push(L,r2);
}
L = L2;
} else
{ if(L2 < r)
{ Push(L2,r);
r = r2;
}
}
} // end while( L < r )
} // end while( sp>0 )
} // end QuickSort
November 18, 2006 ACSE 2006 36
Bad Fibonacci, Bad
f(0) = 0f(1) = 1f(n) = f(n-1) + f(n-2)
November 18, 2006 ACSE 2006 37
Dynamic Programming
Recursion leads to a very powerful problem solving technique called Dynamic Programming
Essentially, don't use the recursive call, but write a recurrence relation and solve it from the bottom-up
November 18, 2006 ACSE 2006 38
Shortest Paths using DP
A shortest path is a path between two vertices that has minimum weight
Number the vertices of the graph from 1..n
Let D(k, i, j) mean the shortest path between vertices i and j that uses only vertices 1, …, k
November 18, 2006 ACSE 2006 39
Base case
D(0, i, j) = 0 if i=j w(i,j) if there is an edge (i,j) otherwise
November 18, 2006 ACSE 2006 40
Recursive case
D(k+1, i, j) uses either vertex k+1 or it doesn't
If it doesn't, D(k+1, i, j) = D(k,i,j)
If it does, D(k+1, i, j) = D(k, i, k+1) + D(k, k+1, j)
So, D(k+1,i,j) is the minimum of these two
November 18, 2006 ACSE 2006 41
Filling in the table
In fact, filling in the table is done without using recursion As we did in the Fibonacci case, except
now, we are in more than one dimension
November 18, 2006 ACSE 2006 42
Ugly: Recursive Main
Don't do this in Javapublic class RecUgly
{ public static int factorial(int n)
{ if (n <= 0)
{ return 1;
} else {
return n*factorial(n-1);
}
}
public static void main(String[] args)
{ System.out.println(factorial(11));
}
}
November 18, 2006 ACSE 2006 43
Context-Free Grammars
Describe very complex things using recursion
S -> (S)S -> SSS ->
November 18, 2006 ACSE 2006 44
Mathematical beauty
Koch curves using Lindenmayer systems
Let F mean "forward", + mean "right" and - mean "left"
Koch curve Rule: F -> F-F++F-F (starting with F)
Koch snowflake Start with F++F++F instead!
November 18, 2006 ACSE 2006 45
Dragon curve
X -> X+YF+, Y->-FX-Y (start with FX)
November 18, 2006 ACSE 2006 46
Conclusion
Recursion is Beautiful Natural (in many senses) Mathematically precise Simple Powerful Recursive