Når en instans kan deles i mindre instanser av samme problem, blir rekursjon en designmetode i seg selv. Splitt og hersk deler instansen, løser delene rekursivt og kombinerer svarene — og kjøretiden faller ut av en rekurrens som vi kan løse mekanisk.
Metoden: del, hersk, kombiner
Korrektheten følger ved induksjon over instansstørrelsen: grunntilfellene er riktige, og hvis alle de mindre delene blir riktig løst, gjør kombineringssteget resten. Det vi må regne ut, er hvor mye arbeid de rekursive kallene pluss del- og kombineringssteget koster til sammen.
Binærsøk — den enkleste delingen
Binærsøk (Bisect) er det reneste eksempelet: i en sortert tabell sammenligner vi med midtelementet og forkaster den halvdelen som umulig kan inneholde målet. Hvert steg halverer søkevinduet , så vi når fra til på steg.
def binary_search(a: list[int], target: int) -> int:
lo, hi = 0, len(a) - 1
while lo <= hi:
mid = (lo + hi) // 2
if a[mid] == target:
return mid
if a[mid] < target:
lo = mid + 1
else:
hi = mid - 1
return -1 Interaktiv visualisering krever JavaScript.
Søkevinduet er rammet inn; forkastede indekser tones ut, midtelementet sammenlignes (oransje), og treffet låses grønt. lo/mid/hi vises som pekere. Spill av, stega med piltastene, eller endre antallet.
Binærsøk gir samtidig den enkleste rekurrensen i kurset: ett rekursivt kall på halve instansen pluss konstant arbeid, . Den iterative varianten over (while-løkka) er bare den samme rekursjonen rullet ut.
Merge-Sort — balansert deling
Merge-Sort deler tabellen i to like halvdeler, sorterer hver rekursivt og fletter de to sorterte halvdelene med et lineært to-finger-sveip. Delingen er alltid balansert, så vi får rekursjonsnivåer, og flettingen gjør arbeid per nivå:
Det gir i alle tilfeller — Merge-Sort er ikke følsom for inputrekkefølge. Prisen er ekstra minne til flettebufferne.
Quicksort — deling ved partisjonering
Quicksort snur problemet: i stedet for å dele blindt på midten og flette etterpå, gjør den alt arbeidet før rekursjonen, ved å partisjonere. Med Lomutos partisjon velger vi pivoten som det høyre elementet, skanner vinduet og samler alt som er pivot til venstre. Pivoten havner på sin endelige plass mellom -regionen og -regionen, og vi sorterer hver side rekursivt — uten noe kombineringssteg.
def quick_sort(a, lo=0, hi=None):
if hi is None:
hi = len(a) - 1
if lo >= hi:
return
pivot = a[hi]
i = lo - 1
for j in range(lo, hi):
if a[j] <= pivot:
i += 1
a[i], a[j] = a[j], a[i]
a[i + 1], a[hi] = a[hi], a[i + 1]
quick_sort(a, lo, i)
quick_sort(a, i + 2, hi) Interaktiv visualisering krever JavaScript.
Pivoten er fiolett, elementet som sammenlignes oransje, og et bytte som utvider ≤-regionen er aksentfarget. Når pivoten slippes på plass låses den grønn. Den stiplede rammen er det aktive vinduet [lo..hi].
Pivotvalget bestemmer alt. Deler partisjonen instansen jevnt, får vi rekurrensen , akkurat som Merge-Sort. Men på allerede (omvendt) sortert input lander pivoten i hjørnet hver gang, partisjonen blir maksimalt skjev, og rekurrensen degenererer til .
Randomisert Quicksort fjerner avhengigheten av inputrekkefølgen ved å velge pivot tilfeldig (eller stokke tabellen først). Da blir den forventede kjøretiden for enhver fast input — worst-case finnes fortsatt, men ingen bestemt input kan fremtvinge den. I praksis er Quicksort ofte raskere enn Merge-Sort fordi den sorterer in-place og har små konstantfaktorer.
Å løse rekurrenser
Rekurrensen forteller hvor mye arbeid splitt-og-hersk koster. Tre metoder løser de fleste vi møter:
| Metode | Idé | Når |
|---|---|---|
| Substitusjon | gjett en grense, bevis den ved induksjon | når du allerede aner svaret |
| Rekursjonstre | summer arbeidet nivå for nivå i kalltreet | for å bygge intuisjon / finne gjettet |
| Iterasjonsmetoden | rull ut rekurrensen til et mønster trer fram | enkle, lineære rekurrenser |
| Masterteoremet | slå opp svaret fra , og | rekurrenser på standardform |
Standardformen masterteoremet dekker er
der delinstanser hver har størrelse og er kostnaden for å dele og kombinere. Svaret avgjøres av en kappestrid mellom arbeidet i bladene, , og arbeidet på toppen, :
| Tilfelle | Betingelse | Løsning |
|---|---|---|
| 1 | — bladene dominerer | |
| 2 | — balanse | |
| 3 | og regularitet — toppen dominerer |