Lecture 10: Recursion vs Iteration

Similar documents
Standard Version of Starting Out with C++, 4th Edition. Chapter 19 Recursion. Copyright 2003 Scott/Jones Publishing

Two Approaches to Algorithms An Example (1) Iteration (2) Recursion

CS 310 Advanced Data Structures and Algorithms

Recursion Chapter 8. What is recursion? How can a function call itself? How can a function call itself?

Unit #3: Recursion, Induction, and Loop Invariants

Recursion Chapter 3.5

Identify recursive algorithms Write simple recursive algorithms Understand recursive function calling

Recursion Chapter 8. What is recursion? How can a function call itself? How can a function call itself? contains a reference to itself.

APCS-AB: Java. Recursion in Java December 12, week14 1

Recursion & Performance. Recursion. Recursion. Recursion. Where Recursion Shines. Breaking a Problem Down

What is recursion? Recursion. How can a function call itself? Recursive message() modified. Week 10. contains a reference to itself.

Algorithm Analysis. (Algorithm Analysis ) Data Structures and Programming Spring / 48

COE428 Lecture Notes Week 1 (Week of January 9, 2017)

Recursive Definitions

Recursive Functions. Biostatistics 615 Lecture 5

An Elegant Weapon for a More Civilized Age

Recursion. What is Recursion? Simple Example. Repeatedly Reduce the Problem Into Smaller Problems to Solve the Big Problem

Recursion Chapter 4 Self-Reference. Recursive Definitions Inductive Proofs Implementing Recursion

11. Recursion. n (n 1)!, otherwise. Mathematical Recursion. Recursion in Java: Infinite Recursion. 1, if n 1. n! =

12. Recursion. n (n 1)!, otherwise. Educational Objectives. Mathematical Recursion. Recursion in Java: 1, if n 1. n! =

Unit #2: Recursion, Induction, and Loop Invariants

What is recursion? Recursion. Recursive message() modified. How can a function call itself? contains a reference to itself. Week 10. Gaddis:

CS 206 Introduction to Computer Science II

Reading 8 : Recursion

What is recursion? Recursion. How can a function call itself? Recursive message() modified. Week 10. contains a reference to itself. Gaddis:

CS 3410 Ch 7 Recursion

Recursion. Recursion in C

Wentworth Institute of Technology COMP1050 Computer Science II Spring 2017 Derbinsky. Recursion. Lecture 13. Recursion

Chapter 15: Recursion

Recursion(int day){return Recursion(day += 1);} Comp Sci 1575 Data Structures. Recursive design. Convert loops to recursion

Recall from Last Time: Big-Oh Notation

Recursive Methods and Problem Solving. Chris Kiekintveld CS 2401 (Fall 2010) Elementary Data Structures and Algorithms

Functions. CS10001: Programming & Data Structures. Sudeshna Sarkar Professor, Dept. of Computer Sc. & Engg., Indian Institute of Technology Kharagpur

Reduction & Recursion Overview

Module 05: Types of recursion

Chapter 12 Supplement: Recursion with Java 1.5. Mr. Dave Clausen La Cañada High School

11/2/2017 RECURSION. Chapter 5. Recursive Thinking. Section 5.1

SOFTWARE DEVELOPMENT 1. Recursion 2018W A. Ferscha (Institute of Pervasive Computing, JKU Linz)

recursive algorithms 1

1.7 Recursion. Department of CSE

Recursion. Lars-Henrik Eriksson. Functional Programming 1. Based on a presentation by Tjark Weber and notes by Sven-Olof Nyström

COMPSCI 230 Discrete Math Prime Numbers January 24, / 15

CSC Design and Analysis of Algorithms. Lecture 5. Decrease and Conquer Algorithm Design Technique. Decrease-and-Conquer

Programming Language Pragmatics

OVERVIEW. Recursion is an algorithmic technique where a function calls itself directly or indirectly. Why learn recursion?

Recursion CSCI 136: Fundamentals of Computer Science II Keith Vertanen Copyright 2011

Object-Oriented Programming and Design D0010E. Interactive lecture 2. Overview of the lecture. Writing larger classes Documentation Recursion

CS 506, Sect 002 Homework 5 Dr. David Nassimi Foundations of CS Due: Week 11, Mon. Apr. 7 Spring 2014

Types of recursion. Structural vs. general recursion. Pure structural recursion. Readings: none. In this module: learn to use accumulative recursion

! Addition! Multiplication! Bigger Example - RSA cryptography

Lecture 6: Recursion RECURSION

What is recursion? Recursion. How can a function call itself? Recursive message() modified. contains a reference to itself. Week 7. Gaddis:

Recursion. Overview. Mathematical induction. Hello recursion. Recursion. Example applications. Goal: Compute factorial N! = 1 * 2 * 3...

Anatomy of a static method, S&W, 2.1, figure page 188. Class.name or just name Scope, S&W, 2.1, figure page 189. Overloading

Recursion. Fundamentals of Computer Science

Data Structures And Algorithms

Recursion. ! When the initial copy finishes executing, it returns to the part of the program that made the initial call to the function.

Types of recursion. Readings: none. In this module: a glimpse of non-structural recursion. CS 135 Winter : Types of recursion 1

Conditionals !

2.3 Recursion. Overview. Mathematical Induction. What is recursion? When one function calls itself directly or indirectly.

CS 101: Computer Programming and Utilization

Introduction to Object-Oriented Programming

COMP-202: Foundations of Programming. Lecture 13: Recursion Sandeep Manjanna, Summer 2015

CMPSCI 250: Introduction to Computation. Lecture #14: Induction and Recursion (Still More Induction) David Mix Barrington 14 March 2013

CS 173, Running Time Analysis, Counting, and Dynamic Programming. Tandy Warnow

Recursion. Chapter 5

CS302 Topic: Algorithm Analysis #2. Thursday, Sept. 21, 2006

Recursion. CSE 2320 Algorithms and Data Structures University of Texas at Arlington

UNIT 5A Recursion: Basics. Recursion

Recursion CS GMU

CPSC 221: Algorithms and Data Structures Lecture #1: Stacks and Queues

CMSC 132: Object-Oriented Programming II. Recursive Algorithms. Department of Computer Science University of Maryland, College Park

Lecture 15: Iteration and Recursion

Algorithms: Efficiency, Analysis, techniques for solving problems using computer approach or methodology but not programming

14. Pointers, Algorithms, Iterators and Containers II

UNIT 5A Recursion: Basics. Recursion

Module 1: Asymptotic Time Complexity and Intro to Abstract Data Types

CS103L SPRING 2017 UNIT 8: RECURSION

CS116 - Module 5 - Accumulative Recursion

CSC236H Lecture 5. October 17, 2018

Algorithmics. Some information. Programming details: Ruby desuka?

Lecture 7 CS2110 Fall 2014 RECURSION

Attributes of Variable. Lecture 13: Run-Time Storage Management. Lifetime. Value & Location

CS/COE 1501 cs.pitt.edu/~bill/1501/ More Math

Lecture 6 CS2110 Spring 2013 RECURSION

I2204 ImperativeProgramming Semester: 1 Academic Year: 2018/2019 Credits: 5 Dr Antoun Yaacoub

CSCI-1200 Data Structures Spring 2018 Lecture 7 Order Notation & Basic Recursion

Recursion. Tjark Weber. Functional Programming 1. Based on notes by Sven-Olof Nyström. Tjark Weber (UU) Recursion 1 / 37

The divide and conquer strategy has three basic parts. For a given problem of size n,

CSI33 Data Structures

Discussion on Writing of Recursive Algorithm

15. Pointers, Algorithms, Iterators and Containers II

Sorting. Popular algorithms: Many algorithms for sorting in parallel also exist.

Overview. What is recursion? When one function calls itself directly or indirectly.

Outline. Simple Recursive Examples Analyzing Recursion Sorting The Tower of Hanoi Divide-and-conquer Approach In-Class Work. 1 Chapter 6: Recursion

34. Recursion. Java. Summer 2008 Instructor: Dr. Masoud Yaghini

Comp215: More Recursion

Cilk, Matrix Multiplication, and Sorting

This session. Recursion. Planning the development. Software development. COM1022 Functional Programming and Reasoning

Recursion. February 02, 2018 Cinda Heeren / Geoffrey Tien 1

Transcription:

cs2010: algorithms and data structures Lecture 10: Recursion vs Iteration Vasileios Koutavas School of Computer Science and Statistics Trinity College Dublin

how methods execute Call stack: is a stack maintained by the Java runtime system One call stack frame (aka activation record) for each running instance of a method: contains all information necessary to execute the method - references to parameter values and local objects, return address etc. Objects themselves are stored in another part of memory: the heap every time a method is called, a new stack frame is pushed on the call stack. every time a method returns, the top-most stack frame is popped. helpmethod... mymethod param1 =... param2 =...... main argv = [...]... 1

recursion Recursion: when something is defined in terms of itself. Infinite Recusion Well-founded Recursion 2

recursion Principle: A method is recursive when its definition calls the method itself. A correct recursive method should be well-founded: it should terminate/must end up at a base case. Classic example: factorial in math written as: n! Math definition: 0! = 1 n! = n (n 1)! when n > 0 3

recursion Principle: A method is recursive when its definition calls the method itself. A correct recursive method should be well-founded: it should terminate/must end up at a base case. Classic example: factorial in math written as: n! Math definition: 0! = 1 n! = n (n 1)! when n > 0 Classic example: Fibonacci numbers Math definition: fib(0) = 1 fib(1) = 1 fin(n) = fib(n 1) + fib(n 2) when n > 1 3

recursion Principle: A method is recursive when its definition calls the method itself. A correct recursive method should be well-founded: it should terminate/must end up at a base case. Classic example: factorial in math written as: n! Math definition: 0! = 1 n! = n (n 1)! when n > 0 Classic example: Fibonacci numbers Math definition: fib(0) = 1 fib(1) = 1 fin(n) = fib(n 1) + fib(n 2) when n > 1 It is convenient to implement recursive math definitions using recursive methods. 3

implementation of factorial Recursive implementation: int fac(int n) { 4

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); 5

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Closely matches the mathematical definition. 5

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Closely matches the mathematical definition. follows the divide and conquer approach: 5

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Closely matches the mathematical definition. follows the divide and conquer approach: break the implementation of fac(n) into smaller and smaller parts: fac(n-1) 5

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Closely matches the mathematical definition. follows the divide and conquer approach: break the implementation of fac(n) into smaller and smaller parts: fac(n-1) only deal with the smallest possible cases (here when n = 0): the base cases 5

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Closely matches the mathematical definition. follows the divide and conquer approach: break the implementation of fac(n) into smaller and smaller parts: fac(n-1) only deal with the smallest possible cases (here when n = 0): the base cases the rest of the cases are the recursive cases (here when n > 0) 5

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Closely matches the mathematical definition. follows the divide and conquer approach: break the implementation of fac(n) into smaller and smaller parts: fac(n-1) only deal with the smallest possible cases (here when n = 0): the base cases the rest of the cases are the recursive cases (here when n > 0) specify how smaller solutions compose into the solutions of recursive cases 5

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Closely matches the mathematical definition. follows the divide and conquer approach: break the implementation of fac(n) into smaller and smaller parts: fac(n-1) only deal with the smallest possible cases (here when n = 0): the base cases the rest of the cases are the recursive cases (here when n > 0) specify how smaller solutions compose into the solutions of recursive cases it is usually a top-down calculation 5

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Q: asymptotic worst-case running time? (# recursive calls * cost of each call) 6

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Q: asymptotic worst-case running time? A: Θ(n) time (# recursive calls * cost of each call) 6

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Q: asymptotic worst-case running time? A: Θ(n) time Q: memory space for call stack frames? (# recursive calls * cost of each call) (max # frames on call stack) 6

implementation of factorial Recursive implementation: int fac(int n) { if (n == 0) return 1; else return n * fac(n-1); Q: asymptotic worst-case running time? A: Θ(n) time (# recursive calls * cost of each call) Q: memory space for call stack frames? (max # frames on call stack) A: Θ(n) space All this call stack space is needed because of the return n * fac(0) return 1 *. fac(n-2) return (n-2) * fac(n) fac(n-1) return n * return (n-1) * return n * return (n-1) * return n * return n*(n-1)*(n-2)* *1*1 start largest stack end time 6

implementation of factorial Recursive implementation using accumulator: (H/W: can you implement the accumulator version bottom-up?) int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); 7

implementation of factorial Recursive implementation using accumulator: (H/W: can you implement the accumulator version bottom-up?) int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); Q: asymptotic worst-case running time? 7

implementation of factorial Recursive implementation using accumulator: (H/W: can you implement the accumulator version bottom-up?) int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); Q: asymptotic worst-case running time? Θ(n) 7

implementation of factorial Recursive implementation using accumulator: (H/W: can you implement the accumulator version bottom-up?) int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); Q: asymptotic worst-case running time? Q: memory space for call stack frames? Θ(n) 7

implementation of factorial Recursive implementation using accumulator: (H/W: can you implement the accumulator version bottom-up?) int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); Q: asymptotic worst-case running time? Q: memory space for call stack frames? Θ(n) In Java Θ(n) for stack space In other, mainly functional, languages (ML, Lisp, Haskell, ) the compiler runs this using Θ(1) stack space. Only the top-most stack frame is necessary because every function call simply returns the inner result: return facacc(n-1, acc * n) This is called tail recursion 7

implementation of factorial Recursive implementation using accumulator: (H/W: can you implement the accumulator version bottom-up?) int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); Q: asymptotic worst-case running time? Q: memory space for call stack frames? Θ(n) In Java Θ(n) for stack space In other, mainly functional, languages (ML, Lisp, Haskell, ) the compiler runs this using Θ(1) stack space. Only the top-most stack frame is necessary because every function call simply returns the inner result: return facacc(n-1, acc * n) This is called tail recursion fac(n) facacc(n, 1) return facacc(n-1, n) return facacc(n-2, n*(n-1)) return facacc(0, n*(n-1)* *1) return start end 7

implementation of factorial From tail recursive implementation iterative implementation: int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); int fac(int n) { int acc = 1; for ( ;!(n == 0); n--) { acc = acc * n; return acc; 8

implementation of factorial From tail recursive implementation iterative implementation: int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); Running time of iterative implementation: int fac(int n) { int acc = 1; for ( ;!(n == 0); n--) { Θ(n) acc = acc * n; return acc; 8

implementation of factorial From tail recursive implementation iterative implementation: int fac(int n) { return facacc(n, 1); int facacc(int n, int acc) { if (n == 0) return acc; else return facacc(n-1, acc * n); Running time of iterative implementation: Stack space of iterative implementation: int fac(int n) { int acc = 1; for ( ;!(n == 0); n--) { Θ(n) Θ(1) acc = acc * n; return acc; In functional languages this simple translation is done by the compiler! 8

fibonacci numbers Math definition: fib(0) = 1 fib(1) = 1 fin(n) = fib(n 1) + fib(n 2) when n > 1 Recursive implementation: 9

fibonacci numbers Math definition: fib(0) = 1 fib(1) = 1 fin(n) = fib(n 1) + fib(n 2) when n > 1 Recursive implementation: int fib(int n) { if (n <= 1) return 1; else return fib(n-1) + fib(n-2); 9

fibonacci numbers Math definition: fib(0) = 1 fib(1) = 1 fin(n) = fib(n 1) + fib(n 2) when n > 1 Recursive implementation: int fib(int n) { if (n <= 1) return 1; else return fib(n-1) + fib(n-2); Running time: non-tight upper bound: O(2 n ) tight bound: Θ(fib(n)) # of recursive calls of fib(n) is the size of the binary tree of recursive calls with n levels ( 2 n ); however this is not a complete tree; thus O(2 n ). 9

fibonacci numbers Math definition: fib(0) = 1 fib(1) = 1 fin(n) = fib(n 1) + fib(n 2) when n > 1 Recursive implementation: int fib(int n) { if (n <= 1) return 1; else return fib(n-1) + fib(n-2); Running time: non-tight upper bound: O(2 n ) tight bound: Θ(fib(n)) # of recursive calls of fib(n) is the size of the binary tree of recursive calls with n levels ( 2 n ); however this is not a complete tree; thus O(2 n ). Call stack space: Θ(n) 9

fibonacci numbers Math definition: fib(0) = 1 fib(1) = 1 fin(n) = fib(n 1) + fib(n 2) when n > 1 Recursive implementation with accumulator (tail recursion): int fib(int n) { return fibacc(n, 1, 1); int fibacc(int n, int last, int secondtolast) { if (n <= 1) return last; else return fibacc(n-1, last + secondtolast, last); This is much trickier! Read it again off-line and understand why it works. It is a bottom-up calculation using two accumulators. 10

fibonacci numbers Math definition: fib(0) = 1 fib(1) = 1 fin(n) = fib(n 1) + fib(n 2) when n > 1 Recursive implementation with accumulator (tail recursion): int fib(int n) { return fibacc(n, 1, 1); int fibacc(int n, int last, int secondtolast) { if (n <= 1) return last; else return fibacc(n-1, last + secondtolast, last); This is much trickier! Read it again off-line and understand why it works. It is a bottom-up calculation using two accumulators. Running time: Θ(n) Call stack space: Θ(n) in Java and Θ(1) in other languages. 10

fibonacci numbers Tail-recursive implementation iterative implementation int fib(int n) { return fibacc(n, 1, 1); int fibacc(int n, int last, int secondtolast) { if (n <= 1) return last; else return fibacc(n-1, last + secondtolast, last); int fib(int n) { int last = 1; int secondtolast = 1; for ( ;!(n <= 1); n--) { int tmplast = last; last = last + secondtolast; secondtolast = tmplast; return last; Worst Case Asymptotic Running time: Call stack space: Θ(1) Θ(n) 11

greatest common divisor (gcd) gcd(x,y) is the largest number n such that x%n = y%n = 0. For simplicity assume x y. 12

greatest common divisor (gcd) gcd(x,y) is the largest number n such that x%n = y%n = 0. For simplicity assume x y. Attempt 1: try all numbers n from +inf down to 1 until you find one that has the above property. 12

greatest common divisor (gcd) gcd(x,y) is the largest number n such that x%n = y%n = 0. For simplicity assume x y. Attempt 1: try all numbers n from +inf down to 1 until you find one that has the above property. Attempt 2: try all numbers n from x down to 1 until you find one that has the above property (because gcd will necessarily be min(x, y)). 12

greatest common divisor (gcd) gcd(x,y) is the largest number n such that x%n = y%n = 0. For simplicity assume x y. Attempt 3: Euclid s algorithm a Divide & Conquer approach: Euclid s Theorem: gcd(x,y) = gcd(y, x % y). The base case here is gcd(x,0) = x (why is this the base case?). Q: How many iterations in the worst case? 13

greatest common divisor (gcd) gcd(x,y) is the largest number n such that x%n = y%n = 0. For simplicity assume x y. Attempt 3: Euclid s algorithm a Divide & Conquer approach: Euclid s Theorem: gcd(x,y) = gcd(y, x % y). The base case here is gcd(x,0) = x (why is this the base case?). Q: How many iterations in the worst case? Gabriel Lame s Theorem (1844): #iterations < 5 h Where h = digits of min(x, y) (here this is x) in base 10. A: O(lg(x)) 13

recursion vs iteration: which one to choose? 14

recursion vs iteration: which one to choose? It depends on the benefits vs the drawbacks each implementation gives us in each case. 14

recursion vs iteration: which one to choose? It depends on the benefits vs the drawbacks each implementation gives us in each case. Recursive algorithms usually have easier proofs of correctness (Divide and Conquer is more obvious and similar to mathematical induction) 14

recursion vs iteration: which one to choose? It depends on the benefits vs the drawbacks each implementation gives us in each case. Recursive algorithms usually have easier proofs of correctness (Divide and Conquer is more obvious and similar to mathematical induction) Iterative algorithms usually have easier proofs of memory usage (and in Java use less memory) 14

recursion vs iteration: which one to choose? It depends on the benefits vs the drawbacks each implementation gives us in each case. Recursive algorithms usually have easier proofs of correctness (Divide and Conquer is more obvious and similar to mathematical induction) Iterative algorithms usually have easier proofs of memory usage (and in Java use less memory) Recursive algorithms are sometimes easier to implement when we have complex data structures. because the compiler maintains a stack of previous calls for us. We will use recursive implementations for most operations over trees. 14

recursion vs iteration: which one to choose? It depends on the benefits vs the drawbacks each implementation gives us in each case. Recursive algorithms usually have easier proofs of correctness (Divide and Conquer is more obvious and similar to mathematical induction) Iterative algorithms usually have easier proofs of memory usage (and in Java use less memory) Recursive algorithms are sometimes easier to implement when we have complex data structures. because the compiler maintains a stack of previous calls for us. We will use recursive implementations for most operations over trees. We could have used recursive implementations for operations over lists & arrays but: they are not simpler than the iterative implementations Java will need O(n) call stack space to execute them. 14

homework (optional) Homework 1: Implement Euclid s algorithm using A recursive method. An iterative method. Homework 2: give recursive implementations for: binary search over an array linear search over a linked list Homework 3: Implement search on a Binary Search Tree (next lecture) using recursion and compare with the iterative version in the book. Homework 4**: give an iterative implementation for method put on binary search tree. 15