ЁЯкЖ рдзрдбрд╛ 06 тАФ Recursion: рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХ рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрдХрд╛рдВрдирд╛ рд╡рд┐рдЪрд╛рд░рддрд╛рдд
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 06 ┬╖ рдкреБрдвреЗ: lesson-07-sorting
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ06. рдПрдЦрд╛рджрд╛ рдкреНрд░рд╢реНрди рддреНрдпрд╛рдЪреАрдЪ рдЫреЛрдЯреА рдЖрд╡реГрддреНрддреА рд╡рд┐рдЪрд╛рд░реВрди рд╕реЛрдбрд╡рдгреЗ, рдЙрддреНрддрд░ рди рдорд┐рд│рд╛рд▓реЗрд▓реЗ рдкреНрд░рд╢реНрди рдзрд░реВрди рдареЗрд╡рдгрд╛рд░рд╛ stack, рдЖрдгрд┐ рдпрд╛рдд рдиреЗрд╣рдореА рд╣реЛрдгрд╛рд░реА рдХреНрд▓рд╛рд╕рд┐рдХ рдЪреВрдХ.
- dsa/algorithms.py тАФ
factorial(depth рдиреЛрдВрджрд╡рддреЛ),fib_slow(calls рдореЛрдЬрддреЛ),fib_memo(рдзрдбрд╛ 11 рдЪрд╛ рдлрд│рд╛) - dsa/demo.py тАФ
recursion
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
5 рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдХрд┐рддреА рдкреНрд░рдХрд╛рд░реЗ рд░рд╛рдВрдЧреЗрдд рдЙрднреЗ рд░рд╛рд╣реВ рд╢рдХрддрд╛рдд (5!) рд╣реЗ рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХреЗрд▓рд╛ рдЬрд╛рдгреВрди рдШреНрдпрд╛рдпрдЪреЗ рдЖрд╣реЗ. рддреА рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХреЗрд▓рд╛ рд╡рд┐рдЪрд╛рд░рддреЗ: "рдорд▓рд╛ 4! рд╕рд╛рдВрдЧрд╛, рдореА рддреНрдпрд╛рд▓рд╛ 5 рдиреЗ рдЧреБрдгреЗрди." рдЙрдкрдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХрд╛ рдПрдХрд╛ рд╢рд┐рдХреНрд╖рд┐рдХреЗрд▓рд╛ 3! рд╡рд┐рдЪрд╛рд░рддреЗ, рддреА 2! рд╡рд┐рдЪрд╛рд░рддреЗ, рддреА 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
тЭУ рдХрд╛рдп
- recursive function рдордзреНрдпреЗ рдПрдХ base case (рдереЗрдЯ рдЙрддреНрддрд░) рдЖрдгрд┐ рдПрдХ recursive case (рддреНрдпрд╛рдЪ рдкреНрд░рд╢реНрдирд╛рдЪреА рдЫреЛрдЯреА рдЖрд╡реГрддреНрддреА) рдЕрд╕рддреЗ.
- call stack рдЙрддреНрддрд░рд╛рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рдгрд╛рд░реА рдкреНрд░рддреНрдпреЗрдХ frame рдзрд░реВрди рдареЗрд╡рддреЛ: depth = memory. Python рдЪреА рдорд░реНрдпрд╛рджрд╛ ~1,000 frames рдЖрд╣реЗ; рдЦреЛрд▓ рдХрд╛рдорд╛рд╕рд╛рдареА loop рдХрд┐рдВрд╡рд╛ рд╕реНрд╡рддрдГрдЪрд╛ stack рд▓рд╛рдЧрддреЛ.
- рдЦрд░реНрдЪ = calls рдЪреА рд╕рдВрдЦреНрдпрд╛ ├Ч рдкреНрд░рддреНрдпреЗрдХ call рдЪреЗ рдХрд╛рдо.
factorial(n): n calls, O(n).fib_slow(n): ~1.6тБ┐ calls, O(2тБ┐) тАФ рддреЗрдЪ рдЙрдк-рдкреНрд░рд╢реНрди рдкреБрдиреНрд╣рд╛ рдкреБрдиреНрд╣рд╛ рд╡рд┐рдЪрд╛рд░рд▓реЗ рдЬрд╛рддрд╛рдд. Memoisation (рдЙрддреНрддрд░ рдорд┐рд│рд╛рд▓реЗрд▓реНрдпрд╛ рдкреНрд░рд╢реНрдирд╛рдВрдЪрд╛ dict) рд╣реЗ O(n) рдХрд░рддреЗ. - trees (рдзрдбрд╛ 09), DFS (рдзрдбрд╛ 10), merge/quick sort (рдзрдбрд╛ 07), backtracking рдЖрдгрд┐ DP (рдзрдбрд╛ 11) рдпрд╛рдВрдЪрд╛ рдиреИрд╕рд░реНрдЧрд┐рдХ рдЖрдХрд╛рд░ recursion рдЪ рдЖрд╣реЗ.
ЁЯдФ рдХрд╛
рдкреБрдврдЪреЗ рдирд┐рдореНрдореЗ 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 рдХрд╛ рдЕрд╕рддрд╛рдд рддреЗ рдореЛрдЬрд▓реЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- base case рдирд╛рд╣реА, рдХрд┐рдВрд╡рд╛ рдЕрд╕рд╛ base case рдЬреЛ рдХрдзреАрдЪ рдЧрд╛рдард▓рд╛ рдЬрд╛рдд рдирд╛рд╣реА тЖТ рдЕрдирдВрдд recursion.
- рджрд╣рд╛ рд▓рд╛рдЦ elements рдЪреНрдпрд╛ list рд╡рд░ recursion рдХрд░рдгреЗ (loop рд╡рд╛рдкрд░рд╛).
- program рдЕрдбрдХреЗрдкрд░реНрдпрдВрдд рдПрдХрдореЗрдХрд╛рдВрд╡рд░ рдпреЗрдгрд╛рд░реЗ (overlapping) рдЙрдк-рдкреНрд░рд╢реНрди рд▓рдХреНрд╖рд╛рдд рди рдпреЗрдгреЗ (рдзрдбрд╛ 11 рд╣реЗ рд╕реБрдзрд╛рд░рддреЛ).
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: JSON parsers, directory walkers, dependency resolvers рдЖрдгрд┐ query planners recursive рдЕрд╕рддрд╛рдд; рддреНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХрд╛рд▓рд╛ рдЦрд▒реНрдпрд╛ data рд╡рд░ рдПрдХрджрд╛ рддрд░реА "maximum recursion depth exceeded" рднреЗрдЯрд▓реЗрд▓рд╛ рдЖрд╣реЗ.
тПня╕П рдкреБрдвреЗ
рдзрдбрд╛ 07 тАФ sorting: рд╡рд░реНрдЧрд╛рд▓рд╛ рдЙрдВрдЪреАрдиреБрд╕рд╛рд░ рд░рд╛рдВрдЧреЗрдд рд▓рд╛рд╡рдгреЗ, рдЪрд╛рд░ рдкреНрд░рдХрд╛рд░реЗ, рд╡реЗрд│ рдореЛрдЬреВрди.