ЁЯПл The SchoolтА║ЁЯзо DSAтА║ЁЯкЖ рдзрдбрд╛ 06 тАФ Recursion: рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХ рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХрд╛рдВрдирд╛ рд╡рд┐рдЪрд╛рд░рддрд╛рдд
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯкЖ рдзрдбрд╛ 06 тАФ Recursion: рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХ рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХрд╛рдВрдирд╛ рд╡рд┐рдЪрд╛рд░рддрд╛рдд

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 06 ┬╖ рдкреБрдвреЗ: lesson-07-sorting


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ06. рдПрдЦрд╛рджрд╛ рдкреНрд░рд╢реНрди рддреНрдпрд╛рдЪреАрдЪ рдЫреЛрдЯреА рдЖрд╡реГрддреНрддреА рд╡рд┐рдЪрд╛рд░реВрди рд╕реЛрдбрд╡рдгреЗ, рдЙрддреНрддрд░ рди рдорд┐рд│рд╛рд▓реЗрд▓реЗ рдкреНрд░рд╢реНрди рдзрд░реВрди рдареЗрд╡рдгрд╛рд░рд╛ stack, рдЖрдгрд┐ рдпрд╛рдд рдиреЗрд╣рдореА рд╣реЛрдгрд╛рд░реА рдХреНрд▓рд╛рд╕рд┐рдХ рдЪреВрдХ.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

5 рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдХрд┐рддреА рдкреНрд░рдХрд╛рд░реЗ рд░рд╛рдВрдЧреЗрдд рдЙрднреЗ рд░рд╛рд╣реВ рд╢рдХрддрд╛рдд (5!) рд╣реЗ рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХреЗрд▓рд╛ рдЬрд╛рдгреВрди рдШреНрдпрд╛рдпрдЪреЗ рдЖрд╣реЗ. рддреА рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХреЗрд▓рд╛ рд╡рд┐рдЪрд╛рд░рддреЗ: "рдорд▓рд╛ 4! рд╕рд╛рдВрдЧрд╛, рдореА рддреНрдпрд╛рд▓рд╛ 5 рдиреЗ рдЧреБрдгреЗрди." рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХрд╛ рдПрдХрд╛ рд╢рд┐рдХреНрд╖рд┐рдХреЗрд▓рд╛ 3! рд╡рд┐рдЪрд╛рд░рддреЗ, рддреА 2! рд╡рд┐рдЪрд╛рд░рддреЗ, рддреА 1! рд╡рд┐рдЪрд╛рд░рддреЗ тАФ рдЖрдгрд┐ рд╕рд░реНрд╡рд╛рдд рд▓рд╣рд╛рди рд╢рд┐рдХреНрд╖рд┐рдХреЗрд▓рд╛ рдЙрддреНрддрд░ рдорд╛рд╣реАрддрдЪ рдЕрд╕рддреЗ:

  1. рдЙрддреНрддрд░реЗ рдкрд░рдд рд╡рд░ рдЬрд╛рддрд╛рдд. рдЙрддреНрддрд░ рди рдорд┐рд│рд╛рд▓реЗрд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ рдкреНрд░рд╢реНрди рд╡рд╛рдЯ рдкрд╛рд╣рдд рдЕрд╕рддрд╛рдирд╛ рдПрдХрд╛ рдврд┐рдЧрд╛рд╡рд░ рдмрд╕рд▓реЗрд▓рд╛ рд╣реЛрддрд╛ тАФ рддреЛ рдвреАрдЧ рдореНрд╣рдгрдЬреЗ call stack. рдвреАрдЧ рд╣рдЬрд╛рд░ рдЙрдВрдЪ рдЭрд╛рд▓рд╛ рддрд░ Python рдерд╛рдВрдмрд╛ рдореНрд╣рдгрддреЛ. рдЖрдгрд┐ рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХреЗрдиреЗ рддреЛрдЪ рдкреНрд░рд╢реНрди рджреЛрди рд╡реЗрдЧрд╡реЗрдЧрд│реНрдпрд╛ рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХрд╛рдВрдорд╛рд░реНрдлрдд рд╡рд┐рдЪрд╛рд░рд▓рд╛ рддрд░ рддреНрдпрд╛рдЪреЗ рдЙрддреНрддрд░ рджреЛрдирджрд╛ рдХрд╛рдврд▓реЗ рдЬрд╛рддреЗ тАФ рдЕрд╢рд╛ рдкреНрд░рдХрд╛рд░реЗрдЪ fib(25) рдЪреЗ 242,785 рдкреНрд░рд╢реНрди рд╣реЛрддрд╛рдд.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart TD
  F5["5! = 5 ├Ч 4!"] --> F4["4! = 4 ├Ч 3!"] --> F3["3! = 3 ├Ч 2!"] --> F2["2! = 2 ├Ч 1!"] --> F1["1! = 1 (base case)"]
  F1 -.->|"answers return"| F5

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдкреБрдврдЪреЗ рдирд┐рдореНрдореЗ structures рд╕реНрд╡рднрд╛рд╡рд╛рдиреЗрдЪ recursive рдЖрд╣реЗрдд; рддреЗ рдЖрдзреА iterative рдкрджреНрдзрддреАрдиреЗ рд▓рд┐рд╣рд┐рдгреЗ рддреНрд░рд╛рд╕рджрд╛рдпрдХ рдЖрд╣реЗ. рдкрдг recursion рдордзреНрдпреЗ рджреЛрди рд╕рд╛рдкрд│реЗ рдЖрд╣реЗрдд тАФ depth рдЖрдгрд┐ рдкреБрдиреНрд╣рд╛ рдкреБрдиреНрд╣рд╛ рд╣реЛрдгрд╛рд░реЗ рдХрд╛рдо тАФ рдЖрдгрд┐ рд╣рд╛ рдзрдбрд╛ tree рдордзреНрдпреЗ рднреЗрдЯрдгреНрдпрд╛рдЖрдзреАрдЪ рджреЛрдиреНрд╣реА рддреБрдореНрд╣рд╛рд▓рд╛ рджрд╛рдЦрд╡рддреЛ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

factorial рдПрдХрд╛ element рдЪреА list рдШреЗрддреЛ рдЖрдгрд┐ рддреЛ рдЬрд┐рдердкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪрд▓рд╛ рддреЗ рд╕рд░реНрд╡рд╛рдд рдЦреЛрд▓ n рдиреЛрдВрджрд╡рддреЛ; fib_slow рдкреНрд░рддреНрдпреЗрдХ call рд▓рд╛ counter рд╡рд╛рдврд╡рддреЛ; fib_memo рдЖрдзреА dict рддрдкрд╛рд╕рддреЛ. demo.py recursion depth рдЖрдгрд┐ рджреЛрдиреНрд╣реА call counts print рдХрд░рддреЛ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 dsa/demo.py recursion
python3 - <<'EOF'
import sys; sys.path.insert(0, "dsa"); from algorithms import fib_slow, fib_memo
for n in (10, 15, 20, 25):
    c = [0]; fib_slow(n, c); print(n, "naive calls:", c[0])        # watch it grow ~├Ч11 per +5: exponential
def depth(n): return 1 + depth(n - 1) if n else 0
try: depth(5000)
except RecursionError as e: print("too deep:", e)
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

depth 5 рд╕рд╣ 5! = 120; fib(25) рд╕рд╛рдзреЗ 242,785 calls, рддрд░ рдлрд│реНрдпрд╛рд╕рд╣ рдлрдХреНрдд 49. 10, 15, 20, 25 рд╕рд╛рдареАрдЪреЗ call counts рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рдпрд░реАрд▓рд╛ рд╕реБрдорд╛рд░реЗ ├Ч11 рдиреЗ рд╡рд╛рдврддрд╛рдд, рдЖрдгрд┐ depth(5000) RecursionError рджреЗрддреЛ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

рддреБрдореНрд╣реА base case рдЖрдгрд┐ рдЫреЛрдЯрд╛ call рд▓рд┐рд╣реВ рд╢рдХрддрд╛, рддреБрдореНрд╣реА stack рдЪреА рдорд░реНрдпрд╛рджрд╛ рдкрд╛рд╣рд┐рд▓реА, рдЖрдгрд┐ рдкреБрдиреНрд╣рд╛ рдкреБрдиреНрд╣рд╛ рдпреЗрдгрд╛рд░реЗ рдЙрдк-рдкреНрд░рд╢реНрди exponential рдХрд╛ рдЕрд╕рддрд╛рдд рддреЗ рдореЛрдЬрд▓реЗ.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: JSON parsers, directory walkers, dependency resolvers рдЖрдгрд┐ query planners recursive рдЕрд╕рддрд╛рдд; рддреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХрд╛рд▓рд╛ рдЦрд▒реНрдпрд╛ data рд╡рд░ рдПрдХрджрд╛ рддрд░реА "maximum recursion depth exceeded" рднреЗрдЯрд▓реЗрд▓рд╛ рдЖрд╣реЗ.

тПня╕П рдкреБрдвреЗ

рдзрдбрд╛ 07 тАФ sorting: рд╡рд░реНрдЧрд╛рд▓рд╛ рдЙрдВрдЪреАрдиреБрд╕рд╛рд░ рд░рд╛рдВрдЧреЗрдд рд▓рд╛рд╡рдгреЗ, рдЪрд╛рд░ рдкреНрд░рдХрд╛рд░реЗ, рд╡реЗрд│ рдореЛрдЬреВрди.

ЁЯкЖ Lesson 06 тАФ Recursion: the head asks the deputy

ЁЯУН You are here: Lesson 06 of 12 ┬╖ Next: lesson-07-sorting


ЁЯУж What's in this branch

Lessons 01тАУ06. Solving a question by asking a smaller version of it, the stack that holds the unanswered ones, and the classic way it goes wrong.

ЁЯзТ Explain like I'm 5

The head wants to know how many ways 5 pupils can line up (5!). She asks the deputy: "tell me 4! and I'll multiply by 5." The deputy asks a teacher for 3!, who asks for 2!, who asks for 1! тАФ and the youngest teacher just knows:

  1. Answers pass back up. Every unanswered question sat on a pile while it waited тАФ that pile is the call stack. If the pile gets a thousand high, Python says stop. And if the head asks the same question through two different deputies, it gets answered twice тАФ which is how fib(25) turns into 242,785 questions.

ЁЯЧ║я╕П Diagram

flowchart TD
  F5["5! = 5 ├Ч 4!"] --> F4["4! = 4 ├Ч 3!"] --> F3["3! = 3 ├Ч 2!"] --> F2["2! = 2 ├Ч 1!"] --> F1["1! = 1 (base case)"]
  F1 -.->|"answers return"| F5

тЭУ What

ЁЯдФ Why

Half the structures ahead are recursive by nature; writing them iteratively first is painful. But recursion has two traps тАФ depth and repeated work тАФ and this lesson makes both visible before you meet them in a tree.

ЁЯФз How (in this repo)

factorial takes a one-element list and records the deepest n it reached; fib_slow increments a counter on every call; fib_memo checks a dict first. demo.py recursion prints the depth and both call counts.

ЁЯзк Try it

python3 dsa/demo.py recursion
python3 - <<'EOF'
import sys; sys.path.insert(0, "dsa"); from algorithms import fib_slow, fib_memo
for n in (10, 15, 20, 25):
    c = [0]; fib_slow(n, c); print(n, "naive calls:", c[0])        # watch it grow ~├Ч11 per +5: exponential
def depth(n): return 1 + depth(n - 1) if n else 0
try: depth(5000)
except RecursionError as e: print("too deep:", e)
EOF

тЬЕ Verify тАФ what you should see

5! = 120 with depth 5; fib(25) 242,785 naive calls versus 49 with a board. The call counts for 10, 15, 20, 25 grow by about ├Ч11 each step, and depth(5000) raises RecursionError.

ЁЯПБ What you just proved

You can write a base case and a smaller call, you saw the stack's limit, and you measured why repeated sub-questions are exponential.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: JSON parsers, directory walkers, dependency resolvers and query planners are recursive; every one of them has met a "maximum recursion depth exceeded" on real data once.

тПня╕П Next

Lesson 07 тАФ sorting: lining the class up by height, four ways, timed.

тЖР Previoushash mapsNext тЖТsorting

This page is the lesson's README from the lesson-06-recursion branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.