1 of 76

Recursion

Jessica Xu

Nov 18, 2024

CSCI 110 - Lecture 35

2 of 76

Today’s Agenda

  • Review (Sorting)
  • Recursion

3 of 76

Recap

4 of 76

sort()

  • Instance method on the List class (only works on lists)
  • Mutates the lists when sorting
  • Is a void function (returns None)

5 of 76

sorted()

  • Function
  • Works on any iterable (dictionary, list, set, string)
  • Does not mutate
  • Returns a list with the iterable values sorted

6 of 76

Both sort() & sorted()

  • Sort in ascending order by default
  • Can reverse the order of sorting with reverse=True parameter
  • Can customize the sort order with the key=function_name parameter

7 of 76

Sorting students by name

students = [[‘Nirmal’, 39], [‘Michael’, 18], [‘Jeremy’, 19], [‘Constance’, 18], [‘Andre’, 19], [‘Deirdre’, 18], [‘Zade’, 19], [‘Conner’, 18]]

students.sort()

[[‘Andre’, 19], [‘Conner’, 18], [‘Constance’, 18], [‘Deirdre’, 18], [‘Jeremy’, 19], [‘Michael’, 18], [‘Nirmal’, 39], [‘Zade’, 19]]

8 of 76

Sorting students by age

students = [[‘Nirmal’, 39], [‘Michael’, 18], [‘Jeremy’, 19], [‘Constance’, 18], [‘Andre’, 19], [‘Deirdre’, 18], [‘Zade’, 19], [‘Conner’, 18]]

students.sort(key=lambda student : student[1])

[[‘Michael’, 18], [‘Constance’, 18], [‘Deirdre’, 18], [‘Conner’, 18], [‘Jeremy’, 19], [‘Andre’, 19], [‘Zade’, 19], [‘Nirmal’, 39]]

9 of 76

Using name as a secondary “tie breaker”

students = [[‘Nirmal’, 39], [‘Michael’, 18], [‘Jeremy’, 19], [‘Constance’, 18], [‘Andre’, 19], [‘Deirdre’, 18], [‘Zade’, 19], [‘Conner’, 18]]

students.sort(key=lambda student : (student[1], student[0]))

[[‘Conner’, 18], [‘Constance’, 18], [‘Deirdre’, 18], [‘Michael’, 18], [‘Andre’, 19], [‘Jeremy’, 19], [‘Zade’, 19], [‘Nirmal’, 39]]

10 of 76

Using name as a secondary “tie breaker” v2

students = [[‘Nirmal’, 39], [‘Michael’, 18], [‘Jeremy’, 19], [‘Constance’, 18], [‘Andre’, 19], [‘Deirdre’, 18], [‘Zade’, 19], [‘Conner’, 18]]

students.sort(key=lambda student : student[0])

[[‘Andre’, 19], [‘Conner’, 18], [‘Constance’, 18], [‘Deirdre’, 18], [‘Jeremy’, 19], [‘Michael’, 18], [‘Nirmal’, 39], [‘Zade’, 19]]

students.sort(key=lambda student : student[1])

[[‘Conner’, 18], [‘Constance’, 18], [‘Deirdre’, 18], [‘Michael’, 18], [‘Andre’, 19], [‘Jeremy’, 19], [‘Zade’, 19], [‘Nirmal’, 39]]

11 of 76

Sort by age (descending)

students = [[‘Nirmal’, 39], [‘Michael’, 18], [‘Jeremy’, 19], [‘Constance’, 18], [‘Andre’, 19], [‘Deirdre’, 18], [‘Zade’, 19], [‘Conner’, 18]]

students.sort(key=lambda student : (student[1], student[0]), reverse=True)

[[‘Nirmal’, 39], [‘Zade’, 19], [‘Jeremy’, 19], [‘Andre’, 19], [‘Michael’, 18], [‘Deirdre’, 18], [‘Constance’, 18], [‘Conner’, 18]]

12 of 76

Sorting Runtime

Different sorting algorithms also have different runtimes.

The default sort in every programming language has time complexity:

O(n log(n))

13 of 76

Recursion

14 of 76

Calling functions from other functions

def add_one(num):

return num + 1

def add_five(num):

for i in range(5):

num = add_one(num)

return num

print(add_five(10))

15

15 of 76

Calling functions from within that function

def add_one(num):

num = add_one(num) + 1

return num

print(add_one(10))

RecursionError: maximum recursion depth exceeded

16 of 76

Imagine you are waiting in a line…

17 of 76

Imagine you are waiting in a line…

How do you determine how long the line is?

You could just get out of line and count!

18 of 76

What if it is a really long line?

19 of 76

Imagine you are waiting in a line…

How do you determine how long the line is?

You could still count! But it might take awhile...

What if no one will save your spot in line? Getting out of line would make you have to go to the end :/

It is too far to see the entire line from where you are standing...

20 of 76

Idea!

Ask your neighbor! Maybe they know?

me

Hey do you know how long this line is?

21 of 76

Idea!

me

Nope but I can ask!

22 of 76

Idea!

me

Hey do you know how long this line is?

23 of 76

Idea!

me

Nope but I can ask!

24 of 76

Idea!

me

Hey do you know how long this line is?

25 of 76

Idea!

me

Nope but I can ask!

26 of 76

Idea!

me

Hey do you know how long this line is?

27 of 76

Idea!

me

Yes i’m actually first in line!

28 of 76

Idea!

me

I’m second in line!

29 of 76

Idea!

me

I’m third in line!

30 of 76

Idea!

me

I’m fourth in line!

31 of 76

Idea!

me

I guess I’m fifth!

32 of 76

Recursion

  • Recursion: Defining a problem in terms of itself.
  • Recursive programming: Writing methods that call themselves to solve problems recursively.
    • An equally powerful substitute for iteration (loops)!
    • Particularly well-suited to solving certain types of problems!

33 of 76

Recursion

  • Every recursive algorithm involves at least 2 cases:
    • Base case: A simple occurrence that can be answered directly.
    • Recursive case: A more complex occurrence of the problem that cannot be directly answered, but can instead be described in terms of smaller occurrences of the same problem.
  • Some recursive algorithms have more than one base or recursive case, but all have at least one of each. A crucial part of recursive programming is identifying these cases!

34 of 76

How long is the line?

def line_length(person):

if (you are first in line):

return 1

else:

# ask neighbor what position they are in, wait for response, add 1

return line_length(neighbor) + 1

Base Case

Recursive Case

35 of 76

Factorial

36 of 76

Code Factorial (iteratively = using a loop)

Function: factorial()

Input: number n

Output: n!

Examples:

factorial(0) -> 1

factorial(1) -> 1

factorial(2) -> 2 * 1 = 2

factorial(3) -> 3 * 2 * 1 = 6

37 of 76

Code using a loop

def factorial_iterative(n):

if n < 0:

raise ValueError("n cannot be negative")

elif n == 0:

return 1

else:

result = 1

for i in range(1, n + 1):

result = result * i

return result

38 of 76

Code Factorial (using recursion)

Function: factorial()

Input: number n

Output: n!

Examples:

factorial(0) -> 1

factorial(1) -> 1

factorial(2) -> 2 * factorial(1) = 2

factorial(3) -> 3 * factorial(2) = 6

39 of 76

Code using recursion

def factorial(n):

if n < 0:

raise ValueError("n cannot be negative")

if n == 0 or n == 1:

return 1

else:

return n * factorial(n - 1)

40 of 76

Fibonacci

41 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1

42 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1,

+

0

1

1

43 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1,

+

1

1

1,

2

44 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1,

+

1

2

1,

2,

3

45 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1,

+

2

3

1,

2,

3,

5

46 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1,

+

3

5

1,

2,

3,

5,

8

47 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1,

+

5

8

1,

2,

3,

5,

8,

13

48 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1,

+

8

13

1,

2,

3,

5,

8,

13,

21

49 of 76

Fibonacci Sequence

Special sequence of numbers where a number in the sequence is the sum of previous two numbers!

Start with 0 and 1:

0, 1, 1, 2, 3, 5, 8, 13, 21...

50 of 76

Code Fibonacci Sequence

Function: fibonacci()

Input: number n

Output: nth value in Fibonacci Sequence

Examples:

fibonacci(0) -> 0

fibonacci(1) -> 1

fibonacci(2) -> 1

fibonacci(3) -> 2

fibonacci(4) -> 3

fibonacci(5) -> 5

fibonacci(6) -> 8

fibonacci(7) -> 13

51 of 76

Code using a loop

def fibonacci(num):

if num <= 1:

return num

num_1 = 0

num_2 = 1

for i in range(num - 1):

temp = num_2

num_2 = num_2 + num_1

num_1 = temp

return num_2

52 of 76

Thinking recursively

Can I define this problem in terms of itself?

Hint: What if I start from the top (n) instead of from the bottom (0 & 1)?

fibonacci(4) -> 3

fibonacci(5) -> 5

fibonacci(6) -> 8

fibonacci(7) -> 13

fibonacci(0) -> 0

fibonacci(1) -> 1

fibonacci(2) -> 1

fibonacci(3) -> 2

53 of 76

Thinking recursively

f(5) = f(4) + f(3)

f(3) + f(2)

f(2) + f(1)

f(2) + f(1)

f(1) + f(0)

f(1) + f(0)

f(1) + f(0)

54 of 76

Thinking recursively

f(5) = f(4) + f(3)

f(3) + f(2)

f(2) + f(1)

f(2) + f(1)

f(1) + f(0)

f(1) + f(0)

f(1) + f(0)

55 of 76

Thinking recursively

f(5) = f(4) + f(3)

f(3) + f(2)

f(2) + 1

f(2) + 1

1 + 0

1 + 0

1 + 0

56 of 76

Thinking recursively

f(5) = f(4) + f(3)

f(3) + 1

1 + 1

1 + 1

57 of 76

Thinking recursively

f(5) = f(4) + 2

2 + 1

58 of 76

Thinking recursively

f(5) = 3 + 2

59 of 76

Thinking recursively

f(5) = 5

60 of 76

Code Fibonacci Sequence

def fibonacci(n):

if n <= 1:

return n

else:

return fibonacci(n-1) + fibonacci(n-2)

Base Case

Recursive Case

61 of 76

Motivation

62 of 76

Why learn recursion?

  • A challenge! A different way of thinking of problems!
  • Can solve some kinds of problems better than iteration.
  • Leads to elegant, simplistic, short code (when used well).
  • Some programming languages ("functional" languages such as Scheme, ML, and Haskell) use recursion exclusively (no loops).

63 of 76

Population count

def update_population_count(population):

world_population = 0

for continent in population:

continent_population = 0

for country in population[continent]:

country_population = 0

for state in population[continent][country]:

state_population = 0

for city in population[continent][country][state]:

state_population += population[continent][country][state][city]

population[continent][country][state]['total'] = state_population

country_population += state_population

population[continent][country]['total'] = country_population

continent_population += country_population

population[continent]['total'] = continent_population

world_population += continent_population

population['total'] = world_population

64 of 76

Population count

def update_population_count(population):

if type(population) != dict:

return population

else:

total = 0

for key in population:

total += update_population_count(population[key])

population['total'] = total

return total

65 of 76

Problems with complex structures

Recursion helps to solve problems that involve exploring all possible paths or combinations within a complex structure.

Ex. Finding all files in a directory and its subdirectories.

Use recursion to traverse the file system, exploring each directory and its subdirectories until you reach the "leaves" (files).

66 of 76

Questions?

67 of 76

Reminders

68 of 76

Reminder: Project 2 (pt. 3)

  • Build a simple search engine using dictionaries!
  • Work with your group of 3 :)
  • Read the instructions because you need to write a doc and submit a form for each part!
  • Due Wednesday @ 11:59pm

Reminder there are no late submissions for the projects!

69 of 76

Reminder: Project 2 (pt. 4)

Due next Monday @ 11:59pm!

Don’t forget the extra credit (practice problems) that is due on Wednesday November 27th @ 11:59pm!

70 of 76

Reminder: HW 11

  • Due Wednesday @ 11:59 PM
  • This HW covers Scope, Pass by Value/Reference, Classes

71 of 76

Reminder: HW 12 – LAST ONE!

  • Due next Wednesday @ 11:59 PM
  • This HW covers Sorting

72 of 76

Retake: Quiz 9

  • No need to have emailed me :)
  • Just come to my OH this week and we can do it together!

73 of 76

Final Lab TOMORROW!

  • Important! Please come on time!
  • There will be an extra credit opportunity :)

74 of 76

Final Exam

When: During your lab on Tuesday, December 3rd!

Where: TBD

Afterwards, there will be an Engineering Director from Google who has volunteered their time to give you a Tech Talk on Tuesday, December 3rd @ 4pm!

75 of 76

Grades!

  • Go to https://csci110.page/grades/
    • I will update it again this Tuesday!

76 of 76

Googler TAs and Career Coaches!

Need some extra support?

Book virtual OH with some folks from Google!

https://sites.google.com/corp/view/gir-career-coaches

Email my Googler TAs:

https://csci110.page/staff/#googler-teaching-assistants