
Recursive Algorithms and Quicksort Implementation
Explore the concept of recursive algorithms and the implementation of Quicksort in Python. Understand the challenges in the initial version and the refinement towards the final version. Learn the general form of a recursive algorithm and its application in problem-solving techniques.
Uploaded on | 0 Views
Download Presentation

Please find below an Image/Link to download the presentation.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author. If you encounter any issues during the download, it is possible that the publisher has removed the file from their server.
You are allowed to download the files provided on this website for personal or commercial use, subject to the condition that they are used lawfully. All files are the property of their respective owners.
The content on the website is provided AS IS for your information and personal use only. It may not be sold, licensed, or shared on other websites without obtaining consent from the author.
E N D
Presentation Transcript
To seal: moisten flap, fold over, and seal Recursion UW CSE 160 1
Three recursive algorithms Sorting GCD (greatest common divisor) Exponentiation Used in cryptography, which protects information and communication 2
Sorting a list Python s sorted function returns a sorted version of a list. sorted([3, 1, 4, 1, 5, 9]) [1, 1, 3, 4, 5, 9] How could you implement sorted? Idea ( quicksort , invented in 1960): Choose an arbitrary element (the pivot ) Collect the smaller items and put them on its left Collect the larger items and put them on its right 3
First version of quicksort (broken) See in python tutor def quicksort(lst): """Return a sorted version of lst.""" pivot = lst[0] smaller = [elt for elt in lst if elt < pivot] larger = [elt for elt in lst if elt > pivot] return smaller + [pivot] + larger print (quicksort([3, 1, 4, 1, 5, 9])) [1, 1, 3, 4, 5, 9] There are three problems with this definition 4
Problems with first version of quicksort 1. The smaller and larger lists aren t sorted 2. Fails if the input list is empty 3. Duplicate elements equal to the pivot are lost 5
Final version of quicksort See in python tutor def quicksort(lst): """Return a sorted version of lst.""" if len(lst) < 2: return lst pivot = lst[0] smaller = [elt for elt in lst if elt < pivot] pivots = [elt for elt in lst if elt == pivot] larger = [elt for elt in lst if elt > pivot] return quicksort(smaller) + pivots + quicksort(larger) 6
General form of a recursive algorithm Determine whether the problem is small or large If the problem is small: Solve the whole thing If the problem is large: Divide the problem, creating one or more smaller problems Ask someone else to solve the smaller problems Recursive call to do most of the work (Maybe) Do a small amount of postprocessing on the result(s) of the recursive call(s) ( base case ) ( recursive case ) 7
Recursion design philosophy Recursion expresses the essence of divide and conquer Solve a smaller subproblem(s), then Use the answer(s) to solve the original problem Passing the buck: I am willing to do a small amount of work, as long as I can offload most of the work to someone else. Wishful thinking: If someone else solves most of the problem, then I will do the rest. 8
Decomposition for recursion List algorithms: Base case: short (or empty) list Recursive case: process all but the first element of the list, or The smaller subproblem is only a tiny bit smaller The postprocessing combines the first element of the list with the recursive result half of the list Often recursively process both halves The postprocessing combines the two recursive results Numeric algorithms: Base case: small number (often 1 or 0) Recursive case: process a smaller value 1 less than the original value half of the original value File system: Base case: single file Recursive case: process a subdirectory Geographical algorithms: Base case: small area Recursive case: smaller part of a map (or other spatial representation) 9
Recursion: base and inductive cases A recursive algorithm always has: a base case (no recursive call) an inductive or recursive case (has a recursive call) solves a smaller problem What happens if you leave out the base case? What happens if you leave out the inductive case? 10
Factorial def fact(num): """ Assumes num is an int > 0, return n!""" if num == 1: return num else: return num * fact(num - 1) print (fact(3)) print (fact(1)) print (fact(2)) 11
Sum List def sum_list(lst): """Returns sum of numbers in list. Returns zero for an empty list.""" if len(lst) == 0: return 0 else: return lst[0] + sum_list(lst[1:]) print (sum_list([1, 3, 6])) 12
Fibonacci def fib(n): """Returns the nth Fibonacci number.""" if n == 0 or n == 1: return 1 else: return fib(n - 1) + fib(n - 2) print (fib(6)) 13
Whats Going On? See in python tutor fib(4) + fib(2) fib(3) fib(1) fib(1) fib(2) + + fib(0) fib(1) fib(0) + return: 1 return: 1 return: 1 return: 1 return: 1 This part last (in stages) This part is calculated first This part second 14
GCD (greatest common divisor) gcd(a, b) = largest integer that divides both a and b gcd(4, 8) = 4 gcd(15, 25) = 5 gcd(16, 35) = 1 How can we compute GCD? 15
Euclids method for computing GCD (circa 300 BC, still commonly used!) a gcd(b, a) if a < b gcd(a-b, b) otherwise if b = 0 gcd(a, b) = 16
Python code for Euclids algorithm def gcd(a, b): """Return the greatest common divisor of a and b.""" if b == 0: return a elif a < b: return gcd(b, a) else: return gcd(a - b, b) 17
Exponentiation Goal: Perform exponentiation, using only addition, subtraction, multiplication, and division. (Example: 34) def exp(base, exponent): """Return baseexponent. Exponent is a non-negative integer.""" if exponent == 0: return 1 else: return base * exp(base, exponent - 1) Example: exp(3, 4) 3 * exp(3, 3) 3 * (3 * exp(3, 2)) 3 * (3 * (3 * exp(3, 1))) 3 * (3 * (3 * (3 * exp(3, 0)))) 3 * (3 * (3 * (3 * 1))) 18
Faster exponentiation Suppose the exponent is even. Then, baseexponent = (base*base)exponent/2 Examples: 34 = 92 92 = 811 512 = 256 256 = 6253 New implementation: def exp(base, exponent): """Return baseexponent. Exponent is a non-negative integer.""" if exponent == 0: return 1 elif exponent % 2 == 0: return exp(base * base, exponent / 2) else: return base * exp(base, exponent - 1) 19
Comparing the two algorithms Original algorithm: 12 multiplications exp(5, 12) 5 * exp(5, 11) 5 * 5 * exp(5, 10) 5 * 5 * 5 * exp(5, 9) 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * exp(5, 0) 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 1 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 25 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 125 244140625 Fast algorithm: 5 multiplications exp(5, 12) (5 * 5)6 exp(25, 6) (25 * 25)3 exp(625, 3) 625 * exp(625, 2) 625 * exp(390625, 1) 625 * 390625 * exp(390625, 0) 625 * 390625 * 1 625 * 390625 244140625 (625 * 625)1 Speed matters: In cryptography, exponentiation is done with 600-digit numbers. 20
Recursion vs. iteration Any recursive algorithm can be re-implemented as a loop instead This is an iterative expression of the algorithm Any loop can be implemented as recursion instead Sometimes recursion is clearer and simpler Mostly for data structures with a recursive structure Sometimes iteration is clearer and simpler 21