Data Structures & Algorithms Recursion and Trees Richard Newman
Recursion Fundamental concept in math and CS Recursive definition Defined in terms of itself aN = a*aN-1, a0 = 1 Recursive function Calls itself int exp(int base, int pow) { return (pow == 0? 1 : base*exp(base, pow)); }
Recursion Recursive definition (and function) must: 1. have a base case – termination condition 2. always call a case smaller than itself All practical computations can be couched in a recursive framework! (see theory of computation)
Trees Recursively defined structures e.g., binary tree Base case: – Empty tree has no nodes Recursion: – None-empty tree has a root node with two children, each a tree
Roadmap to Recursion Widely used in CS and with trees... Mathematical recurrences Recursive programs Divide and Conquer Dynamic Programming Tree traversal DFS
Recursive Algorithms Recursive algorithm – solves problem by solving one or more smaller instances of same problem Recurrence relation – factorial – N! = N(N-1)!, for N > 0, with 0! = 1. – In C++, use recursive functions Int factorial(int N) { if (N == 0) return 1; return N*factorial(N-1); }
Recursive Algorithms BTW, can often also be expressed as iteration E.g., can also write N! computation as a loop: int factorial(int N) { for (int t = 1, i = 1; i <= N; ++i) t *= i; return t; }
Euclid's Algorithm Euclid's Algorithm is one of the oldest known algorithms Recursive method for finding the GCD of two integers int gcd(int m, int n) {// expect m >= n if (n == 0) return m; return gcd(n, m % n); } Base case Recursive call to smaller instance
Divide & Conquer Recursive scheme that divides input into two (or some fixed number) of (roughly) equal parts Then makes a recursive call on each part Widely used approach Many important algorithms Depending on expense of dividing and combining, can be very efficient
Divide & Conquer Example: find the maximum element in an array a[N] Easy to do iteratively... Base case: – Only one element – return it Divide: – Split array into upper and lower halves Recursion: – Find maximum of each half Combine results: – Return larger of two maxima
Divide & Conquer Property 5.1: A recursive function that divides a problem of size N into two independent (non-empty) parts that it solves, recursively calls itself less than N times. Prf: T(1) = 0 T(N) = T(k) + T(N-k) + 1 for recursive call on size N divided into one part of size k and the other of size N-k Induct!
Tower of Hanoi 3 pegs N disks, all on one peg Disks arranged from largest on bottom to smallest on top Must move all disks to target peg Can only move one disk at a time Must place disk on another peg Can never place larger disk on a smaller one Legend has it that the world will end when a certain group of monks finishes the task in a temple with 40 golden disks on 3 diamond pegs
Tower of Hanoi Target peg Which peg should top disk go on first?
Tower of Hanoi How many moves does this take?
Tower of Hanoi Property 5.2: The recursive d&c algorithm for the Towers of Hanoi problem produces a solution that has 2N – 1 moves. Prf: T(1) = 1 T(N) = T(N-1) T(N-1) = 2 T(N-1) + 1 = 2N – 1 by induction
Divide & Conquer Two other important D&C algorithms: Binary search MergeSort Algorithm/metri c RecurrenceApprox. Soln. Binary Search comparisons C(N) = C(N/2)+1lg N MergeSort recursive calls A(N) = 2 A(N/2) + 1 N MergeSort comparisons C(N) = 2 C(N/2) + N N lg N
Dynamic Programming In Divide & Conquer, it is essential that the subproblems be independent (partition the input) When this is not the case, life gets complicated! Sometimes, we can essentially fill up a table with values we compute once, rather than recompute every time they are needed.
Dynamic Programming Fibonacci Numbers: F[0] = 0 F[1] = 1 F[N] = F[N-1] + F[N-2] Horribly inefficient implementation: int F(int N) { if (N < 1) return 0; if (N == 1) return 1; return F(N-1) + F(N-2); }
Dynamic Programming How bad is this code? How many calls does it make to itself? F(N) makes F(N+1) calls! Exponential!!!!
Dynamic Programming Can we do better? How? Make a table – compute once (yellow shapes) Fill up table
Dynamic Programming Property 5.3: Dynamic Programming reduces the running time of a recursive function to be at most the time it takes to evaluate the functions for all arguments less than or equal to the given argument, treating the cost of a recursive call as a constant.
Trees A mathematical abstraction Central to many algorithms Describe dynamic properties of algorithms Build and use explicit tree data structures Examples: Family tree of descendants Sports tournaments (Who's In?) Organization Charts (Army) Parse tree of natural language sentence File systems
Types of Trees Trees Rooted trees Ordered trees M-ary trees and binary trees Defn: A Tree is a nonempty collection of vertices and edges such that there is exactly one path between each pair of vertices. Defn: A path is a list of distinct vertices such that successive vertices have an edge between them Defn: A graph in which there is at most one path between each pair of vertices is a forest.