Presentation is loading. Please wait.

Presentation is loading. Please wait.

Recursion Review Spring 2019 CS 1110

Similar presentations


Presentation on theme: "Recursion Review Spring 2019 CS 1110"— Presentation transcript:

1 Recursion Review Spring 2019 CS 1110

2 Before you Begin Plan out how you will approach the task before writing code Consider the following: How can you “divide and conquer” the task? Do you understand the spec? How would you describe the implementation of the function using words? Recursion Review

3 Steps to Recursion Base case Recursive case
Ensure the recursive case makes progress towards the base case Recursion Review

4 Base Case Create cases to handle smallest units of data
Ideal base cases depend on what type of data is being handled and what the function must do on that data Recursion Review

5 Recursive Case Divide and conquer: how to divide the input so that we can call the function recursively on smaller input When calling the function recursively, assume that it works exactly as the specification states it does -- don’t worry about the specifics of your implementation here Use this recursive call to handle the rest of the data, besides the small unit being handled Recursion Review

6 Make Progress Recursive calls must always make some sort of “progress” towards the base cases This is the only way to ensure the function terminates properly Risk having infinite recursion otherwise Recursion Review

7 Example def count_vowels(s):
"""Returns: The number of vowels (defined here as “a”, “e”, “i”, “o”, “u”) in the string s. Precondition: s is a string""" What should the base case be? Recursion Review

8 Example def count_vowels(s):
"""Returns: The number of vowels (defined here as “a”, “e”, “i”, “o”, “u”) in the string s. Precondition: s is a string""" if len(s) == 0: #Base case return 0 The simplest unit of a string? The empty string; cannot contain any vowels by definition Recursion Review

9 Example def count_vowels(s):
"""Returns: The number of vowels (defined here as “a”, “e”, “i”, “o”, “u”) in the string s. Precondition: s is a string""" if len(s) == 0: #Base case return 0 #Divide and conquer #Divide the list into the first element s[0], and the rest s[1:] For nonempty strings, evaluate the small unit of data; either 1 or 0 in this case Recursion Review

10 Example def count_vowels(s):
"""Returns: The number of vowels (defined here as “a”, “e”, “i”, “o”, “u”) in the string s. Precondition: s is a string""" if len(s) == 0: #Base case return 0 #Divide and conquer #Divide the string into the first element s[0], and the rest s[1:] #s[0] -> check if it is a vowel #s[1:] -> recursive call that returns the number of vowels in the rest of the string #Finally, put it back together When you are writing code, it helps to write pseudocode first. Recursion Review

11 Example def count_vowels(s):
"""Returns: The number of vowels (defined here as “a”, “e”, “i”, “o”, “u”) in the string s. Precondition: s is a string""" if len(s) == 0: #Base case return 0 #Recursive Case with divide and conquer #divide into s[0] and s[1:] if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): # `left` stores number vowels in s[0] left = 1 else: left = 0 we divide the string into s[0] and s[1:] and compute the number of vowels on each Recursion Review

12 Example def count_vowels(s):
"""Returns: The number of vowels (defined here as “a”, “e”, “i”, “o”, “u”) in the string s. Precondition: s is a string""" if len(s) == 0: #Base case return 0 #Recursive Case with divide and conquer #divide into s[0] and s[1:] if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): # `left` stores number vowels in s[0] left = 1 else: left = 0 right = count_vowels(s[1:]) #`right` stores number vowels in s[1:] Now, recursively process the rest of the string When writing recursive functions, you can call the function recursively, assuming that it will function properly How does this make progress towards base case? Well, every time count_vowels recursively called the argument passed is 1 character shorter (due to the slice) Recursion Review

13 Example def count_vowels(s):
"""Returns: The number of vowels (defined here as “a”, “e”, “i”, “o”, “u”) in the string s. Precondition: s is a string""" if len(s) == 0: #Base case return 0 #Recursive Case with divide and conquer #divide into s[0] and s[1:] if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): # `left` stores number vowels in s[0] left = 1 else: left = 0 right = count_vowels(s[1:]) #`right` stores number vowels in s[1:] return left + right #Putting it back together Now, recursively process the rest of the string When writing recursive functions, you can call the function recursively, assuming that it will function properly How does this make progress towards base case? Well, every time count_vowels recursively called the argument passed is 1 character shorter (due to the slice) Recursion Review

14 Visualization def count_vowels(s):
‘efo’ left 1 s 1, 3, 4, 7 def count_vowels(s): """Returns: The number of vowels in the string s. Precondition: s is a string""" if len(s) == 0: return 0 if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): left = 1 else: left = 0 right = count_vowels(s[1:]) return left + right Call: count_vowels(‘efo’) Recursion Review

15 Visualization def count_vowels(s):
‘efo’ left 1 s 1, 3, 4, 7 def count_vowels(s): """Returns: The number of vowels in the string s. Precondition: s is a string""" if len(s) == 0: return 0 if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): left = 1 else: left = 0 right = count_vowels(s[1:]) return left + right count_vowels ‘fo’ left s 1, 3, 5, 6, 7 Call: count_vowels(‘efo’) Recursion Review

16 Visualization def count_vowels(s):
‘efo’ left 1 s 1, 3, 4, 7 def count_vowels(s): """Returns: The number of vowels in the string s. Precondition: s is a string""" if len(s) == 0: return 0 if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): left = 1 else: left = 0 right = count_vowels(s[1:]) return left + right count_vowels ‘fo’ left s 1, 3, 5, 6, 7 count_vowels ‘o’ left 1 s 1, 3, 4, 7 Call: count_vowels(‘efo’) Recursion Review

17 Visualization def count_vowels(s):
‘efo’ left 1 s 1, 3, 4, 7 def count_vowels(s): """Returns: The number of vowels in the string s. Precondition: s is a string""" if len(s) == 0: return 0 if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): left = 1 else: left = 0 right = count_vowels(s[1:]) return left + right count_vowels ‘fo’ left s 1, 3, 5, 6, 7 count_vowels ‘o’ left 1 s 1, 3, 4, 7 count_vowels ‘’ s 1,2 RETURN Call: count_vowels(‘efo’) Recursion Review

18 Visualization def count_vowels(s):
‘efo’ left 1 s 1, 3, 4, 7 def count_vowels(s): """Returns: The number of vowels in the string s. Precondition: s is a string""" if len(s) == 0: return 0 if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): left = 1 else: left = 0 right = count_vowels(s[1:]) return left + right count_vowels ‘fo’ left s 1, 3, 5, 6, 7 count_vowels ‘o’ left 1 s right 1, 3, 4, 7, 8 RETURN count_vowels ‘’ s 1,2 RETURN Call: count_vowels(‘efo’) Recursion Review

19 Visualization def count_vowels(s):
‘efo’ left 1 s 1, 3, 4, 7 def count_vowels(s): """Returns: The number of vowels in the string s. Precondition: s is a string""" if len(s) == 0: return 0 if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): left = 1 else: left = 0 right = count_vowels(s[1:]) return left + right count_vowels ‘fo’ left s right 1 1, 3, 5, 6, 7, 8 RETURN count_vowels ‘o’ left 1 s right 1, 3, 4, 7, 8 RETURN Call: count_vowels(‘efo’) Recursion Review

20 Visualization def count_vowels(s):
‘efo’ left 1 s right 1, 3, 4, 7, 8 2 RETURN def count_vowels(s): """Returns: The number of vowels in the string s. Precondition: s is a string""" if len(s) == 0: return 0 if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): left = 1 else: left = 0 right = count_vowels(s[1:]) return left + right count_vowels ‘fo’ left s right 1 1, 3, 5, 6, 7, 8 RETURN Call: count_vowels(‘efo’) Recursion Review

21 Visualization def count_vowels(s):
‘efo’ left 1 s right 1, 3, 4, 7, 8 2 RETURN def count_vowels(s): """Returns: The number of vowels in the string s. Precondition: s is a string""" if len(s) == 0: return 0 if(s[0] in [‘a’, ‘e’, ‘i’, ‘o’, ‘u’]): left = 1 else: left = 0 right = count_vowels(s[1:]) return left + right Call: count_vowels(‘efo’) Recursion Review

22 Practice Worksheet Pair up with a neighbor and work
on the practice problems! Raise your hand if you have any questions. Recursion Review

23 Recursion with Objects
class TreeNode (object): """ Attributes: value: An int, the “value” of this TreeNode object left: A TreeNode object, or None right: A TreeNode object, or None 341 2 377 50 9 1110 Recursion Review

24 Understanding the Object’s Structure
id1 341 value id2 id3 left right TreeNode id3 377 value id5 id4 left right id2 TreeNode 2 value id6 None left right TreeNode id5 9 value None left right id4 1110 value None left right id6 50 value None left right TreeNode TreeNode TreeNode Recursion Review

25 Recursion with Objects
def contains (t, v): """ Returns: A boolean. Returns True if any of the TreeNode objects in the entire “tree” have a value equivalent to v. Let us define the “tree” as the TreeNode t, as well as the TreeNodes accessible through the left and right attributes of the node (if not None), as well as the TreeNodes accessible through the left and right attributes of those TreeNodes, etc. Precondition: t is a TreeNode, or None Recursion Review

26 Base Case Comparison “1” [1] “” [] None Strings Lists Tree 1 Element
0 Elements “” [] None id6 1 value None left right TreeNode Just make sure to mention that the "0 element" for objects is based on whether the precondition says that the object can be None or not. Recursion Review

27 Recursion with Objects
def contains (t, v): """ Returns: A boolean. Returns True if any of the TreeNode objects in the entire “tree” have a value equivalent to v. Let us define the “tree” as the TreeNode t, as well as the TreeNodes accessible through the left and right attributes of the node (if not None), as well as the TreeNodes accessible through the left and right attributes of those TreeNodes, etc. Precondition: t is a TreeNode, or None if t is None: #Case: None/non-existent Tree return False What I might do is ask the audience what they think the base case is. They will very likely say a node with no left or right, and I would say that's a valid base case, but ask them to think about the type that t can be, hinting at None. Recursion Review

28 Recursion with Objects
def contains (t, v): """ Returns: A boolean. Returns True if any of the TreeNode objects in the entire “tree” have a value equivalent to v. Let us define the “tree” as the TreeNode t, as well as the TreeNodes accessible through the left and right attributes of the node (if not None), as well as the TreeNodes accessible through the left and right attributes of those TreeNodes, etc. Precondition: t is a TreeNode, or None if t is None: #Case: None/non-existent Tree return False elif t.value == v: #Case: Found value return True Recursion Review

29 Divide and Conquer on Trees
Recall the tree structure... They can be easily divided into left and right subtrees! 341 2 377 50 9 1110 Recursion Review

30 Divide and Conquer on Trees
Recall the tree structure... They can be easily divided into left and right subtrees! 341 2 377 50 9 1110 Left subtree Right subtree Recursion Review

31 Divide and Conquer on Trees
Recall the tree structure... They can be easily divided into left and right subtrees! Recursion on left Recursion on right Put result back together 341 2 377 50 9 1110 Left subtree Right subtree Recursion Review

32 Recursion with Objects
def contains (t, v): """ Returns: A boolean. Returns True if any of the TreeNode objects in the entire “tree” have a value equivalent to v. Let us define the “tree” as the TreeNode t, as well as the TreeNodes accessible through the left and right attributes of the node (if not None), as well as the TreeNodes accessible through the left and right attributes of those TreeNodes, etc. Precondition: t is a TreeNode, or None if t is None: #Case: None/non-existent Tree return False elif t.value == v: #Case: Found value return True return contains(t.left, v) or contains(t.right, v) #Recursively check branches Recursion Review

33 Recursion with Objects
def contains (t, v): """ Returns: A boolean. Returns True if any of the TreeNode objects in the entire “tree” have a value equivalent to v. Let us define the “tree” as the TreeNode t, as well as the TreeNodes accessible through the left and right attributes of the node (if not None), as well as the TreeNodes accessible through the left and right attributes of those TreeNodes, etc. Precondition: t is a TreeNode, or None if t is None: #Case: None/non-existent Tree return False elif t.value == v: #Case: Found value return True return contains(t.left, v) or contains(t.right, v) #Recursively check branches What is the type of t.left and t.right? What happens if t.left or t.right is None? Recursion Review

34 Practice Worksheet (contd.)
Continue working on the problems! Raise your hand if you have any questions. Recursion Review

35 sumDigits def sumDigits(n):
"""Returns: Given a non-negative int n, return the sum of its digits recursively (no loops). For example sumDigits(126) → 9 sumDigits(49) → 13 sumDigits(12) → 3 Hint: recall the mod operator % that gives you the remainder during division""" if n // 10 == 0: return n else: return n % 10 + sumDigits(n//10) Recursion Review

36 fib def fib(n): """Returns: the nth Fibonacci number.
Fibonacci number sequence is a sequence that goes like Precondition: n is an int. 0th element is 0.""" if n == 0: return 0 elif n == 1: return 1 return fib(n-1) + fib(n-2) Recursion Review

37 delimStr def delimStr(s, delim):
"""Returns: returns the given word s with str delim after each letter, e.g. delimStr(‘hello’, "*") → ‘h*e*l*l*o*’ delimStr(‘hi’, "_") → ‘h_i_’ """ if len(s) == 0: return s else: return s[0] + delim + delimStr(s[1:], delim) Recursion Review

38 canSum def canSum(list, target):
"""Returns: True if you can sum elements of integer list <list> to target, e.g. canSum([2,4,5],7) -> True canSum([2,4,5],8) -> False canSum([],0) -> True """ if target == 0: return True if len(list) > 0: return canSum(list[1:],target-list[0]) or canSum(list[1:],target) else: return False #CHALLENGE QUESTION: This function is more difficult than what you would be expected to accomplish on a prelim; its main difficulty does not come from recursion, but from the algorithm to determine whether the elements are summable or not Recursion Review

39 count_ints def count_ints(lst):
"""Returns: The number of integers in a multi-dimensional list of integers, lst. For example, count_ints([1,[2,3,[4,5,6]],[7,8,[9,10]]]) would return 10. Precondition: lst is a list of ints """ count = 0 for item in lst: if type(item) == int: count += 1 else: count += count_ints(item) return count Recursion Review

40 count_ints alternative solution
def count_ints(lst): """Returns: The number of integers in a multi-dimensional list of integers, lst. For example, count_ints([1,[2,3,[4,5,6]],[7,8,[9,10]]]) would return 10. Precondition: lst is a list of ints """ if lst == []: return 0 if type(lst[0]) == int: return 1 + count_ints(lst[1:]) else: return count_ints(lst[0]) + counts_int(lst[1:]) Recursion Review

41 merge def merge(list1, list2):
"""Returns: The result of merging two sorted lists of ints, list1 and list2, in order. For example, merge([1,2,2,5], [2,3,3,3,4,5,6]) should return [1,2,2,2,3,3,3,4,5,5,6] """ if list1 == []: return list2 elif list2 == []: return list1 else: if list1[0] <= list2[0]: return [list1[0]] + merge(list1[1:], list2) return [list2[0]] + merge(list1, list2[1:]) Recursion Review

42 max_ancestor def max_ancestor(p):
""" Returns: How many generations old the family tree can be traced. If p has no parents, the function would return 1 because only 1 generation can be traced. Preconditions: p is a Person """ me dad mom grandpa1 grandpa2 great grandma Example: The family tree to the left can be traced up to 4 generations. That is, me -> dad -> grandpa1 -> great grandma On the mom's side, it could be traced up to 3 generations, but we are looking for the maximum tracing, which is 4 generations on dad's side. Recursion Review

43 max_ancestor def max_value(p):
""" Returns: How many generations old the family tree can be traced. If p has no parents, the function would return 1 because only 1 generation can be traced. Preconditions: p is a Person """ if (p.dad is None) and (p.mom is None): return 1 elif not (p.dad is None) and (p.mom is None): return 1 + max_ancestor(p.dad) if (p.dad is None) and not (p.mom is None): return 1 + max_ancestor(p.mom) else: return max(1 + max_ancestor(p.dad), 1 + max_ancestor(p.mom)) Recursion Review

44 max_ancestor alternate
def max_value(p): """ Returns: How many generations old the family tree can be traced. If p has no parents, the function would return 1 because only 1 generation can be traced. Preconditions: p is a Person """ d = 0 m = 0 if not (p.dad is None): d = max_ancestor(p.dad) if not (p.mom is None): m = max_ancestor(p.mom) return max(1 + d, 1 + m) Recursion Review

45 max_value def max_value(t):
"""Returns: Max value of all values stored in the tree reachable from TreeNode t Precondition: t is a TreeNode """ if (t.left is None) and (t.right is None): return t.value elif (not (t.left is None)) and (t.right is None): return max(t.value, max_value(t.left)) elif (t.left is None) and (not (t.right is None)): return max(t.value, max_value(t.right)) else: return max(t.value, max_value(t.left), max_value(t.right)) Recursion Review

46 tree_flip Recursion Review def tree_flip(t):
"""Swaps the right and left attributes of t, and recursively does the same to all subtrees Note the this is a procedural function and does not return anything Precondition: t is a TreeNode""" if (t.right != None): tree_flip(t.right) if (t.left != None): tree_flip(t.left) temp = t.right t.right = t.left t.left = temp Example 1: 1 would become Example 2: 1 4 would become Recursion Review


Download ppt "Recursion Review Spring 2019 CS 1110"

Similar presentations


Ads by Google