Recursion CITS1001.

Slides:



Advertisements
Similar presentations
Introduction to Recursion and Recursive Algorithms
Advertisements

Copyright 2006 by Pearson Education 1 Building Java Programs Chapter 12: Recursion.
Scott Grissom, copyright 2004 Chapter 5 Slide 1 Analysis of Algorithms (Ch 5) Chapter 5 focuses on: algorithm analysis searching algorithms sorting algorithms.
Unit 181 Recursion Definition Recursive Methods Example 1 How does Recursion work? Example 2 Problems with Recursion Infinite Recursion Exercises.
1 Recursion  Recursion is a fundamental programming technique that can provide an elegant solution certain kinds of problems  Chapter 11 of the book.
1 Introduction to Recursion  Introduction to Recursion  Example 1: Factorial  Example 2: Reversing Strings  Example 3: Fibonacci  Infinite Recursion.
©The McGraw-Hill Companies, Inc. Permission required for reproduction or display. ETC - 1 What comes next? Recursion (Chapter 15) Recursive Data Structures.
ELC 310 Day 24. © 2004 Pearson Addison-Wesley. All rights reserved11-2 Agenda Questions? Problem set 5 Parts A Corrected  Good results Problem set 5.
Copyright © 2008 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Starting Out with Java: Early Objects Third Edition by Tony Gaddis Chapter.
CHAPTER 10 Recursion. 2 Recursive Thinking Recursion is a programming technique in which a method can call itself to solve a problem A recursive definition.
Chapter 11 Recursion. © 2004 Pearson Addison-Wesley. All rights reserved11-2 Recursion Recursion is a fundamental programming technique that can provide.
Recursion CITS1001.
1 Decrease-and-Conquer Approach Lecture 06 ITS033 – Programming & Algorithms Asst. Prof. Dr. Bunyarit Uyyanonvara IT Program, Image and Vision Computing.
JAVA: An Introduction to Problem Solving & Programming, 5 th Ed. By Walter Savitch and Frank Carrano. ISBN © 2008 Pearson Education, Inc., Upper.
© 2010 Pearson Addison-Wesley. All rights reserved. Addison Wesley is an imprint of Chapter 15: Recursion Starting Out with Java: From Control Structures.
Copyright © 2011 Pearson Education, Inc. Starting Out with Java: Early Objects Fourth Edition by Tony Gaddis Chapter 14: Recursion.
Chapter 12 Recursion, Complexity, and Searching and Sorting
1 Programming with Recursion. 2 Recursive Function Call A recursive call is a function call in which the called function is the same as the one making.
Lecturer: Dr. AJ Bieszczad Chapter 11 COMP 150: Introduction to Object-Oriented Programming 11-1 l Basics of Recursion l Programming with Recursion Recursion.
Copyright © 2009 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Java Software Solutions Foundations of Program Design Sixth Edition by Lewis.
1Recursion. 2 Outline thinking recursively recursive algorithms iteration vs. recursion recursive functions integer exponentiation (pow) infinite recursion.
Review Introduction to Searching External and Internal Searching Types of Searching Linear or sequential search Binary Search Algorithms for Linear Search.
Chapter 13 Recursion. Learning Objectives Recursive void Functions – Tracing recursive calls – Infinite recursion, overflows Recursive Functions that.
1 TCSS 143, Autumn 2004 Lecture Notes Recursion Koffman/Wolfgang Ch. 7, pp ,
CSE 501N Fall ‘09 12: Recursion and Recursive Algorithms 8 October 2009 Nick Leidenfrost.
11-1 Recursive Thinking A recursive definition is one which uses the word or concept being defined in the definition itself When defining an English word,
CSC 221: Recursion. Recursion: Definition Function that solves a problem by relying on itself to compute the correct solution for a smaller version of.
Java Programming: Guided Learning with Early Objects Chapter 11 Recursion.
Chapter 11Java: an Introduction to Computer Science & Programming - Walter Savitch 1 Chapter 11 l Basics of Recursion l Programming with Recursion Recursion.
Winter 2006CISC121 - Prof. McLeod1 Stuff No stuff today!
JAVA: An Introduction to Problem Solving & Programming, 7 th Ed. By Walter Savitch ISBN © 2015 Pearson Education, Inc., Upper Saddle River,
JAVA: An Introduction to Problem Solving & Programming, 6 th Ed. By Walter Savitch ISBN © 2012 Pearson Education, Inc., Upper Saddle River,
Recursion.
Recursion.
Chapter 13 Recursion Copyright © 2016 Pearson, Inc. All rights reserved.
Chapter Topics Chapter 16 discusses the following main topics:
to understand recursion you must understand recursion
Recursion -- Introduction
Chapter 15 Recursion.
Abdulmotaleb El Saddik University of Ottawa
Decrease-and-Conquer Approach
COP 3503 FALL 2012 Shayan Javed Lecture 15
Chapter 15 Recursion.
Java 4/4/2017 Recursion.
Recursive Thinking Chapter 9 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences.
Chapter 8: Recursion Java Software Solutions
Java Software Structures: John Lewis & Joseph Chase
Announcements Final Exam on August 17th Wednesday at 16:00.
Recursion CITS1001.
Recursive Thinking Chapter 9 introduces the technique of recursive programming. As you have seen, recursive programming involves spotting smaller occurrences.
Recursion Output Input
Chapter 12 Recursion (methods calling themselves)
Algorithm design and Analysis
2.3 Recursion do automated demo of towers of hanoi before class
Chapter 8: Recursion Java Software Solutions
Recursion.
Recursion Chapter 11.
Basics of Recursion Programming with Recursion
Chapter 11 Recursion.
Chapter 8: Recursion Java Software Solutions
11 Recursion Software Solutions Lewis & Loftus java 5TH EDITION
Recursion Taken from notes by Dr. Neil Moore
Java Programming: Chapter 9: Recursion Second Edition
Recursion Chapter 11.
Searching.
Dr. Sampath Jayarathna Cal Poly Pomona
Chapter 13 Recursion Copyright © 2010 Pearson Addison-Wesley. All rights reserved.
Java Software Solutions Foundations of Program Design Sixth Edition
2.3 Recursion Introduction to Programming in Java: An Interdisciplinary Approach · Robert Sedgewick and Kevin Wayne · Copyright © 2002–2010 · 2/17/11.
Presentation transcript:

Recursion CITS1001

Scope of this lecture Concept of recursion Simple examples of recursion Reading The BlueJ book does not have a chapter on recursion I recommend these notes from Princeton’s Intro to Programming course: http://introcs.cs.princeton.edu/java/23recursion/ Some examples in these notes are sourced from here

Recursion We have already seen that a method can call other methods Either in the same class or in other classes However a method can also call itself This self-referential behaviour is known as recursion We saw examples with Quicksort and Mergesort Recursion is an extremely powerful technique for expressing certain complex programming tasks It provides a very natural way to decompose problems There are computational costs associated with recursion The careful programmer will always be aware of these

The simplest example The factorial of a positive integer k is the product of the integers between 1 and k k! = 1 × 2 × 3 × … × (k–1) × k In Java: private long factorial(long k) { long z = 1; for (long i = k; i > 1; i––) z *= i; return z; }

Think differently! k! = 1 × 2 × 3 × … × (k–1) × k This is a recursive definition of factorial Factorial defined in terms of itself It uses factorial to define factorial

Something else is required 4! = 4 × 3! = 4 × 3 × 2! = 4 × 3 × 2 × 1! = 4 × 3 × 2 × 1 × 0! = 4 × 3 × 2 × 1 × 0 × (–1)! … We need something to tell it when to stop! The base case of the recursion is when we know the result directly 1! = 1

Recursive factorial in Java public static int factorial(int k) { if (k == 1) { return 1; } else { return k * factorial(k - 1); } In the base case factorial stops and returns a result directly In the recursive case factorial calls itself with a smaller argument

What happens in the method call? factorial(4) = 4 * factorial(3) factorial(3) = 3 * factorial(2) factorial(2) = 2 * factorial(1) factorial(1) = 1 * factorial(0) factorial(0) = 1

Every k is a local variable Each invocation of factorial has its own independent parameter k factorial(4) creates a local variable k = 4 Then factorial(3) creates its own local variable k = 3 Then factorial(2) creates its own local variable k = 2 Then factorial(1) creates its own local variable k = 1 The compiler manages all of these variables for you, behind the scenes Exactly as if you called any other method multiple times Each invocation would have its own local variable(s)

Order is crucial This will not work! private long factorial(long k) { return k * factorial(k – 1); if (k == 1) return 1; }

What could possibly go wrong? /** * factorial as above but with * exception handling for * the cases of <=0 input or * multiply overflow in the result */ public static int factorialRobust(int k) { if (k <= 0) { throw new IllegalArgumentException( "k must be >0 for factorial"); } if (k == 1) { return 1; } else { return Math.multiplyExact( k, factorialRobust(k - 1)); Recall last week’s lectures on Exceptions

Ingredients for a recursive definition Every recursive definition must have two parts One or more base cases Each base case represents some “trivial case”, where we return a result directly These are essential so that the recursion doesn’t go on forever Often either a number being 0 or 1, or an array segment having length 0 or 1 One or more recursive cases The result is defined in terms of one or more calls to the same method, but with different parameters The new parameters must be “closer to” the base case(s) in some sense Often a number getting smaller, or an array segment getting shorter, or maybe two numbers getting closer together

Multiple base cases Each Fibonacci number is the sum of the previous two Fibonacci numbers F1 = 1 F2 = 2 Fk = Fk–1 + Fk–2 1, 2, 3, 5, 8, 13, 21, …

Fibonacci in Java This version is appalling slow, though private long fib(long k) { if (k == 1) return 1; else if (k == 2) return 2; else return fib(k – 1) + fib(k – 2); } This version is appalling slow, though The number of calls to calculate fib(k) is Fk

Be careful though public int fibonacci(int n) { if (n == 0 || n == 1) { return 1; } else { return fibonacci(n-1)+ fibonacci(n-2); This looks fine, but in fact is disastrously slow because it unnecessarily repeats some calculations over and over again!

Faster Fibonacci The number of calls to calculate fib1(k) is k–1 private long fib1(long k) { return fib2(k, 1, 1); } private long fib2(long k, long x, long y) if (k == 1) return x; else return fib2(k – 1, x + y, x); The number of calls to calculate fib1(k) is k–1 Make sure you understand that fib1(k) == fib(k)

Really fast Fibonacci Constant time! private long fib3(long k) { double sq5 = Math.sqrt(5); double phi = (1 + sq5) / 2; return Math.round(Math.pow(phi, k + 1) / sq5); } Constant time! Make sure you understand that fib3(k) == fib(k)

Binary search We saw previously that linear search is very slow for large data If the data is sorted, we can use the much faster binary search Assume we are given an array of numbers in ascending order, and we want to check if the number z is in the array Inspect the middle number If the middle number is smaller than z, then if z is in the array, it must be in the top half All numbers in the bottom half are smaller than z and can be ignored If the middle number is larger than z, then if z is in the array, it must be in the bottom half

Binary search can be expressed recursively in a very natural fashion, because we repeatedly perform the same operation of calculating the middle element and then searching in an array of half the size What is the “simplest case” in this situation? The length of the array is the parameter that is reduced at each stage of binary search and so the base case is when the left and the right bounds of the array are adjacent In this situation it is trivial to determine whether or not the element we are looking for is in the array or not

Code for binary search public static boolean binarySearch(int[] a, int z) { return bs(a, 0, a.length - 1, z); } // search a[l..u] inclusive for z private static boolean bs(int[] a, int l, int u, int z) if (l == u) return a[l] == z; else int m = (l + u) / 2; if (a[m] < z) return bs(a, m + 1, u, z); else return bs(a, l, m, z);

Performance of binary search Binary search is fast because: In each recursive call, the size of the array that must be searched is reduced, in fact it is halved So there will be log2n+1 calls, where n is the size of the original array And also the base case is always reached because In each recursive call, u–l defines the length of the array segment u–l gets smaller in each call When u–l hits 0, we use the base case

Practical considerations If the array has 1024 entries, then BinarySearch will take at most 11 steps, as opposed to 1024 for the linear search If the array has 10,000,000 entries then the binary search will take at most 24 steps instead of 10,000,000!! Humans do an approximate binary search when using phone books, dictionaries and playing number guessing games

Recursive Graphics

Recursive Graphics Simple recursive drawing schemes can lead to pictures that are remarkably intricate. For example, an H-tree of order n is defined as follows: The base case is null for n = 0. The reduction step is to draw, within the unit square three lines in the shape of the letter H four H-trees of order n-1, one connected to each tip of the H with the additional provisos that the H-trees of order n-1 are centered in the four quadrants of the square, halved in size.

H-tree Htree.java takes a command-line argument n, and plots to standard drawing an H-tree of order n. An H-tree is a simple example of a fractal: a geometric shape that can be divided into parts, each of which is (approximately) a reduced size copy of the original.

draw(int n, double x, double y, double size) public static void draw(int n, double x, double y, double size) { if (n == 0) return; drawH(x, y, size); // compute x- and y-coordinates of the 4 half-size H-trees double x0 = x - size/2; double x1 = x + size/2; double y0 = y - size/2; double y1 = y + size/2; // recursively draw 4 half-size H-trees of order n-1 draw(n-1, x0, y0, size/2); // lower left H-tree draw(n-1, x0, y1, size/2); // upper left H-tree draw(n-1, x1, y0, size/2); // lower right H-tree draw(n-1, x1, y1, size/2); // upper right H-tree }

drawH(double x, double y, double size) public static void drawH(double x, double y, double size) { // compute the coordinates of the 4 tips of the H double x0 = x - size/2; double x1 = x + size/2; double y0 = y - size/2; double y1 = y + size/2; // draw the 3 line segments of the H StdDraw.line(x0, y0, x0, y1); // left vertical segment of the H StdDraw.line(x1, y0, x1, y1); // right vertical segment of the H StdDraw.line(x0, y, x1, y); // connect the two vertical segments of the H }

The main method Problem: How to execute Java without BlueJ Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling The main method Problem: How to execute Java without BlueJ The answer: The java system always executes a method called main with a certain signature: public static void main(String[] args) { ... } For this to work, such a method must exist!

The main method main must exist. main must be public. Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling The main method main must exist. main must be public. main must be static (class method). main must have a String[] parameter. Only main can be invoked.

Objects First with Java - A Practical Introduction using BlueJ, © David J. Barnes, Michael Kölling Main method - example public static void main(String[] args) { Game game = new Game(); game.play(); } Consider placing in a separate class, containing just this. The main method should create an object call the first method

Htree main method // reads an integer command-line argument n // and plots an order n H-tree public static void main(String[] args) { int n = Integer.parseInt(args[0]); double x = 0.5, y = 0.5; // center of H-tree double size = 0.5; // side length of H-tree draw(n, x, y, size); }

Pitfalls of Recursion With recursion, you can write compact and elegant programs that fail spectacularly at runtime. Study the following examples to help you to avoid the pitfalls.

Missing base case public static double harmonic(int n) { This function is supposed to compute harmonic numbers, but is missing a base case: public static double harmonic(int n) { return harmonic(n-1) + 1.0/n; } If you call this function, it will repeatedly call itself and never return. Your program will eventually crash with a StackOverflow exception

No guarantee of convergence Another common problem is to include within a recursive function a recursive call to solve a sub-problem that is not smaller than the original problem. public static double harmonic(int n) { if (n == 1) { return 1.0; } return harmonic(n) + 1.0/n; } This goes into an infinite recursive loop for any value of its argument (except 1).

Excessive Memory Requirements If a function calls itself recursively an excessive number of times before returning, the memory required by Java to keep track of the recursive calls may be prohibitive. public static double harmonic(int n) { if (n == 0) return 0.0; return harmonic(n-1) + 1.0/n; } This method correctly computes the nth harmonic number However, calling it with a huge value of n will lead to a StackOverflowError

Excessive Computation The temptation to write a simple recursive program to solve a problem must always be tempered by the understanding that a simple program might require exponential time (unnecessarily), due to excessive recomputation. // Warning: spectacularly inefficient. public static long fibonacci(int n) { if (n == 0) return 0; if (n == 1) return 1; return fibonacci(n-1) + fibonacci(n-2); }

Dynamic Programming A general approach to implementing recursive programs. Beyond the scope of cits1001 but here is a taste: The basic idea is to store the answer to each sub-problem and then use the stored answers to solve the original problem. Solving the sub-problem only once avoids exponential blow-up.

Challenge: Recursive trees Write a program that takes a parameter n and produces the recursive patterns above for n equal to 1,2,3,4 and 8 For more challenges, see http://introcs.cs.princeton.edu/java/23recursion/

Summary Recursion can be used to express some complex computations in an elegant way But there are overheads for using recursion that the programmer needs to be aware of