Tema
/
Algoritmai ir duomenų struktūros GO
Pamoka 14 / 15 Grafai: BFS ir DFS ~55 min
Teorija

Tas pats algoritmas, kitas atsakymas

Penktoje pamokoje parodei, kad rekursija ir atskiras stekas yra tas pats algoritmas, ir tai pamatavai:

rekursinis                       80             40
iteracinis (tavo stekas)         80             40
identiški — tas pats algoritmas, tik stekas laikomas kitoje vietoje

Čia turi abu variantus grafe. Ir jie nesutampa.

  path from 0 to 705
  DFS (stack)                 214
  DFS (recursive)               1

  the two DFS versions agree: false

Testas sako, kiek dažnai:

the two DFS versions took different paths to 552 destinations

Iš 554 pasiekiamų — 552.

Ar penkta pamoka klydo

Ne. Ji tebėra teisinga, tik reikia tiksliai pasakyti, apie ką.

Tas pats liko tas pats. Abi versijos aplanko tas pačias viršūnes, atlieka tą patį darbo kiekį, kainuoja O(V + E) ir sutaria, kas pasiekiama — TestBothSearchesAgreeOnReachability to reikalauja ir jis praeina.

Skiriasi kaimynų eilės tvarka. Steko versija sudeda visus kaimynus ir ima paskutinį, tad juos apeina atbulai. Rekursinė eina iš eilės nuo pirmo. Ta pati aikštė, priešingos kryptys.

„Tas pats algoritmas" reiškia „skaičiuoja tą patį", ne „grąžina tą patį atsakymą". Kai atsakymų yra daug ir visi teisingi, tvarka nusprendžia, kurį gausi.

DFS grąžina kažkokį kelią. Nė vienas šių dviejų nėra teisingesnis už kitą.

Kur lygybė iš tikrųjų baigiasi

Penkta pamoka rado ir antrą skirtumą — gylį. Štai jis grafe, grandinės pavidalo bibliotekoje:

n= 4000000  iteracinis DFS: ok=true  hops=3999999
n= 4000000  rekursinis DFS: ok=true  hops=3999999

n=12000000  iteracinis DFS: ok=true  hops=11999999
n=12000000  rekursinis DFS:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

Keturi milijonai — abu veikia. Dvylika milijonų — iteracinis nueina visą grandinę, rekursinis nulūžta.

Priežastis ta pati, kurią penkta pamoka pamatavo: kvietimų stekas auga iki 1 GB ribos ir sustoja. Tavo stekas yra griežinys krūvoje, o jam tokios ribos nėra.

Ir dabar tai nebe demonstracija:

  • rekursija trumpesnė — DFS telpa į šešias eilutes vietoj dešimties;
  • iteracija neturi gylio ribos ir leidžia valdyti aplankymo tvarką;
  • BFS rekursijos net neturi — sluoksniams reikia eilės, o kvietimų stekas yra stekas.

Ketvirtoje pamokoje buvo pasakyta, kad transit rašo savo BFS iteraciškai su atskira eile. Dabar aišku, kad kitaip ir negalėtų: rekursija duoda steką, o BFS reikia eilės. Pasirinkimo ten nėra — jis yra tik DFS.