CSE 341 Lecture 5 efficiency issues; tail recursion; print

Slides:



Advertisements
Similar presentations
Types of Recursive Methods
Advertisements

Tail Recursion. Problems with Recursion Recursion is generally favored over iteration in Scheme and many other languages – It’s elegant, minimal, can.
CSE 341 Lecture 16 More Scheme: lists; helpers; let/let*; higher-order functions; lambdas slides created by Marty Stepp
Tail Recursion. Problems with Recursion Recursion is generally favored over iteration in Scheme and many other languages It’s elegant, minimal, can be.
Recursion - see Recursion. RHS – SOC 2 Recursion We know that: –We can define classes –We can define methods on classes –Mehtods can call other methods.
Recursion. Binary search example postponed to end of lecture.
1 CSCD 300 Data Structures Recursion. 2 Proof by Induction Introduction only - topic will be covered in detail in CS 320 Prove: N   i = N ( N + 1.
1 Chapter 18 Recursion Dale/Weems/Headington. 2 Chapter 18 Topics l Meaning of Recursion l Base Case and General Case in Recursive Function Definitions.
CSE 341 Lecture 6 exceptions; higher order functions; map, filter, reduce Ullman 5.2, 5.4 slides created by Marty Stepp
Copyright © 2008 Pearson Education, Inc. Publishing as Pearson Addison-Wesley Starting Out with Java: Early Objects Third Edition by Tony Gaddis Chapter.
CSE 143 Lecture 7 Stacks and Queues reading: Stuart Reges notes on website slides created by Marty Stepp
Tail Recursion. Problems with Recursion Recursion is generally favored over iteration in Scheme and many other languages – It’s elegant, minimal, can.
CSE 143 Lecture 7 Stacks and Queues reading: "Appendix Q" (see course website) slides created by Marty Stepp and Hélène Martin
20-1 Computing Fundamentals with C++ Object-Oriented Programming and Design, 2nd Edition Rick Mercer Franklin, Beedle & Associates, 1999 ISBN
Recursion. Basic problem solving technique is to divide a problem into smaller subproblems These subproblems may also be divided into smaller subproblems.
A Computer Science Tapestry 1 Recursion (Tapestry 10.1, 10.3) l Recursion is an indispensable technique in a programming language ä Allows many complex.
CMSC 2021 Recursion Recursive Definition – one that defines something in terms of itself Recursion – A technique that allows us to break down a problem.
CSE 143 Lecture 5 Stacks and Queues slides created by Marty Stepp
© 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 9: Recursion1 CHAPTER 9 RECURSION. Recursion  Concept of recursion  A recursive: Benefit and Cost  Comparison : Iterative and recursive functions.
Comp 245 Data Structures Recursion. What is Recursion? A problem solving concept which can be used with languages that support the dynamic allocation.
Programming for Engineers in Python Sawa 2015 Lecture 2: Lists and Loops 1.
Computer Science Department Data Structure & Algorithms Lecture 8 Recursion.
Recursion. What is recursion? Rules of recursion Mathematical induction The Fibonacci sequence Summary Outline.
CSE 341 Lecture 4 merge sort; basic efficiency issues Ullman slides created by Marty Stepp
CSC 221: Recursion. Recursion: Definition Function that solves a problem by relying on itself to compute the correct solution for a smaller version of.
Discrete Structure Li Tak Sing( 李德成 ) Lecture 13 1.
CSE 341 Lecture 8 curried functions Ullman 5.5 slides created by Marty Stepp
Program Development and Design Using C++, Third Edition
Stacks and Queues. 2 Abstract Data Types (ADTs) abstract data type (ADT): A specification of a collection of data and the operations that can be performed.
Recursion ● Recursion or Iteration ● A Common Recursive Design Pattern ● Computing factorials ● Searching a filesystem tree ● Faster exponentiation ● Slow.
Recursion.
Recursion.
Chapter Topics Chapter 16 discusses the following main topics:
Class 2 – Recursion on Lists
Lecture 9: introduction to recursion reading: 12.1
Topic 6 Recursion.
Chapter 15 Recursion.
Tail Recursion.
Data Structures and Algorithms
Stacks and Queues.
Chapter 15 Recursion.
PPL Lazy Lists.
Programming for Engineers in Python
Stacks and Queues.
Announcements Final Exam on August 17th Wednesday at 16:00.
Applied Algorithms (Lecture 17) Recursion Fall-23
Algorithm design and Analysis
CSE 341 Lecture 3 let expressions; pattern matching Ullman
Building Java Programs
Announcements Final Exam on August 19th Saturday at 16:00.
Stacks and Queues CLRS, Section 10.1.
Unit 3 Test: Friday.
Stack Frames and Functions
slides created by Marty Stepp and Alyssa Harding
Module 1-10: Recursion.
Announcements Final Exam on December 25th Monday at 16:00.
Java Programming: Chapter 9: Recursion Second Edition
Madhusudan Parthasarathy
CSE 341 Lecture 7 anonymous functions; composition of functions Ullman 5.1.3, 5.6 slides created by Marty Stepp
Yan Shi CS/SE 2630 Lecture Notes
slides created by Marty Stepp
Dr. Sampath Jayarathna Cal Poly Pomona
CSE 341 Lecture 11 b closures; scoping rules
Recursive Algorithms 1 Building a Ruler: drawRuler()
CSE 341 Lecture 2 lists and tuples; more functions; mutable state
Lecture 20 – Practice Exercises 4
Types of Recursive Methods
Recursion Examples.
Presentation transcript:

CSE 341 Lecture 5 efficiency issues; tail recursion; print Ullman 3.3 - 3.4; 4.1 slides created by Marty Stepp http://www.cs.washington.edu/341/

Efficiency exercise Write a function called reverse that accepts a list and produces the same elements in the opposite order. reverse([6, 2, 9, 7]) produces [7,9,2,6] Write a function called range that accepts a maximum integer value n and produces the list [1, 2, 3, ..., n-1, n]. Produce an empty list for all numbers less than 1. Example: range(5) produces [1,2,3,4,5]

Flawed solutions These solutions are correct; but they have a problem... fun reverse([]) = [] | reverse(first :: rest) = reverse(rest) @ [first]; fun range(0) = [] | range(n) = range(n - 1) @ [n];

Efficiency of the @ operator val x = [2, 4, 7]; val y = [5, 3]; val a = 9 :: x; val z = x @ y; The :: operator is fast: O(1) simply creates a link from the first element to front of right The @ operator is slow: O(n) must walk/copy the left list and then append the right one using @ in a recursive function n times : function is O(n2) 2 x 4 7 9 a 5 y 3 2 z 4 7

Flawed solution in action fun reverse([]) = [] | reverse(first :: rest) = reverse(rest) @ [first]; reverse([2, 4, 7, 6]); 6 7 4 @ 2 first rest 4 7 6 @ 6 7 4 first rest 7 6 @ 6 7 first rest 6 [] @ rest [] 6 first

Fixing inefficient reverse How can we improve the inefficient reverse code? fun reverse([]) = [] | reverse(first :: rest) = reverse(rest) @ [first]; Hint: Replace @ with :: as much as possible. :: adds to the front of a list. How can we perform a reversal by repeatedly adding to the front of a list? (Think iteratively...)

Better reverse solution fun reverse([]) = [] | reverse(L) let (* lst accumulates reversed values *) fun helper(lst, []) = lst | helper(lst, first::rest) = helper(first::lst, rest) in helper([], L) end; The parameter lst here serves as an accumulator.

Fixing inefficient range How can we improve the inefficient range code? fun range(0) = [] | range(n) = range(n - 1) @ [n]; Hint: Replace @ with :: as much as possible. Hint: We can't build the list from front to back the way it's currently written, because n (the max of the range) is the only value we have available. Hint: Consider a helper function that can build a range in order from smallest to largest value.

Better range solution The parameter lst here serves as an accumulator. fun range(n) = let fun helper(lst, i) = if i = 0 then lst else helper(i :: lst, i - 1) in helper([], n) end; The parameter lst here serves as an accumulator.

Times-two function Consider the following function: (* Multiplies n by 2; a silly function. *) fun timesTwo(0) = 0 | timesTwo(n) = 2 + timesTwo(n - 1); Run the function for large values of n. Q: Why is it so slow? A: Each call must wait for the results of all the other calls to return before it can add 2 and return its own result.

Tail recursion tail recursion: When the end result of a recursive function can be expressed entirely as one recursive call. Tail recursion is good . A smart functional language can detect and optimize it. If a call f(x) makes a recursive call f(y), as its last action, the interpreter can discard f(x) from the stack and just jump to f(y). Essentially a way to implement iteration recursively.

Times-two function revisited This code is not tail recursive because of 2 + (* Multiplies n by 2; a silly function. *) fun timesTwo(0) = 0 | timesTwo(n) = 2 + timesTwo(n - 1); Exercise: Make the code faster using an accumulator. accumulator: An extra parameter that stores a partial result in progress, to facilitate tail recursion.

Iterative times-two in Java // Multiplies n by 2; a silly function. public static int timesTwo(int n) { int sum = 0; for (int i = 1; i <= n; i++) { sum = sum + 2; } return sum;

Iterative times-two in Java, v2 // Multiplies n by 2; a silly function. public static int timesTwo(int n) { int sum = 0; while (n > 0) { sum = sum + 2; n = n - 1; } return sum;

Tail recursive times-two in ML (* Multiplies n by 2; a silly function. *) fun timesTwo(n) = let help(sum, 0) = sum | help(sum, k) = help(sum + 2, k - 1) in help(0, n) end; Accumulator variable sum grows as n (k) shrinks.

Efficiency and Fibonacci The fibonacci function we wrote previously is also inefficient, for a different reason. It makes an exponential number of recursive calls! Example: fibonacci(5) fibonacci(4) fibonacci(3) fibonacci(2) fibonacci(1) How can we fix it to make fewer (O(n)) calls?

Iterative Fibonacci in Java // Returns the nth Fibonacci number. // Precondition: n >= 1 public static int fibonacci(int n) { if (n == 1 || n == 2) { return 1; } int curr = 1; // the 2 most recent Fibonacci numbers int prev = 1; // k stores what fib number we are on now for (int k = 2; k < n; k++) { int next = curr + prev; // advance to next prev = curr; // Fibonacci number curr = next; return curr;

Efficient Fibonacci in ML (* Returns the nth Fibonacci number. Precondition: n >= 1 *) fun fib(1) = 1 | fib(2) = 1 | fib(n) = let fun helper(k, prev, curr) = if k = n then curr else helper(k + 1, curr, prev + curr) in helper(2, 1, 1) end;

The print function (4.1) print(string); The type of print is fn : string -> unit unit is a type whose sole value is () (like void in Java) unlike most ML functions, print has a side effect (output) print accepts only a string as its argument can convert other types to string: Int.toString(int), Real.toString(real), Bool.toString(bool), str(char), etc.

(expression; expression; expression) "Statement" lists (expression; expression; expression) evaluates a sequence of expressions; a bit like {} in Java the above is itself an expression its result is the value of the last expression might seem similar to a let-expression... but a let modifies the ML environment (defines symbols); a "statement" list simply evaluates expressions, each of which might have side effects

Using print - fun printList([]) = () = | printList(first::rest) = ( print(first ^ "\n); printList(rest) ); val printList = fn : string list -> unit - printList(["a", "b", "c"]); a b c val it = () : unit

print for debugging Useful pattern for debugging: (* Computes n!; not tail recursive. *) fun factorial(0) = 0 | factorial(n) = ( print("n is " ^ str(n)); n * factorial(n - 1) ); Useful pattern for debugging: ( print(whatever); your original code )