Představte si, že máte v ruce balíček karet, ale jsou úplně zpřeházené. Nebo máte seznam skóre hráčů, ale nevíte, kdo vyhrál, protože nejsou seřazená. Seznamy jsou mocné, ale často v nich vládne chaos. V této kapitole se naučíme, jak tento chaos zkrotit. Naučíme se seznamy třídit a manipulovat s nimi jako profesionálové. Třídění je jedním ze základních kamenů informatiky – pokud umíte efektivně třídit data, umíte vyřešit spoustu problémů.
Než začneme psát vlastní složité algoritmy, podíváme se do kufříku nástrojů, které nám Prolog nabízí. Jsou to vestavěné predikáty, které už někdo chytře naprogramoval za nás.
append(Seznam1, Seznam2, Vysledek): Spojí dva seznamy dohromady. Je to "švýcarský nůž" Prologu, protože umí seznamy nejen spojovat, ale i rozdělovat! (Zkuste se zeptat append(X, Y, [1,2,3]).).member(Prvek, Seznam): Zjistí, zda je prvek v seznamu. To už známe, ale Prolog to má v sobě.select(Prvek, Seznam, Zbytek): Vybere prvek ze seznamu a vrátí zbytek. Skvělé pro karetní hry (líznutí karty).permutation(Seznam, Permutace): Vytvoří všechny možné varianty seřazení seznamu (anagramy).Třídění je klasický problém. Jak seřadit čísla od nejmenšího po největší? Zkusíme si napsat Bubble Sort (Bublinkové třídění). Princip je jednoduchý a elegantní: představte si bublinky ve vodě. Větší (těžší) bublinky stoupají pomaleji, menší (lehčí) rychleji. Pokud jsou dva prvky vedle sebe špatně (větší je před menším), prohodíme je. Opakujeme to tak dlouho, dokud není vše seřazeno.
% Hlavní pravidlo: Seznam je seřazený, pokud...
bubblesort(Seznam, Serazeny) :-
swap(Seznam, NovySeznam), !, % ...se nám podařilo něco prohodit (swap).
bubblesort(NovySeznam, Serazeny). % Pak zkusíme třídit dál ten nový seznam.
bubblesort(Serazeny, Serazeny). % Pokud už nejde nic prohodit, je hotovo. Seznam je seřazený.
% Pravidlo pro prohození (Swap)
swap([A, B | Zbytek], [B, A | Zbytek]) :-
A > B. % Prohodíme, pokud A je větší než B (jsou ve špatném pořadí).
swap([Z | Zbytek], [Z | NovyZbytek]) :-
swap(Zbytek, NovyZbytek). % Jinak zkusíme prohodit něco dál v seznamu (v Ocasu).
Co dělá ten vykřičník !? To je tzv. řez (cut). Říká Prologu: "Pokud jsi úspěšně něco prohodil, už se nevracej zpátky a nezkoušej to jinak. Pokračuj v třídění nového seznamu." Bez něj by byl program strašně pomalý a zkoušel by zbytečné kombinace.
Příklad 9.1: Anagramy
Chcete najít všechny přesmyčky slova "ABC"? Použijeme permutation.
?- permutation([a,b,c], X).
X = [a, b, c] ;
X = [a, c, b] ;
X = [b, a, c] ;
X = [b, c, a] ;
X = [c, a, b] ;
X = [c, b, a].
Prolog automaticky vygeneroval všechny možné kombinace. To se hodí třeba pro luštění křížovek nebo šifrování.
Algoritmus je přesný postup, jak vyřešit problém. Bubble Sort je algoritmus. Není to jen "nějak to seřaď", ale "porovnej sousedy, prohoď je, opakuj". V programování je důležité nejen vědět co chceme (seřazený seznam), ale někdy i jak toho dosáhnout efektivně.
select/3? Zkuste si představit, že máte v ruce balíček karet a jednu si vyberete. Co vám zůstane?bubblesort a vestavěným sort/2? (Tip: Zkuste seřadit seznam [3, 1, 2, 1] oběma způsoby. Co se stane s duplicitními jedničkami?)vymaz(X, Seznam, NovySeznam), který odstraní všechny výskyty prvku X ze seznamu. (Např. vymažte všechna čísla 0 ze seznamu naměřených teplot).palindrom(Seznam), který zjistí, zda je seznam palindrom. (Nápověda: Seznam je palindrom, pokud je stejný jako jeho obrácená verze. Použijte vestavěný predikát reverse/2).