compsci 105 s2 2014 principles of computer science · tail recursion ! textbook: ! problem solving...
TRANSCRIPT
COMPSCI 105 S2 2014 Principles of Computer Science
Recursion 1
Agenda } Agenda
} What is recursion? } Recursive solutions: } Examples } The Factorial of N } Box Trace Example } Write a String Backward } Tail Recursion
} Textbook: } Problem Solving with Algorithms and Data Structures } Chapter 4 – Recursion
20 COMPSCI105 3
20 COMPSCI105 4
} GOAL: Design algorithms to solve problems!
} Introducing particular type of algorithm – recursive algorithms
} The rest of this course is about recursive algorithms
Specifying a Programming Problem
20 COMPSCI105 5
} Specify the structure of the input
} Specify the structure of the output
} Specify the relationship between the contents of the two
} Example: } Input – list of numbers } Output – number } Relationship – output number equals sum of numbers in input list
divided by size of input list
20.1 Introduction
Definitions
} Problem Input: } The space consisting of all elements for which the problem is
solved } Examples: An array of integers, all people in this room, the days of
the month, all “All Blacks” rugby games
} Problem Size: } The number of elements of the problem input } Examples: An array with N elements, the number of people in this
room, a list of N cities, the number of games played by the “All Blacks”
} Why do we care about measuring “problem size”?
20 COMPSCI105 6
20.1 Introduction
Iterative algorithm
} Algorithm which solves a problem by applying a function to each element of the problem domain. } Example: Find the tallest person in a group of N>0 students
Student FindTallestStudent(Group_of_students){ TallestStudent = Take any student from group; Repeat until nobody left Take next student from group If student is taller than TallestStudent then TallestStudent = student; Return TallestStudent; }
163 157
155 162
169 TallestStudent
20 COMPSCI105 7
20.1 Introduction Recursion
} Recursion is a powerful problem solving technique where a problem is broken into smaller and smaller identical versions of itself until a version is small enough that it has an obvious solution.
} Note: } Complex problems can have simple recursive solutions } It is an alternative to iteration (involves loops) } BUT: in some languages some recursive solutions are inefficient and
impractical!
P1 P2 …
PN A base case is a special case whose solution is known
20 COMPSCI105 8
20.1 Introduction Recursion
} Recursion involves a function calling itself. } Example: Find the tallest person in a group of N>0 students
FindTallestStudent(Group of students){ If only one student in group return this student else StudentA = Take any student from group StudentB = FindTallestStudent(Remaining Group) return the taller person of StudentA and studentB; }
FindTallestStudent([162,155,169,157])
TallestStudent
FindTallestStudent([155,169,157])
FindTallestStudent([169,157])
FindTallestStudent([157]) 157
155
162 169
169 169
169
Taller
Taller
Taller
20 COMPSCI105 9
20.2 Recursion
Recursive Solutions
} Properties of a recursive solution } A recursive method calls itself } Each recursive call solves an identical, but smaller, problem } A test for the base case enables the recursive calls to stop
} Base case: a known case in a recursive definition
} Eventually, one of the smaller problems must be the base case (problem not allowed to become smaller than base case)
20 COMPSCI105 10
20.2 Recursion
Four Questions } Four questions for constructing recursive solutions
} How can you define the problem in terms of a smaller problem of the same type?
} How does each recursive call diminish the size of the problem? } What instance of the problem can serve as the base case? } As the problem size diminishes, will you reach this base case?
20 COMPSCI105 11
20.3 Examples Example – Calculate the Sum
} Get the sum by taking the first number + the sum of the rest of the list recursive_sum([2,1,5,6])
2 + recursive_sum([1,5,6])
1 + recursive_sum([5,6])
5 + recursive_sum([6])
6 + recursive_sum([]) 0
6
11
12
14
def recursive_sum(num_list): if len(num_list) == 0: return 0 return num_list[0] + recursive_sum(num_list[1:])
20 COMPSCI105 12
Recursive Data Structures
20 COMPSCI105 13
} Just as a function can call itself, a data structure can have itself as part of its definition.
} For example, a list is either: } the empty list } or an element and a list
} The first one (the empty list) plays the part of the base case } The second one plays the part of the recursive case } Recursive data structures are very powerful because they can
recurse indefinitely (e.g., lists, queues, stacks, etc.) } Recursive algorithms are the “natural” way to process
recursive data structures
20.3 Examples
Example – Bad Recursion 1
} Problem: } Compute the sum of all integers from 1 to n
def bad_sum(n): return n + bad_sum(n-1)
No base case!!!
20 COMPSCI105 14
20.3 Examples
Example – Bad Recursion 2
} Problem: } If n is odd compute the sum of all odd integers from 1 to n, if it is
even compute sum of all even integers
def bad_sum2(n): if n == 0: return 0 return n + bad_sum2(n-2)
Base case never reached if n is odd!!
20 COMPSCI105 15
20.4 The Factorial of n
Definition
} Problem } Compute the factorial of an integer n >=0
} An iterative definition of factorial(n) } If n = 0, factorial(0) = 1 } If n > 0, factorial(n) = n * (n-1) * (n-2) * … * 1
} Examples: } 4! = 4 * 3 * 2 * 1 = 24 } 7! = 7 * 6 * 5 * 4 * 3 * 2 * 1 = 5040
def factorial(n): result = 1 for i in range(n, 1, -1): result = result * i return result
20 COMPSCI105 16
20.4 The Factorial of n
The Factorial of n } A recurrence relation
} A mathematical formula that generates the terms in a sequence from previous terms
factorial(n) = n * [(n-1) * (n-2) * … * 1]
= n * factorial(n-1) } A recursive definition of factorial(n)
factorial(n) = 1 if n = 0 n * factorial(n-1) if n > 0
def fact(n): if n <= 0: return 1 return n * fact(n-1)
20 COMPSCI105 17
20.4 The Factorial of n
Four Criteria } fact satisfies the four criteria of a recursive solution
} fact calls itself. } At each recursive call, the integer whose factorial to be
computed is diminished by 1. } The methods handles the factorial 0 differently from all other
factorials, where fact(0) is 1. Thus the base case occurs when n is 0.
} Given that n is non-negative, item 2 of this assures that the computation will always reach the base case.
def fact(n): if n <= 0: return 1 return n * fact(n-1)
20 COMPSCI105 18
20.4 The Factorial of n
Call Tree } A systematic way to trace the actions of a recursive method
} Create a new box for each recursive method call } Describe how return value is computed } Provide link to box (or boxes) for recursive method calls within
the current method call } Each box corresponds to an activation record
} Contains a method’s local environment at the time of and as a result of the call to the method
The local environment contains: Value of argument, local variables, return value, address of
calling method, …etc
20 COMPSCI105 19
20.5 Box Trace
Box Trace Example
} A method’s local environment includes: } The method’s local variables } A copy of the actual value arguments } A return address in the calling routine } The value of the method itself
Fact(3)
20 COMPSCI105 20
20.5 Box Trace
Box Trace on Factorial
n = 3 return ? 3 * fact(2)
fact(3)
1
n = 2 return? 2 * fact(1)
fact(2)
n = 1 return? 1 * fact(0)
fact(1)
n = 0 return? 1
fact(0)
1
2
6
20 COMPSCI105 21
20.6 Writing a String Backward
Definition } Problem
} Given a string of characters, write it in reverse order } Recursive solution
} Each recursive step of the solution diminishes by 1 the length of the string to be written backward
} Base case } Write the empty string backward
} Examples:
print(writeBackward("cat"))
print(writeBackward2("cat"))
tac
tac
20 COMPSCI105 22
20.6 Writing a String Backward
Two approaches
} writeBackward(s)
} writeBackward2(s) if the string s is empty:
Do nothing – base case else: writeBackward2(s minus its first char) write the first char of s
if the string s is empty: Do nothing – base case else: write the last char of s writeBackward(s minus its last char) call method recursively for the
string minus the last character
call method recursively for the string minus the first character
20 COMPSCI105 23
20.6 Writing a String Backward writeBackward(s)
s = “cat”, write t writeBackward("ca")
writeBackward("cat")
s = “ca”, write a writeBackward("c")
writeBackward("ca")
s = “c”, write c writeBackward("")
writeBackward("c")
s = “” return
writeBackward(“")
t
ta
tac
20 COMPSCI105 24
20.6 Writing a String Backward writeBackward2(s)
s = “cat” writeBackward2("at")
writeBackward2("cat")
s = “at” writeBackward2(“t")
writeBackward2("at")
s = “t” writeBackward2("")
writeBackward2("t")
s = “” return
writeBackward2("")
Write a
Write t
“”
Write c
20 COMPSCI105 25
20.7 Tail Recursion Tail Recursion
} Tail Recursion occurs when the last action executed by a recursive method is a recursive call.
} In Python tail recursion can be done more efficiently using iteration. def get_sum(num_list): sum_numbers = 0 for num in num_list: sum_numbers += num return sum_numbers
20 COMPSCI105 26
} def recursive_sum(num_list, init_sum):
} if len(num_list) == 0:
} return init_sum
} new_sum = num_list[0] + init_sum
} return recursive_sum(num_list[1:], new_sum)
Summary
07 COMPSCI105 27
} A recursive algorithm passes the buck repeatedly to the same function
} Recursive algorithms are well-suited for solving problems in domains that exhibit recursive patterns or involve recursive data structures
} Recursive strategies can be used to simplify complex solutions to difficult problems
Exercise } We can determine how many digits a positive integer has by
repeatedly dividing by 10 (without keeping the remainder) until the number is less than 10, consisting of only 1 digit. We add 1 to this value for each time we divided by 10. Here is the recursive algorithm: 1. If n < 10 return 1. 2. Otherwise, return 1 + the number of digits in n/10 (ignoring the
fractional part).
} Implement this recursive algorithm in Python and test it using the values 15, 105, and 15105.
20 COMPSCI105 28