Haskell Hero
Interaktivní učebnice pro začínající Haskellisty
|
Sázíme stromyO binárních stromechBinární strom Binární strom je datová struktura. Může být buďto prázdný nebo neprázdný. Neprázdný strom se skládá z
V Haskellu jej budeme definovat následovně: data BinTree a = Empty | Node a (BinTree a) (BinTree a)kde Empty označuje prázdný strom. Neprázdný strom je definován jako
Node a (BinTree a) (BinTree a)kde ve výrazu Node x l r označuje x hodnotu v kořeni, l levý podstrom a r pravý podstrom.
Ukázky binárních stromů typu BinTree Int
Funkce na binárních stromechPříklad
Definujte funkci Jak začít? Drtivá většina funkcí na binárních stromech vypadá následovně:
Můžeme si tedy nadepsat definici: size :: BinTree a -> Int size Empty = size (Node x l r) = Kolik uzlů je v prázdném stromě? Přesně nula. Můžeme tedy doplnit první klauzuli. size Empty = 0 Kolik uzlů je v neprázdném stromě? Na tuto otázku už není možné odpovědět tak rychle, jako na předchozí. Podívejme se, co máme k dispozici. Je to hodnota v kořeni, levý podstrom a pravý podstrom. Nic víc. Kolik je uzlů v takovém stromě? Přesně tolik, kolik je dohromady v levém podstromu, v pravém podstromu a v kořeni. Čili rekurzivně spočítáme uzly v levém podstromu, spočítáme uzly v pravém podstromu a přičteme jedničku za uzel v kořeni. A přesně tak to zapíšeme. size (Node x l r) = size l + size r + 1Vidíme, že nám nezáleží na hodnotě v kořeni, takže můžeme x nahradit podtržítkem. Celá definice tedy vypadá následovně:
size :: BinTree a -> Int size Empty = 0 size (Node _ l r) = size l + size r + 1 Vzorové vyhodnoceníUkážeme si, jak vypadá počítání uzlů tříuzlového stromu. size (Node 5 -- x (Node 2 Empty Empty) -- l (Node 4 Empty Empty) -- r ) ~> size (Node 2 Empty Empty) + size (Node 4 Empty Empty) + 1 ~> size Empty + size Empty + 1 + size (Node 4 Empty Empty) + 1 ~> 0 + size Empty + 1 + size (Node 4 Empty Empty) + 1 ~> 0 + 0 + 1 + size (Node 4 Empty Empty) + 1 ~> 0 + 0 + 1 + size Empty + size Empty + 1 + 1 ~> 0 + 0 + 1 + 0 + size Empty + 1 + 1 ~> 0 + 0 + 1 + 0 + 0 + 1 + 1 ~>* 3 n-ární stromyKromě binárních stromů můžeme definovat i stromy n-ární. Od binárních stromů se liší tím, že každý uzel může mít libovolný počet následníků. Tvar n-árního stromu má například běžná adresářová struktura. Ukázka n-árního stromu typu NTree Char
V Haskellu budeme n-ární stromy definovat následovně: data NTree a = Nnode a [ NTree a ]kde ve výrazu Nnode x s je x hodnota uzlu a s seznam následníků.
Příklady n-árních stromů Všimněme si, že nemáme definován prázdný strom. Pokud bychom jej měli, tento zápis by vedl k nejednoznačnosti zápisu jednotlivých stromů. Například jednouzlový strom by mohl být definován následně: data NTree a = Empty | Nnode a [ NTree a ] Nnode 3 [] Nnode 3 [Empty] Nnode 3 [Empty, Empty] Nnode 3 [Empty, Empty, Empty] Nnode 3 [Empty, Empty, Empty, Empty] ... funkce na n-árních stromechPříklad
Definujte funkci Když se podíváme, jak n-ární strom vypadá, logicky nám vyplyne následující postup:
K rekurzivnímu sečtení všech stromů v seznamu podstromů použijeme funkci treeSum :: NTree Integer -> Integer treeSum (Nnode x s) = sum (map treeSum s) + x Vzorové vyhodnocení
treeSum (Nnode 5 [ Nnode 4 [], Nnode 6 [], Nnode 8 [] ]) ~> sum (map treeSum [ Nnode 4 [], Nnode 6 [], Nnode 8 [] ]) + 5 ~>* sum [ 4 , 6 , 8 ] + 5 ~>* 18 + 5 ~> 23 |