Tema
/
Algoritmai ir duomenų struktūros GO
Pamoka 12 / 15 Subalansuoti medžiai (AVL) ~55 min
Kodas

avl.go — karkasas

Sukurk avl.go. Karkasas kaip įprasta; kūnai tavo.

Didesnė šio failo dalis yra vienuoliktos pamokos kodas, perkeltas be pakeitimųGet, Keys, Range, Min, Max yra tie patys, tik *node pakeistas į *avlNode. Rotacijos keičia formą, ne reikšmę. Kopijuok juos ir nesijausk sukčiaudamas: tai ir yra pastebėjimas, kad AVL medis yra BST.

Tikrai naujo — penkios funkcijos: height, balance, fix, dvi rotacijos ir rebalance.

Ką verta pasižymėti:

  • height privalo būti saugi nil atžvilgiu. Nesamo pomedžio aukštis yra 0. Pusė visų AVL klaidų yra pamiršta nil patikra būtent čia, ir jos pasirodo kaip „kartais nesubalansuota", ne kaip griūtis.
  • fix po rotacijos kviečiamas dviem mazgams, ir tvarka svarbi. Pirma tam, kuris nusileido, paskui tam, kuris pakilo — antrojo aukštis priklauso nuo pirmojo.
  • Vienodas raktas nebalansuojamas. Put su esamu raktu tik pakeičia įrašą; medžio forma nepasikeitė, tad ir taisyti nėra ko.
  • Rotacijos nėra palyginimai. c.Hit() kviečiamas tik lyginant raktus. Jei suskaičiuosi ir rotacijas, šeštas žingsnis nustos veikti — o jis kaip tik apie tai, ko skaitiklis nemato.
  • Height() čia yra O(1) — grąžina root.h. Vienuoliktoje pamokoje tam reikėjo apeiti visą medį. Tai nemokamas priedas prie lauko, kurį jau pridėjai.

Įterpimas turi būti rekursinis. Vienuoliktos pamokos ciklas su &(*cur).left čia netinka: taisyti reikia grįžtant atgal, o ciklas kelio atgal neturi.

Spąstai

rebalance grąžina naują pomedžio šaknį, ir kviečiantysis privalo tą reikšmę pasiimti:

n.left = insert(n.left)   // teisingai — pomedis gali turėti naują šaknį
insert(n.left)            // klaida — rotacija įvyko ir buvo pamesta

Antrasis variantas kompiliuojasi ir jokios klaidos neparodo. Len() didėja kiekvienu kvietimu, nes skaitiklis didinamas ten, kur sukuriamas lapas — bet pats lapas išmetamas, tad Get rakto neberanda. Pamatuota: krenta pats pirmas testas — Get("00000"): ok=false.

Tylus nieko nedarymas, kuris dar ir didina skaitiklį, yra piktesnis gedimas nei griūtis. Todėl avl_test.go pirmiausia ir tikrina, ar kiekvienas įdėtas raktas randamas.