Workshop 1 explores four classic recursive problems implemented in Python. Each exercise introduces a distinct recursion pattern — either LIFO (stack/last-in-first-out) or FIFO (tail/first-in-first-out) — building a practical foundation for reasoning about call-stack depth, accumulated state, and memoization. All exercises were authored by Santiago Rivera Marín (4th Semester, Data Structures, UCALDAS) and run in Google Colab.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/tutosrive/ed/llms.txt
Use this file to discover all available pages before exploring further.
Open this workshop in Google Colab →
https://colab.research.google.com/github/tutosrive/ED/blob/from_colab/workshops/colab/workshop_1_ED.ipynb
Exercise 1 — Binary Search (LIFO)
Implement a recursive algorithm that, given a sorted list and a target value, returns the index of the element or-1 if it is not found. The function uses LIFO (stack) recursion: each call pushes a new frame onto the call stack and waits for the recursive result before returning.
How it works:
- Compute the midpoint
medio = (left + right) // 2. - Base case — not found: if
medioexceeds the list bounds orright < left, return-1. - Base case — found: if
lista[medio] == value, returnmedio. - Recursive step: narrow the search window to the right half (
left = medio + 1) or the left half (right = medio - 1), then recurse.
binary_search.py
Exercise 2 — Factorial
Two versions of factorial are implemented to contrast the two main recursion styles.LIFO Version (Stack Recursion)
The LIFO version mirrors classical mathematical recursion. Each call tofactorial_pila suspends until the deeper call returns, building the product on the way back up the call stack.
factorial_lifo.py
FIFO Version (Tail / Accumulator Recursion)
The FIFO version uses a mutable list as an accumulator (array[0]). The multiplication happens before the recursive call — the function passes accumulated state forward rather than waiting to multiply on the way back. This is the tail-recursive pattern.
factorial_fifo.py
The FIFO version passes
array by reference (a single-element list acts as a mutable box). This avoids returning a value and lets the accumulator carry state across all recursive frames without waiting for any of them to return.Exercise 3 — List Sum (FIFO)
Compute the sum of all elements in a list using FIFO (tail) recursion. The running total is stored in the single-element listsum, which is updated before each recursive call — no return value is needed.
list_sum.py
[0, 1, 2, 3, 4]:
| Call | index | array[index] | sum[0] after step |
|---|---|---|---|
| 1 | 0 | 0 | 0 |
| 2 | 1 | 1 | 1 |
| 3 | 2 | 2 | 3 |
| 4 | 3 | 3 | 6 |
| 5 | 4 | 4 | 10 |
| 6 | 5 | — | (base case, stop) |
Exercise 4 — Fibonacci
Two Fibonacci implementations are presented: a tail-recursive version and a memoized version.Tail-Recursive Version
State is carried forward through theleft and right parameters; the result is stored in the mutable accumulator suma. No multiplication or addition happens on the return path.
fibonacci_tail.py
Memoized Version
The memoized version uses a dictionary (values) to cache already-computed Fibonacci numbers. Before recursing, the function checks whether the value is already known, avoiding redundant subtree evaluations.
fibonacci_memoized.py
Summary
| Exercise | Algorithm | Recursion Type | Key Technique |
|---|---|---|---|
| 1 | Binary Search | LIFO (Stack) | Halving search window on each call |
| 2 | Factorial | LIFO / FIFO | Return value vs. mutable accumulator |
| 3 | List Sum | FIFO (Tail) | Index advance with shared accumulator |
| 4 | Fibonacci | FIFO / Memoized | Tail state passing + dict cache |