Algorithm design techniques(recursion)
2 terms added to get the Fibonacci number for a term
(N-2)+(n-1)
What the Fibonacci Sequence starts with
1 & 1
What is the output of tail(15)
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
real power(real x, int n )
1: if (x = 1) or (n = 0) then 2: return 1 3: else 4: if (n > 0) then 5: return x × power(x, n − 1) 6: end if 7: end if
Recursive calls Fibonacci Sequence makes
2 calls
Factorial, Fibonacci, Palindrome
3 common recursive algorithms
recursive definition
A definition in which something is defined in terms of a smaller version of itself.
mechanism of recursion
A function is recursive if its solution contains a call of the function itself as part of the solution for a given problem. Similarly, a program (or subprogram) is recursive if it contains a statement which calls itself as part of the solution.
fractal
A geometric shape in which certain patterns repeat, perhaps at a different scale and orientation.
indirectly recursive
A method that calls another method and eventually results in the original method call.
directly recursive
A method that calls itself.
recursive method
A method that calls itself.
Fractal
A pattern which produces a picture, which contains an infinite amount of copies of itself
tail recursive method
A recursive method in which the last statement executed is the recursive call.
Tail recursion
A recursive program is "tail-recursive" if only one recursive call appears in the program and that recursive call is the last operation performed at that recursive level. For example, Algorithm 3.4 is tail-recursive but Algorithm 3.6 is not. Tail recursive methods are desirable due to their relative space efficiency
Recursion
A subprogram can be referred as a method in Java. In most conventional computer languages, a method in Java, procedure or function in C can call itself. A subprogram that calls itself is said to be recursive or referred to as a recursive method, procedure or recursive function respectively
Ackermann function recursion
A(i,j)=|J+1 if i=1, j>= 1 |A(i-1,2) if i>=2, j=1 |A(i-1,A(i,j-1)) if i,j >=2
example of nested recursion
Ackermann function
is created every time a method is called, holds arguments, variables, return address
Activation Frame
Example of binary recursion pusedo code to solve the problem add all the nubers in an integer array a:
Algorithm BinarySum(A, i, n): Input: An array A and integers i and n Output: The sum of the n integers in A starting at indexi if n = 1 then return A[i] return BinarySum(A,i,n/2)+BinarySum(A,i+n/2,n/2)
Recursive squaring power function method pseudo code
Algorithm Power(x,n): Input: A number x and integer n=0 Output: The value x^n if n=0 then return 1 if n is odd then y=Power(x,(n-1)/2) return x*y*y else y=Power(x,n/2) return y*y
Example of reversing an array using tail recursion
Algorithm ReverseArray(A, i, j): Input: An array A and nonnegative integer indices i andj Output: The reversal of the elements in A starting at index i and ending at j if i < j then Swap A[i] and A[ j] ReverseArray(A,i+1,j-1) return
Example of Fibonacci Algorithm
Algorithm: LinearFibonacci(k) Input: A nonnegative integer k Output: A pair of Fibonacci numbers (F(k),F(k-1)) if k=1 then return (k,0) else (i,j)= LinearFibonacci(k-1) return (i+j,i)
Verifying the correctness of a recursive function is equivalent to verifying the following conditions: Step 2
All recursive calls of the function involve a case of the problem that is closer to one of the base case.
recursive algorithm
An algorithm that finds the solution to a given problem by reducing the problem to smaller versions of itself.
When coding the solution as a recursive function the following condition must be satisfied Step 2
Any recursive use of the function must move the problem closer to one of the base cases.
can only be performed on sorted array base case if array is empty or if target element is middle element algorithm if array is empty return -1; else if middle matches the target return subscript of middle element else if target is < middle element recursively search array elements before the middle element return result; else recursively search the elements to the right of middle element return result
Binary Search Algorithm
public static int binarySearch(Object items,Object target, int first, int last ) { //base case if (first>last) return -1; else int middle = first + last/2 int result = target.compareTo(items[middle]) if (result == 0) return middle; else if result< middle return binarySearch(items, first, middle-1) }
Binary Search Implementation
Recursion
Calls itself to help solve the problem in smaller parts
By drawing out the calls
Can trace a recursive solution
Merge step 1
Divide an n-element input sequence to be sorted into two subsequences of n/2 elements each.
The two basic step of quick sort step 1
Divide the array A[p..r] into two nonempty subarrays A[p..q]and A[(q + 1)..r] such that each element of A[p..q] is less than or equal to each element of A[(q + 1)..r]. The element q (called the pivot) is computed by the algorithm.
Recursive case(s)
Divide, invoke, combine
Iteration - complexity
Easier to approach
Recursion - ease of understanding
Easier to break Down
Question: In previous examples, which are the base cases and which are the inductive steps?
Example 3.3 Let us look at the well-known Fibonacci sequence 1, 1, 2, 3, 5, 8, 13, 21, 24, 34, .... Fibonacci sequence starts with two 1s. Each Fibonacci number thereafter is the sum of the two preceding numbers. This infinite sequence can be defined recursively by a1 = 1, a2 = 1 (Base case) an = an−1 + an−2, for n > 2 (Recursive step).
MC Eschers Drawing Hands
Example of recursion
Russian Nesting Dolls
Example of recursion
Sea shells, snail shells, elephant trunks, flowers, pineapples
Examples of Fibonacci in nature
Trees and snowflakes
Examples of recursion
Example of Factorial function f(n)=n!
F(n)= 1 if n=0 nf(n-1) if n>0
if n = 0 return 1 else n! = n(n-1)!
Factorial Algorithim
n! = n * (n-1)! (n > 0) ex. 4! = n * 3! ( 4 > 0) base case n = 0
Factorial Recursive
Common recursive programs
Factorials, Fibonacci, palindrome, drawing fractles
Fibonacci sequence
Find the nth term by adding the term before it and the term before that (n= (n-1)+(n-2))
Recursion - primary paradigm
Functional
Iteration - ease of understanding
Harder to track down Variables
Recursion - complexity
Harder to visualize
listMoves(int NumDisks, char StartPeg, LastPeg, SparePeg)
INPUT: The number of disks to move, the initial peg StartPeg, the destination peg LastPeg and the working peg SparePeg OUTPUT: Nothing (but display the moves) 1: if NumDisks = 1 then 2: writeln ("Move a disk from ", StartPeg, " to ", LastPeg) 3: else 4: ListMoves(NumDisks-1, StartPeg, SparePeg, LastPeg) 5: writeln ("Move a disk from ", StartPeg, " to ", LastPeg) 6: ListMoves(NumDisks-1, SparePeg, LastPeg, StartPeg) 7: end if
Iteration - primary paradigm
Imperative
what is recursion mathematically
In Mathematics, recursion is a process (or phenomenon) of finding solutions to a sequence of subproblems that are identical to the original problem but smaller in problem size.
recursive function composed of
In general, a function is said to be defined recursively if its definition consists of the following two parts: 1. Base case This must be a well defined termination 2. Inductive or recursive steps This consists of well defined inductive (or recursive) steps that must lead to a termination state
Example 3.6 (Towers of Hanoi problem) This is a game with a long history. There are 3 pegs (A, B, C) and a set of n disks of n different sizes. We mark them 1 · · · n with disk 1 the smallest, and n the largest (there are n = 64 disks in the legend). The n disks are to be moved from one peg to another, for example, from peg A to C. However, only one disk is allowed to be moved on each step and the disks must remain in the sorted order with the smallest on the top at any peg, so no disk is above a smaller one. Figure 3.1 shows that three disks on peg A need to be moved to peg C.
Let us summarise the problem again: Consider three pegs (A, B, C) and 3 disks (1, 2, 3) as in Figure 3.1, with disk 1 the smallest, and 3 the largest. Objective: to move the disks from peg A to C; Two rules: 1. one disk may be moved at a time 2. a larger disk can never be placed on a smaller disk. Suppose n is the number of disks. We take a recursive approach. 1. Base case: The solution for 1-disk problem (n = 1): Move the disk from peg A to peg C (Figure 3.2). 2. Inductive steps: (a) The solution for 2-disk problem (n = 2): i. Use the one-disk solution to move disk 1 to peg B, ii. then move disk 2 to peg C and iii. use the solution to the one-disk problem to move disk 1 to peg C
Enumeration
Looking for patterns in the code
Merge sort step 3
Merge the two sorted subsequences to produce the sorted sequence.
Base case in factorial solution
Num=0 or 1, report 1
Recursive squaring method runs
O(log n) time
The best-case efficiency of the quick sort
O(n log2 n)
The average run-time efficiency of the quick sort is
O(n log2 n),
The worst-case efficiency of the quick sort
O(n^2)
How can you recursively define the power function, P(x,n)=x^n
P(x,n)=|1 if n=0 |x *P(x, n-1) if n>0
Recursion and iteration have
Pros and cons
recursion function
Recursion is a powerful algorithmic tool for problem solving. As we shall see later, recursion is another way to realise repetition
Example of binary recursion peuso code
Recursive algorithm (first attempt): Algorithm BinaryFib(k): Input: Nonnegative integer k Output: The kth Fibonacci number Fk if k = 1 then return k else return BinaryFib(k - 1) + BinaryFib(k - 2)
The two basic step of quick sort step 2
Recursively call the Quick sort to sort A[p..q] and A[(q + 1)..r].
rightmost bit
Remainder of a number after division by 2.
For example, we defined the array reversal function as ReverseArray(A, i, j), an not
ReverseArray(A).
is a stack created by Java that holds activation frames it creates a new Activation frame every time a method is called.
Run Time Stack
Write recursive case so sprite moved to relocate angles and
Same size scaling factor of the parts of the fractal
Example 3.1 Given a non-negative integer n, compute n factorial
Solution 0!=1; 1!=1; for n>1, n!= n * (n-1)! For instance, when n = 5, 5! = 5 ∗ 4! = 5 ∗ 4 ∗ 3! = 5 ∗ 4 ∗ 3 ∗ 2! = 5 ∗ 4 ∗ 3 ∗ 2 ∗ 1! = 5 ∗ 4 ∗ 3 ∗ 2 ∗ 1
Example 3.2 Given n, an integer ≥ 0, and x, a real, compute the n consecutive powers of some number x.
Solution n = 0, xn = 1 n > 0, xn = x ∗ xn−1 For instance, when x = 3, n = 5, 30 = 1; 35 = 3 × 34, 34 = 3 × 33, 33 = 3 × 32, 32 = 3 × 31, 31 = 3 × 30 = 3 × 1.
Merge sort step 2
Sort the two subsequences recursively using merge sort
base case of quick sort
The base case is when there is one element to be sorted (which is returned as is because it is already sorted)
recursive case
The case in a recursive definition in which a smaller version of itself is called; general case.
general case
The case in a recursive definition in which a smaller version of itself is called; recursive case.
base case
The case in a recursive definition in which the solution is obtained directly.
Verifying the correctness of a recursive function is equivalent to verifying the following conditions: Step 1
The function contains (non-recursive) base cases.
Invoke
The function(recursively) on each part
Divide
The problem into 1 or more simpler/smaller parts
Base case
The problem is simple enough to be solved directly
recursion
The process of solving a problem by reducing it to successively smaller versions of itself.
Verifying the correctness of a recursive function is equivalent to verifying the following conditions: Step 3
The recursion properly implements the problem to be solved.
Combine
The solutions of the parts into a solution for the problem
Merge sort have time complexity
There are no best-case or worst-case
When coding the solution as a recursive function the following condition must be satisfied step 1
There must be at least one simple (base) case of the problem being solved that does not require recursion.
iterative control structures
Use a looping structure to repeat a set of statements.
Recursion - length of implementation
Uses fewer lines
Iteration - memory
Uses less memory
Iteration - length of implementation
Uses more lines
Recursion - memory
Uses more memory
Why recursion?
We first summarise the reasons and then look at an example. It may be the best way of thinking to solve some problems such as the Towers of Hanoi problem below. Algorithms can be very short as compared to an iterative version.It can help us understand certain problems. We may derive an iterative version later, based on the recursive one. In this way, a more efficient algorithm may be developed. the Quicksort algorithm.
Pick a base case that capture the part of the image which
Will be repeated throughout the image
C++ of void merge
___(int A[], int copyA[], int leftPos, int rightPos, int rightEnd) { int leftEnd = rightPos - 1; int j = leftPos; // index for copyA while (leftPos <= leftEnd && rightPos <= rightEnd) if ( A[leftPos] < A[rightPos] ) copyA[j++] = A[leftPos++]; else copyA[j++] = A[rightPos++]; // copy the rest while (leftPos <= leftEnd) copyA[j++] = A[leftPos++]; while (rightPos <= rightEnd) copyA[j++] = A[rightPos++]; }
c++ of Void mergeSort
____(int A[], int copyA[], int left, int right) { if (left < right) { int center = (left + right)/2; mergeSort(copyA, A, left, center); mergeSort(copyA, A, center+1, right); merge(A, copyA, left, center+1, right); } }
Indirect recursion
a function f () calls a function g() and the function g() calls the function f ().
When a function is called what information is stored 4
a returned value for a function (when not declared as void)
To define the method in ways that facilitate recursion then we must define
additional parameters that are passed to the method.
When a function is called what information is stored 1
alues for all formal parameters of the function
To describe quick sort
assume that we sort a subarray A[p..r]. The notation A[p..r] stands for an array with elements A[p], A[p + 1], . . . , A[r].
Why dose recursive squaring method runs at O(log n) time
because each time a recursive call is made it halve the value of n
Tail recursion
characterized by the use of only one recursive call at the end of a function.
classes that implement the comparable interface must define the compareTo() method
comparable interface
Merge sort Algorithm the copy A dose
copy of the array a
When a function is called what information is stored 3
ddress of the caller's instruction immediately following the call
In creating recursive methods, it is important
define the methods in ways that facilitate recursion.
Recursion:
defining the solution to a problem in terms of a simpler version of the same problem. It must eventually end in a version which does not contain any recursion at all and then immediately returns an answer through the preceding levels of recursive calls.
Recursive callings are represented internally by
different activation records s and are thus differentiated by the system
this information is stored dynamically using the
e run-time stack
if n = 0 return 1 else result is x* x^(n-1)
exponent Algorithm
Example of base case
factorial function the base case is n = 0.
factorail function
int factorial(int n) 1: if (n ≤ 1) then 2: return 1 3: else 4: return n × factorial(n − 1) 5: end
Recursive programs
int fibonacciItem(int n); (where n > 0) 1: if (n = 1) or (n = 2)) then 2: return 1 {where n > 0} 3: else 4: return fibonacciItem(n − 1) + fibonacciItem(n− 2) 5: end if
C++ quick sort main
int main(void) { int A[100]; ... // initialize the array A quicksort(A, 100); ... // use the sorted array A } void quicksort(int A[], int n) { quicksort(A, 0, n); } void quicksort(int A[], int low, int high) { if (low < high) { int middle = qsPartition(A, low, high); quicksort(A, low, middle); quicksort(A, middle+1, high); } }
Merge sort main
int main(void) { int A[100]; ... // initialize A mergeSort(A, 100); ... // use the sorted A }
Quick sort partition
int qsPartition(int A[], int low, int high) { int pivot = A[low]; int i = low-1, j = high+1; while (true) { do { j--; } while (pivot < A[j]); do { i++; } while (A[i] < pivot); if (i < j) { //swap A[i] and A[j] int temp = A[i]; A[i] = A[j]; A[j] = temp; } else return j; } }
most recursive implementations code
is shorter than it is in the non-recursive version
iteration has a condition that determines when to stop the loop recursions uses a base case, when it equals that case
iteration vs recursion
public static int factorial(int n) { int result = 1; for ( int k = 1; k<=n; k++) result = result * k return result; }
iterative factorial method
the recursively power function runs in
liner O(n) time( for we make n recursive calls)
private int size(Node head) { if (head == null) return 0; else return 1+size(head.next); }
linked List recursive size method
When a function is called what information is stored 2
local variables (which can be stored elsewhere, but then pointers to them must be stored)
C++ implementation of factorial
long factorial(int n){ if(n==0) return 1; else return n*factorial(n-1)}
Iterative Factorial()
long factorialNonRecur(int n) { int result = 1; for (int k = n; k > 0; k--) result *= k; return result; }
The Merge Sort Algorithm left <= right denote
lower and upper indices of the subarray to be sorted
To handle recursion properly then a system
must create an activation record whenever a function is called
The average case of quick sort where
n is the number of elements in array to be sorted
Example of recursive step 2
n the factorial function the recursive call is factorial(n-1) which is one step closer than the original call factorial(n)
Is Merge sort practical
no Because the merge sort needs a duplicate copy of the array being sorted
In languages (such as C++ or Java) is there advantage ins using tail recursion over iteration
no in such languages tail recursion is not a recommendable feature.
When using the recursive squaring method do you call the method twice
no you have to use the variable twice
Binary recursion
occurs whenever there are two recursive calls for each non-base case.
Where is the activation record allocated
on the run-time stack
An activation record exists
or as long as a function owning it has not completed its execution, then it is removed from the stack by the system.
algorithm to improve the power function by repeated squaring for n=1 return 1n>0
p(x,n)| x *p(x,(n-1)/2)^2 if x >0, n odd | p(x,n/2)^2 if x >0, n even | 1 if x >0, n=0
The recursive version increases
program readability, improves self-documentation, and simplifies coding
find the largest integer that divides both numbers ex 20 and 15 GCD = 5 36 and 24 GCD = 12 given 2 positive integers n,m m> n if n is a divisor of m GCD of m and n = GCD(m,n) = (n, m%n)
recursive GCD
linked list is a recursive data structure Linked list either has a node or is empty
recursive Linked List
private void add(Node head, Object data) { if (head.next == null) head.next = new Node data else add(head.next, data) }
recursive add()
base case is empty array first element of array being search is target search rest of array minus the first element algorithm if array is empty return -1 else if first element of array match's target return subscript of element in array else search the array minus the first element implementation private static int search(Object[] items, Object target, int posFirst) { if (posFirst == items.length) return -1; else if (target.equals(items[posFirst])) return posFirst else return search(items, target, posFirst+1) }
recursive array search
Factorials Powers GCD
recursive examples
first check if n is <=2 and if so return 1, this is the base case, else return fib(n-1) + fib (n-2) fibonacci is a sequece that adds two numbers together, starts at n = 2 (2-1)+ (2-2) = 1 n = 3 (3-1) + (3-2) = 3 n = 4 (4-1) + (4-2) = 5
recursive fibo method
private boolean remove(Node head, Node pred, Object data) { if (head == null) return false; else if (head.data.equals(data) pred.next = head.next; //removes head return true; else return remove(head.next, pred, data)
recursive remove()
private void replace(Node head, Object old, Object new) { if (head != null) if(old.equals(head)) head.data = new; replace(head.next, old, new) }
recursive replace
private String toString(Node head) { if(head == null) return ""; else return head.data + toString(head.next) {
recursive toString()
Factorial (4) | V Factoria(0)
return 1 1*1=1 2*1=2 3*2=6 4*6=24
The merge sort requires
s O(n log2 n) comparisons
Nested recursion
s when a function not only calls itself but the function call is also used as one of the parameters
Recursion means calling a function of the
same name as the caller with the same formal arguments
The function mergeSort is
simple driver that declares a temporary array and calls the recursive function mergeSort
Quick sort
sorting algorithm based on recurrence.
Merge function in Merge sort
sorting itself
Sierpinski gasket
special type of fractal.
non-tail recursion example
static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; void printHexadecimal(int n) { if (n >= 16) printHexadecimal(n/16); cout << hexDigits[n % 16]; }
implementation of recursion
static int fibonacciItem(int n) { int f=0; if (n=1) || (n=2) { f=1;} else{ f=fibonacciItem(n-1)+fibonacciItem(n-2);} return f;} static int factorial(int n) { int f=0; if (n<2) { f=1;} else{ f=n*factorial(n-1);} return f;} static double power(double x, int n) { double p=0.0; if ((x==1) || (n==0)) { p=1; } else if (n>0) { p=x*power(x, n-1); } return p; }
The worst case for the algorithm is when
the array is already sorted and depend on the choice of the pivotal element(pivot)
In a tail recursion
the recursive call is the last statement
The Droste effect
the result of a picture recursively appearing within itself, in a place where a similar picture would realistically be expected to appear.
Activation record (stack frame)
the set set of information that is called
In C++, the prefix 0x is used
to represent hexadecimal numbers
Merge sort
uses recursion to sort an array of numbers
Merge sort function
void mergeSort(int A[], int n) { int *copyA = new int[n]; for (int i = 0; i < n; i++) copyA[i] = A[i]; mergeSort(copyA, A, 0, n-1); delete [] copyA; }
Example of tail recursion
void tail(int n) { if (n > 0) { cout << n << " "; tail(n - 1); } else cout << endl; }
example of tail function using iterative approach
void tailNonRecur(int n) { for (int k = n; k > 0; k--) cout << k << " "; cout << endl; }
Merge sort base case
when the subsequence contains one or zero elements (which are already sorted).
is a tail recursion like a loop
yes
In language(such as Prolog,Lisp) is there advantage in using tail recursion over iteration
yes such language have explicit loop constructs so tail recursion is important