Lecture 8

Recursion

MCS 275 Spring 2024
Emily Dumas

View as:   Presentation   ·   PDF-exportable  ·   Printable

Lecture 8: Recursion

Reminders and announcements:

  • Homework 3 posted, due Tuesday at Noon
  • Project 1 description will be posted over the weekend. Discussion in Monday's lecture.

A few parting words about context managers...

Context manager summary

Safest way


                            #
                            

                            with CtxMgr() as varname:
                                thing(varname)
                                varname.f()


                            print("Ok.")
                        

                            #
                            M = CtxMgr()
                            
                            with M as varname:
                                thing(varname)
                                varname.f()


                            print("Ok.")
                        

Unsafe analog


                            #
                            M = CtxMgr()
                            varname = M.__enter__()
                            
                            thing(varname)
                            varname.f()
                            
                            M.__exit__(None,None,None)
                            print("Ok.")
                        

The one on the left still calls __exit__ if there is an exception in the indented block.

Built-in context managers

Some examples (listed as class - resource)

  • open - Open file
  • threading.Lock - Thread-exclusive right
  • urllib.request.urlopen - HTTP connection
  • tempfile.TemporaryFile - Temporary file (deleted after use)

Recursion

In computer science, recursion refers to a method of solving a problem that depends on solving a smaller version of the same problem.

Usually, recursion involves a function calling itself.

Strategies using recursion

  • Divide and conquer: A problem can be split into pieces; solutions for the pieces can be combined to the full solution.
    • e.g. Mergesort (later)
  • "Decrease and conquer": Reduce a problem for a given input (e.g. n) to the answer for a slightly smaller input (e.g. n-1) and a bit of extra work.
    • e.g. Factorial (today)

Iteration

Recursive solutions are often contrasted with iterative solutions.

  • Iterative: Loops and local variables keep track of current state
  • Recursive: Call history and argument keep track of current state

Recursive solutions can always be converted to iterative ones. Often recursive code is shorter.

Stop condition

A function that always calls itself will never finish!

Recursion must include some kind of stop condition—a case in which the function can directly return an answer instead of calling itself.

First recursion examples

  • Factorial
  • Fibonacci numbers
  • Paper folding sequence

Factorial

The classic first example of recursion, computing $$n! = n \times (n-1) \times \cdots \times 2 \times 1.$$

Natural to do recursively because $n! = n \times (n-1)!$ if $n>0$.

Fibonacci

The Fibonacci numbers are defined by $$F_0=0,\; F_1=1,\; \text{and }F_n = F_{n-1} + F_{n-2}$$

So the sequence begins $0,1,1,2,3,5,8,13,...$

The definition immediately suggests a recursive implementation.

Paper folding sequence

  • Start with a strip of paper
  • Fold it in half n times, always in the same direction
  • Unfold and read the in/out creases as 0/1

Paper folding sequence

Paper folding sequence

Let's use $\oplus$ to mean concatenation of binary sequences, so $0110 \oplus 11 = 011011$.

If $A$ is a binary sequence, let $\bar{A}$ denote the sequence with $0$ and $1$ switched, e.g. $\overline{11101} = 00010$

Finally, let $A^r$ denote the sequence in opposite order, e.g. $10010^r = 01001$.

$$PFS(n) = PFS(n-1) \oplus 1 \oplus \overline{PFS(n-1)^r}$$

Cool fact

If you use the infinite paper folding sequence as the binary digits of a real number, you get the paper folding constant.

$$ \begin{split} PFC &= (0.11011001110010011101100\ldots)_2\\ &= 0.85073618820186\ldots \end{split} $$

This number is irrational. In 2007 it was shown1 that it is also transcendental, i.e. cannot be expressed in terms of square roots, cube roots, or any solutions of polynomials with rational coefficients.

1 Adamczewski and Bugeaud, On the complexity of algebraic numbers I: Expansions in integer bases, Annals of Mathematics 165 (2007) 547-565.

Limited recursion depth

Active function calls are tracked by the call stack.

  • Calling a function → pushing onto call stack
  • Returning from a function → popping from call stack

Python imposes a limit on the call stack size (hence on recursion depth). Usually max is $\approx$ 1000.

Iterative solutions

Let's write iterative versions of factorial, Fibonacci, and paper folding. (Or as many as time allows.)

References

Revision history

  • 2023-02-03 Finalization of the 2023 lecture this was based on
  • 2024-01-26 Initial publication