... 1/40 CSCI 2212: Intermediate Programming / C Recursion Alice E. Fischer November 13 and 16, 2015
... 2/40 Outline What is Recursion? Recursively Defined Images What is a Recursive Function? How Does A Recursive Function Work? Recursive Coding Patterns
... 3/40 What is Recursion? I. What is Recursion?
... 4/40 What is Recursion?
... 5/40 What is Recursion? Recursive Definition A thing defined in terms of itself. Definition: Recursion see Recursion. Google Recursion, you get Did you mean: Recursion?. Definition: Recursion If you still don t get it, see Recursion. Definition: Fractal A rough or fragmented geometric shape that can be split into parts, each of which is (at least approximately) a reduced-size copy of the whole.
... 6/40 What is Recursion?
... 7/40 What is Recursion? The Mandlebrot Set z 0 = 0 z n+1 = z 2 n + c where c is a complex number (a point on the complex plain) A complex number, c, is part of the Mandelbrot set if the absolute value of z n never exceeds a limit (which depends on c) however large n gets. In visualizations, points on the plane that belong to the Mandlebrot Set are colored black. The other colors encode the number of repetitions required, for that point, until the computation diverges.
... 8/40 What is Recursion? The Mandlebrot Set
... 9/40 What is Recursion? Self-similar at a smaller scale
... 10/40 What is Recursion? Zooming In
... 11/40 What is Recursion?
... 12/40 Recursively Defined Images The Sierpinski Triangle
... 13/40 Recursively Defined Images Fractal Tree
... 14/40 Recursively Defined Images Hilbert s Space-Filling Curve: Recursive Definition Each cup is replaced by four cups of half the size, connected by three links.
... 15/40 Recursively Defined Images Hilbert s Space-Filling Curve Order 1
... 16/40 Recursively Defined Images Hilbert s Space-Filling Curve Building Order 2
... 17/40 Recursively Defined Images Hilbert s Space-Filling Curve Building Order 2
... 18/40 Recursively Defined Images Hilbert s Space-Filling Curve Orders 1 and 2
... 19/40 Recursively Defined Images Hilbert s Space-Filling Curve Orders 1, 2, and 3
... 20/40 What is a Recursive Function? I. What is a Recursive Function in C? A method of repetition. A top-down way to solve a problem. A function that calls itself.
... 21/40 What is a Recursive Function? A Method of Repetition Recursion is a control structure for implementing repetition. It is nearly as old as programming languages. FORTRAN (1957) provided a counted loop and GOTO for repetition. Recursion was the foundation of LISP (List Processing Language, 1958), which had no loops and no GOTO. Both counted loops and recursion were present in ALGOL (1958, 1960). Other kinds of loops (while, do) developed much later. Recursion and if...else are all you need to implement a programming language.
... 22/40 What is a Recursive Function? Procedural Thinking In a program with loops, the programmer starts with input and a goal, and plans a series of steps to transform the input into the goal. Some of those steps involve loops. This is sequential thinking, sometimes called procedural thinking. The focus of the thought is a procedure to achieve the goal, given the input. One can also solve problems using recursive thinking.
... 23/40 What is a Recursive Function? Recursive Thinking Suppose you have a large problem to solve. Figure out how to break the problem into two or more parts in such a way that the results can be combined to solve the original problem. Figure out how to solve the problem for one or a few data items. Make sure that you can divide every large problem into smaller problems that can eventually be reduced to the case for a few items that you already know how to solve.
... 24/40 What is a Recursive Function? The Recursion Parameter(s) One or more parameters to a recursive function define the size of the problem to be solved. A loop is infinite if the body of the loop does not change the variable used in the exit test. An recursion is infinite if the exit test is never true because the recursion parameter(s) cycle or diverge or do not change. To write a correct recursion, you must ensure that the number of unexplored possibilities decreases on each recursive call. Example: factorial decrements its parameter on each call. Example: the difference between two parameters of quicksort becomes smaller on each call.
... 25/40 What is a Recursive Function? A Recursive Sorting Algorithm Suppose you have a set of numbers (written on cards) to sort into into ascending order (smallest on top). If there is one object in the set, it is sorted. Return the sorted card to your boss. Sit down. If there are two to four objects in the set, sort them using insertion sort. Return the sorted cards to your boss. Sit down. Otherwise, divide your stack approximately in half, find two helpers (they should stand up), and delegate sorting the halves to them. Wait until both of your helpers return their sorted cards to you. Merge the two stacks into one sorted stack. Return the stack to your boss. Sit down.
... 26/40 How Does A Recursive Function Work? I. How Does Recursion Work? Function calls make stack frames. A recursive function calls itself. Walking in and walking out of the recursion.
... 27/40 How Does A Recursive Function Work? Function calls make stack frames. Modern programming languages use automatically allocated dynamic memory for function calls. Before a function is called, memory on the run-time stack is automatically allocated in a block called a stack frame. The calling program stores the parameter values in this block. Then the hardware stores the return address and two stack pointers in the block. Space for the local variables follows the pointers. It is initialized when control enters the function. Then the function s code is executed. When the function returns, the stack frame is deallocated.
... 28/40 How Does A Recursive Function Work? A recursive function calls itself. When a function calls itself, the stack frame for the caller and the stack frame for the called are BOTH on the stack. If recursive calls continue, many frames can exist simultaneously for successive invocations of the same function. The newest frame is always used as the context for execution. The older frames just wait on the stack until their children return and the child frames are deleted. Then the parent frame becomes active again. unsigned factorial( unsigned n ) { if (n < 2) return 1; return n * factorial( n-1 ); }
... 29/40 How Does A Recursive Function Work? Stacking up the Frames: First Call unsigned answer = factorial( 4 ); factorial n 2 pointers return address 4 main answer? main answer? Before the first call. After the first call.
... 30/40 How Does A Recursive Function Work? Stacking up the Frames: 2nd and 3rd Calls 2 pointers factorial n return address 2 factorial n 2 pointers return address 3 factorial n 2 pointers return address 3 factorial n 2 pointers return address 4 factorial n 2 pointers return address 4 main answer? main answer? After the second call. After the third call.
... 31/40 How Does A Recursive Function Work? Stacking up the Frames: Last Call, First Return factorial return 1 n 2 pointers return address 1 factorial n 2 pointers return address 2 factorial return 2*1 n 2 pointers return address 2 factorial n 2 pointers return address 3 factorial n 2 pointers return address 3 factorial n 2 pointers return address 4 factorial n 2 pointers return address 4 main answer? After the fourth call. main answer? After the first return.
... 32/40 How Does A Recursive Function Work? Stacking up the Frames: Finishing Up factorial return 3*2 n 2 pointers return address 3 factorial return 4*6 n 2 pointers return address 4 factorial n 2 pointers return address 4 main answer? After the third return. main answer? After the second return. main answer 24 After the last return.
... 33/40 How Does A Recursive Function Work? Walking in and walking out of the recursion. Two kinds of things happen to the stack during a recursion: Stack frames are added as more recursive calls happen. Stack frames are removed when calls return. In the factorial example, all the stack frames were created before anything was removed. However, this recursion is particularly simple. Many recursions (such as merge sort) add and remove, add and remove, in complex patterns. Students generally find it easy to understand how and when stack frames are added. Some students have trouble with removing them one at a time and returning a value to the caller each time.
... 34/40 Recursive Coding Patterns I. Recursive Patterns Linear tail recursion: sequential search Linear recursion with post-processing: maximum Non-linear tail recursions: Decision trees. Divide and Conquer: quicksort Backtracking: Exhaustive search.
... 35/40 Recursive Coding Patterns Tail recursion: Sequential Search A tail recursion is equivalent to a while loop and can easily be rewritten as a loop. Only one recursive call is made on each activation. No processing is done after a child call returns the answer returned by the child is returned directly to the parent, and again, up the line to the original caller. n is the number of values in the array; last value is at n-1. int seqsearch( double ary[], int n, double key ) { if (n<1) return -1; if (ary[n-1]==key) return n-1; return seqsearch( ary, n-1, key ); }
... 36/40 Recursive Coding Patterns Linear recursion that is not tail recursion: maximum Only one recursive call is made on each activation. The recursive call is NOT the last thing executed on each repetition. After a child call returns, the parent uses the return value to compute something before returning to its caller. // Return the subscript of the maximum element in the array. int maximum( double ary[], int n ) { if (n==1) return 0; int temp = maximum( ary, n-1 ); return (ary[n-1] > ary[temp])? n-1 : temp ; }
... 37/40 Recursive Coding Patterns Decision trees: Non-linear tail recursions. Two recursive calls appear in the code. However, only one recursive call is made on each activation. int binsearch (double ary[], int first, int last, double key) { if (last < first) return -1; // Search failed. int mid = first + (last - first)/2; if (ary[mid]==key) return mid; // Success. if (ary[mid]>key) return binsearch(ary, first, mid-1, key); return binsearch( ary, mid+1, last, key ); }
... 38/40 Recursive Coding Patterns Divide and Conquer: quicksort In practice, this is the fastest sorting algorithm for up to a couple of thousand values. Split the array into two sections such that everything in the left section is less than everything in the right section. Recursively sort each section. When a section is short (say below 20 items) stop using recursion and use insertion sort instead. Refer to code file quick.c
... 39/40 Recursive Coding Patterns Backtracking We do not know any efficient solution algorithm for some problems. One way to solve such problems is to try all possible solutions. Backtracking is one way to search a space of possibilities. A partial solution is built incrementally. Each forward step reduces the number of untried possibilities. A partial solution is discarded when it becomes clear that it cannot be extended to a full solution. When that happens, control backtracks to the previous partial solution (from which it was derived), from whence a different way to progress is attempted.
... 40/40 Recursive Coding Patterns Recursive exhaustive search (runmaze.c) We implement backtracking with a recursive function that tries the possibilities. The parameter to the function specifies the current position in the search space. The set of existing stack frames specifies the partial solution. On each activation, we try all possibile ways to progress, starting from the current position. If a possibility succeeds, it becomes the new position and the basis for further exploration. If all of those possibilities fail, we backtrack, that is, we return from the current stack frame to its parent frame. A position that has failed is never tried again. The process ends when we reach the goal or exhaust all possibilities.