IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 7 - Dolní odhad složitosti problému třídění

V minulé lekci, Quick sort, jsme si ukázali algoritmus Quick sort i se zdrojovými kódy.

Každý, kdo se setkal s alespoň dvěma třídícími algoritmy, si jistě položil otázku, jestli může existovat algoritmus, který to udělá rychleji. A tím rychleji mám na mysli z hlediska (asymptotické) časové složitosti, tedy zda existuje kategoricky efektivnější algoritmus. Složitostí problému (nikoli složitostí algoritmu) je tedy myšlena složitost úlohy, tedy složitost nejlepšího možného algoritmu, který úlohu vyřeší. V některých případech algoritmus dokonce nemusí být ani známý, ale my budeme vědět, že existuje a že bude někdy objeven. Teď se zaměříme na problém třídění prvků.

Každý zde uvedený algoritmus nám dávál vlastně horní odhad složitosti problému třídění. Bubblesort měl časovou složitost O(n2), věděli jsme tedy, že třídit můžeme nejhůře s touto složitostí. Např. Heap sort však ten samý problém zvládl s časovou složitostí O(n log n). Automaticky víme, že to půjde nejhůře takto. Ale může existovat algoritmus s ještě lepší časovou složitostí? Budeme předpokládat, že ne a toto tvrzení se pokusíme dokázat. Dokazujeme tedy dolní složitost problému třídění, tedy že to nejde lépe než v O(n log n).

Důkaz

Pokud třídíme na základě porovnávání prvků (pro dvojice prvků určujeme, který je větší, resp. menší), můžeme každý takový algoritmus zapsat jako rozhodovací strom. Rozhodovací strom je binární strom, který ve vnitřních vrcholech obsahuje dvojice porovnávaných prvků a v listech jejich permutace. V každém listu je tedy uložen jeden možný výstup algoritmu, ve všech listech jsou potom všechny možnosti, jak mohou být prvky v poli seřazené.

Takový rozhodovací strom pro pole 2 prvků by byl jednoduchý, obsahoval by jen kořen, ve kterém bychom se zeptali: je a < b? Pokud ano, dostali bychom permutaci [a, b]. Pokud ne, dostali bychom [b, a] a bylo by setříděno. Rozhodovací strom však s přibývajícími prvky velmi rychle roste. Takhle by vypadal rozhodovací strom pro 3 prvky:

Rozhodovací strom pro 3 prvky - Třídicí/řadicí algoritmy

Pro 4 prvky by byl strom asi 4x větší.

Pokud třídíme n prvků, všech permutací těchto prvku bude celkem zcela jistě n!, strom tedy musí mít nejméně n! listů. Stromy hloupějších algoritmů jich budou mít mnohem více. Můžeme si představit, že ten úplně nejlepší algoritmus má ideální strom s n! listy. V nejhorším případě (když půjde po nejdelší větvi) při průchodu od kořene do listu udělá tolik porovnání, kolik má strom "úrovní", tedy jaká je výška stromu h.

Binární strom výšky h bude jistě obsahovat max. 2^h listů.

Počet listů binárního stromu výšky h - Třídicí/řadicí algoritmy

Jak jsem se zmínil výše, listů musí být nejméně n!, aby byl strom úplný, jinak by nějakou permutaci vstupních prvků nedokázal setřídit. Budeme tedy vycházet z nerovnice:

Třídicí/řadicí algoritmy

Po zlogaritmování dostaneme:

Třídicí/řadicí algoritmy

Nyní se podrobně zaměřme pouze na n! a na to, zda bychom ho nemohli pro naše potřeby nějak upravit. K dalším krokům by se nám velmi hodilo dostat místo n! výraz (n/2)^(n/2). Toho dosáhneme následujícím trikem:
Pro lepší představu jsem na ukázku přidal členy 8!. n! si můžeme rozepsat jako:

Třídicí/řadicí algoritmy

Jelikož v naší původní nerovnici bylo >= n!, můžeme si klidně dovolit n! zmenšit a nerovnost neporušíme. Vezmeme si tedy jen levou polovinu ze zápisu výše a tu pravou zahodíme.

Třídicí/řadicí algoritmy

Můžeme si dokonce dovolit nahradit všechny členy za n/2, protože každý člen je jistě >= n/2, nerovnost tedy opět neporušíme.

Třídicí/řadicí algoritmy

Výše uvedený výraz můžeme zapsat jako (n/2)^(n/2) a dosadit do původní nerovnice.

Třídicí/řadicí algoritmy

Upravujeme:

Třídicí/řadicí algoritmy

(mocnina šla před logaritmus, log. podílu je rozdíl logaritmů, log 2 je 1, tu zanedbám a zvýším jmenovatel). Dostáváme tedy h >= n/4 log n.

Což znamená, že každý algoritmus musí v nejlepším případě udělat Třídicí/řadicí algoritmy porovnání (konstantu jsme schovali do symbolu Omega)

Dolní odhad složitosti problému třídění je Třídicí/řadicí algoritmy a tedy nemůže existovat třídící algoritmus založený na vzájmeném porovnávání prvků s lepší časovou složitostí než touto. Všimněte si, že jsem zdůraznil založený na vzájmeném porovnávání prvků. Že by to přeci jen šlo rychleji? O tom je následující článek - Counting sort :)

V další lekci, Counting sort, si ukážeme algoritmus Counting sort i se zdrojovými kódy.


 

Předchozí článek
Quick sort
Všechny články v sekci
Třídicí/řadicí algoritmy
Přeskočit článek
(nedoporučujeme)
Counting sort
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
28 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity