Algoritmy I Třídění 1 ALGI 2010/2011
Třídící problém Je dána množina A = {a 1,a 2,...,a n }. Je potřebné najít permutaci π těchto n prvků, která zobrazuje danou posloupnost do neklesající posloupnosti a π(1), a π(2),...,a π(n) tak, že a π(1) a π(2)... a π(n). Množinu U, ze které vybíráme prvky tříděné množiny, nazýváme univerzum. 2 ALGI 2010/2011
Třídící problém Prvky množiny U se nazývají klíče a informace vázaná na klíč spolu s klíčem se nazývá záznam. Jestliže je velikost vázané informace příliš velká je výhodnější utřídit jen klíče s patřičnými odkazy na vázané informace, které se v tomto případě nehýbají. Bez újmy na obecnosti budeme dále předpokládat, že třídíme pouze klíče. 3 ALGI 2010/2011
Vlastnosti třídících metod Třídící metoda se nazývá stabilní, když zachovává relativní uspořádání záznamů se stejným klíčem. To znamená, že pro třídící permutaci platí: π(i)<π(j) a π(i) = a π(j) pro 1 i < j n. Stabilita třídění je často důležitá tehdy, když jsou prvky již uspořádané podle určitých sekundárních klíčů, to znamená vlastností, které samotný (primární) klíč neodráží. 4 ALGI 2010/2011
Vlastnosti třídících metod Třídící algoritmus nazýváme přirozeným, jestliže jeho složitost roste resp. klesá v závislosti na míře setříděnosti vstupní posloupnosti tj. jestliže doba potřebná k setřídění již setříděné podmnožiny údajů je menší, než doba potřebná na setřídění zbývající nesetříděné podmnožiny. Pokud tato podmínka není splněna, pak se metoda označuje za nepřirozenou. 5 ALGI 2010/2011
Vlastnosti třídících metod Třídění se nazývá in situ (neboli na původním místě), jestliže třídící algoritmus vyžaduje, kromě vlastního tříděného pole, pomocnou paměť pouze konstantního rozsahu. Jinými slovy algoritmus nepoužívá žádnou další paměť, jejíž velikost by byla závislá na rozsahu tříděných hodnot (např. další pole rozsahu n). ALGI 2010/2011 6
Klasifikace třídících algoritmů Při vnitřním třídění máme větší volnost při výběru vhodných datových struktur (pole, seznamy, stromy,.) a operací nad nimi. Naopak při vnějším třídění musíme vystačit jen se sekvenčním přístupem k prvkům tříděné množiny, a tedy třída přípustných algoritmů je oproti předcházejícímu případu značně omezená. ALGI 2010/2011 7
Složitost třídících algoritmů Složitost algoritmů bude dána počtem provedených významných operací. Pro vnitřní třídění považujeme za významné operace porovnávání klíčů a přesuny prvků. U vnějšího třídění hrají klíčovou roli operace přístupu do datových souborů. 8 ALGI 2010/2011
ALGI Asociativní třídění 9 ALGI 2010/2011
Třídění přímým vkládáním (Insertion Sort) Tento způsob třídění připomíná řazení karet. Postupně vybíráme jednu kartu za druhou a zařazujeme je na odpovídající místo podle barvy a hodnoty - klíče, ostatní ještě nezatříděné posuneme o jednu pozici. 10 ALGI 2010/2011
Třídění přímým vkládáním Algoritmus: 1. První prvek pole ponecháme na svém místě. 2. Vezmeme druhý prvek a porovnáme jej s prvním. Je-li menší, zařadíme ho na první místo a první prvek posuneme, jinak je ponecháme na místě. 3. Vezmeme třetí prvek a porovnáme jej s prvními dvěma prvky. Je-li menší než některý z nich, zařadíme jej na odpovídající pozici a následující prvky podle potřeby posuneme. Jinak je ponecháme na původních místech. 4. Obdobně postupujeme i s ostatními prvky v poli. 11 ALGI 2010/2011
Př: Je dána posloupnost čísel 11 3 27 8 50 22 12. Setřiďte ji metodou přímého vkládání. 11 3 27 8 50 22 12 3 11 27 8 50 22 12 3 11 27 8 50 22 12 3 8 11 27 50 22 12 3 8 11 27 50 22 12 3 8 11 22 27 50 12 3 8 11 12 22 27 50 12 ALGI 2010/2011
Složitost Nejhorší případ nastává, jestliže zdrojová posloupnost je uspořádána v opačném pořadí. Počet porovnání pro i-tý prvek bude C i = i-1 a počet přesunů M i = C i +2. Celkový počet porovnání C max a přesunů M max pro nejhorší případ bude N 2 N 2 N N N + 3N Cmax = Ci = M max = M i = i= 2 2 i= 2 2 Složitost metody přímým vkládáním je tedy O(N 2 ). 4 13 ALGI 2010/2011
Třídění přímým výběrem (Selection Sort) Pro jednoduchost si představme posloupnost rozdělenou do dvou částí. V jedné části jsou již setříděné prvky, zatímco druhá část je nesetříděná. V nesetříděné části najdeme nejmenší prvek a přesuneme ho na konec setříděné části (vyměníme s posledním prvkem setříděné části). ALGI 2010/2011 14
Třídění přímým výběrem Algoritmus: 1. V posloupnosti najdeme nejmenší prvek a vyměníme ho s prvkem na první pozici. Tím dojde k rozdělení posloupnosti na dvě části. Setříděná část obsahuje pouze jeden prvek, nesetříděná N-1. 2. V nesetříděné části najdeme nejmenší prvek a vyměníme ho s prvním prvkem v nesetříděné části, čímž dojde k zařazení tohoto prvku do setříděné části. 3. Obsahuje-li nesetříděná část více než jeden prvek, pokračujeme bodem 2, jinak je třídění ukončeno. ALGI 2010/2011 15
Př: Je dána posloupnost čísel 11 3 27 8 50 22 12. Setřiďte ji metodou přímého výběru. 11 3 27 8 50 22 12 3 11 27 8 50 22 12 3 8 27 11 50 22 12 3 8 11 27 50 22 12 3 8 11 12 50 22 27 3 8 11 22 22 50 27 3 8 11 12 22 27 50 ALGI 2010/2011 16
Složitost C = N 2 2 N M max N 4 2 + 3( N 1) Složitost metody přímým výběrem je tedy O(N 2 ). ALGI 2010/2011 17
Bublinkové třídění (Bubble Sort) Třídění přímou výměnou sousedních prvků. Procházíme polem, porovnáváme dva sousední prvky a pokud nejsou v požadovaném pořadí, prohodíme je. ALGI 2010/2011 18
Algoritmus: Bublinkové třídění 1. Posloupnost rozdělíme na dvě části, setříděnou a nesetříděnou.setříděná část je prázdná. 2. Postupně porovnáme všechny sousední prvky v nesetříděné části a pokud nejsou v požadovaném pořadí, prohodíme je. 3. Krok 2 opakujeme tak dlouho, dokud nesetříděná část obsahuje více než jeden prvek. Jinak algoritmus končí. ALGI 2010/2011 19
Př: Je dána posloupnost čísel 11 3 27 8 50 22 12. Setřiďte ji metodou Bubble Sort. 11 27 8 50 22 3 12 3 11 27 8 50 22 12 3 8 11 27 12 50 22 3 8 11 12 27 22 50 3 8 11 12 22 27 50 3 8 11 22 22 27 50 3 8 11 12 22 27 50 ALGI 2010/2011 20
Modifikace kroku 3 (Přirozené bublinkové třídění): Pokud nastala v kroku 2 alespoň jedna výměna, došlo ke zmenšení nesetříděné části o jeden prvek, pokračujeme bodem 2. Jinak je třídění ukončeno. 11 27 8 50 22 3 12 3 11 27 8 50 22 12 3 8 11 27 12 50 22 3 8 11 12 27 22 50 3 8 11 12 22 27 50 3 8 11 22 22 27 50 ALGI 2010/2011 21
Složitost Počet porovnání je v jednotlivých krocích bude C i = N-i a Počet přesunů v i-tém kroku je M i = 3(N-i). Celkem tedy C N = C = N 2 N 2 = M 3( N i i i= 2 i= 2 2 Složitost metody přímým vkládáním je tedy O(N 2 ). M N = 2 N) ALGI 2010/2011 22
Přetřásání (Shaker Sort) Jde o modifikaci algoritmu bublinkového třídění, kdy střídáme porovnávání prvků z hlediska uspořádání. Při průchodu posloupností z jedné strany provádíme porovnávání pro relaci uspořádání, z druhé strany pak pro relaci uspořádání. Ani úpravou bublinkového třídění se nesnížil řádový odhad, složitost zůstává stále O(N 2 ). ALGI 2010/2011 23
Př: Je dána posloupnost čísel 11 3 27 8 50 22 12. Setřiďte ji metodou Shaker Sort. 11 27 8 50 22 3 12 3 11 27 8 50 22 12 3 11 8 27 22 12 50 3 8 11 12 27 22 50 3 8 11 12 22 27 50 3 8 11 12 22 27 50 3 8 11 12 22 27 50 ALGI 2010/2011 24
Rychlé třídění (Quick Sort) Metoda Quick-sort je založena na principu rozdělení tříděného pole na dva disjunktní úseky U 1 a U 2 (v souladu s metodou divide-et-impera) přibližně stejné velikosti, pro které musí platit x U 1, y U 2, platí x y v případě vzestupného třídění. Každá množina se potom rekurzívně dotřídí. Závěrečný syntetizační krok je triviální - spočívá ve spojení setříděných posloupností. ALGI 2010/2011 25
Rychlé třídění (Quick Sort) Algoritmus: Zvolíme prvek x (pivot). Pole začneme prohledávat jak od začátku, tak od konce. Pro všechny prvky a i, které porovnáváme s x směrem od začátku musí platit, že a i < x. Naopak, pro všechny prvky a j, které porovnáváme s x směrem od konce musí platit, že a j > x. Jakmile narazíme na dvojici a i a a j, která nesplňuje výše uvedenou podmínku, prvky a i a a j zaměníme. Takto postupujeme dokud i j. Ve chvíli, kdy i > j platí, že pole je rozděleno do dvou úseků U 1 a U 2, přičemž úsek U 1 zahrnuje prvky od začátku pole až po prvek na pozici j, U 2 pokračuje od i až do konce pole. Úseky U 1 a U 2 opět třídíme metodou Quick Sort. Třídění je ukončeno ve chvíli, kdy délka všech setříděných úseků je 1. ALGI 2010/2011 26
Př: Je dána posloupnost čísel 6 55 12 42 94 18 44 67. Setřiďte ji metodou Quick Sort. 6 55 12 42 94 18 44 67 6 18 12 42 94 55 44 67 6 12 18 42 94 55 44 67 6 12 18 42 94 55 44 67 6 12 18 42 44 55 94 67 6 12 18 42 44 55 67 94 ALGI 2010/2011 27
Rychlé třídění (Quick Sort) Složitost algoritmu: Značně se liší pro nejlepší a nejhorší případ. Složitost není ovlivněna pořadím prvků před tříděním, ale volbou prvku x. Nejlepší případ nastane tehdy, když volba x vždy padne na tzv. medián, který rozdělí pole na dva stejně velké úseky. Počet dělení pro získání úseků délky 1 je pak přibližně log 2 (N) a složitost celé metody je O(N log 2 (N)). Nejhorší případ nastane, když jako prvek x pokaždé zvolíme nejmenší nebo největší prvek tříděného úseku. Pole se vždy rozdělí na dva úseky - jeden úsek bude obsahovat volený prvek x, druhý ostatní prvky tříděného úseku. V tomto případě se bude provádět N-1 dělení, takže výsledná složitost je řádu O(N 2 ). ALGI 2010/2011 28
Rychlé třídění (Quick Sort) Praktické testy ukázaly, že Quick Sort je velice rychlý při třídění rozsáhlých polí, ale zaostává oproti přirozeným algoritmům třídění Insert Sort a Select Sort při třídění malých polí. Ukazuje se, že složitost Quick Sortu má jistou minimální hodnotu, pod kterou i při třídění malého počtu prvků neklesne. Kdežto složitost přirozených algoritmů roste úměrně s počtem tříděných prvků. Jinými slovy do jistého počtu prvků má Quick Sort větší režii (třídí pomaleji) než např. Insert Sort. Tato hranice byla experimentálně stanovena na asi 12 prvků. Vyplatilo by se tedy Quick Sortem třídit rozsáhlé pole, ale jakmile úseky na než se pole dělí budou kratší než zvolená mez (řekněme zmíněných 12 prvků), tento krátký úsek dotřídit Insert Sortem. ALGI 2010/2011 29
Vlastnosti uvedených algoritmů Selection Sort metoda je stabilní a přitozená Bubble Sort metoda je stabilní a přirozená Insertion Sort metoda je stabilní a přirozená Quick Sort - metoda je nestabilní! ALGI 2010/2011 30
Třídění vkládáním s ubývajícím krokem (Shell Sort) Jednoduchý, ale přitom geniální algoritmus popsal D. L. Shell v roce 1959, když navrhl využít třídění vkládáním ve více chodech. V i-tém chodu se třídí prvky ležící ve vzdálenosti h i, pro i=t, t-1,,0, h i+1 > h i, h 1 = 1, t > 0. Číslo h i se nazývá i-tý krok metody. Takto dostaneme v závislosti na volbě kroků celou třídu třídících algoritmů. Tyto algoritmy fungují efektivně, protože v počátečních chodech se třídí relativně krátké posloupnosti a v dalších chodech se třídí delší, ale utříděnější posloupnosti. ALGI 2010/2011 31
Př: Je dána posloupnost čísel 44 18 12 42 94 55 6 67. Setřiďte ji metodou Shell Sort 44 55 12 42 94 18 6 67 44 18 6 42 94 55 12 67 44 18 6 42 94 55 12 67 6 18 12 42 44 55 94 67 6 18 12 42 44 55 94 67 6 12 18 42 44 55 67 94 ALGI 2010/2011 32
Shell Sort Intuitivně je zřejmé, že složitost Shellova algoritmu bude záviset na volbě posloupnosti kroků. Mezi nejznámější návrhy patří tyto posloupnosti kroků: A. h 1 =1, h i+1 =2*h i +1 B. h 1 =1, h 2 =2, h i+1 =2*h i-1 (pro i > 2), O(N (log N) 2 ). C. h 1 =1, h i+1 =3*h i +1 (364, 121, 40, 13, 4, 1 pro 1000 prvků), O(N 3/2 ). Podrobná matematická analýza volby optimální posloupnosti však patří k nevyřešeným problémům. Jsou známé jen některé částečné výsledky. ALGI 2010/2011 33
Poznámka Algoritmy asociativního třídění používají pro určení pozice prvku v tříděné množině S jen relativní hodnoty prvků, které určují vzájemným porovnáváním těchto prvků. Algoritmy adresního třídění (viz dále) využívají jednoznačný vztah mezi absolutními hodnotami prvků z U a jejich pozicí v uspořádané množině. Pro výpočet tohoto vztahu můžeme použít libovolné operace mimo porovnání tříděných prvků. ALGI 2010/2011 34
Adresní třídící algoritmy Tyto algoritmy nepoužívají při své činnosti žádnou preferovanou operaci. Proto za míru časové efektivnosti zvolíme celkový počet operací vykonaných po dobu třídění. Adresní třídění se podobá uklízení např. rozházených dětských hraček: když o každé hračce víme, na které místo patří, stačí ji jen vzít a dát na své místo. ALGI 2010/2011 35
Přihrádkové třídění Přihrádkové třídění je základním algoritmem adresního třídění. Většinou slouží jako základ pro konstrukci složitějších algoritmů adresního třídění. Nechť a π(1), a π(2),...,a π(n) je posloupnost celých čísel z ohraničeného univerza U={0,,m-1} (některá z čísel a i mohou být stejná). Když m není příliš veliké, potom je možné posloupnost efektivně utřídit touto metodou: ALGI 2010/2011 36
Přihrádkové třídění Algoritmus: 1. Inicializace: inicializuj m prázdných seznamů (přihrádek), pro každé číslo i {0,,m-1} jeden seznam; 2. Distribuce: čti posloupnost zleva doprava, a prvek a i umísti do a i -tého seznamu, na jeho konec (tj. seznamy se chovají jako fronty); 3. Zřetězení: zřetězit všechny seznamy tak, že začátek (i+1)-ního seznamu se připojí na konec i- tého. ALGI 2010/2011 37
Přihrádkové třídění Tak vznikne jediný seznam obsahující prvky v utříděném pořadí. Protože jeden prvek je možné zařadit do i-tého seznamu v konstantním čase, n prvků v čase O(n). Zřetězení m seznamů si vyžaduje čas O(m), takže celková složitost přihrádkového třídění je O(m+n). Tento druh třídění se používá zejména tehdy, když m << n. Potom je jeho složitost lineární. Třídění sice není in situ, ale je stabilní. ALGI 2010/2011 38
Přihrádkové třídění - příklad Mějme například realizovat funkci, která načte jednotlivé znaky ze souboru InputName a vypíše je setříděné do souboru OutputName. Celý problém lze naprogramovat velice jednoduše využitím zjednodušené verze přihrádkového třídění. Vytvoříme pole 256 počítadel - pro každý znak jedno - na počátku je nastavíme na 0. Potom čteme vstupní soubor a příslušné počítadlo inkrementujeme. Nakonec vypíšeme do výstupního souboru tolik znaků, na kolik jsou jednotlivá počítadla nastavena, to znamená, že nejprve vypíšeme například 20 znaků a, potom 10 znaků c, 1 znak f atd. ALGI 2010/2011 39
Přihrádkové třídění - příklad Mějme dánu posloupnost písmen s o r t i n g e x a m p l e Po setřídění dostaneme posloupnost a e e g i l m n o p r s t x ALGI 2010/2011 40
Třídění podle základu (Radix Sort) Klíče užívané k definování pořadí záznamů jsou v mnoha případech velice komplikované. Například klíče užívané pro třídění v katalozích knihoven. Proto je vhodné postavit třídicí metody na porovnání dvou klíčů a výměně dvou záznamů. Pro mnoho aplikací je možno využít faktu, že klíč lze považovat za číslo jistého rozsahu. Třídící metoda založená na této myšlence se nazývá Radix Sort. Tento algoritmus neporovnává dva klíče, nýbrž zpracovává a porovnává části klíčů. ALGI 2010/2011 41
Třídění podle základu (Radix Sort) Radix Sort považuje klíče za čísla zapsaná v číselné soustavě o základu M (radix) a pracuje s jednotlivými číslicemi. Představme si úředníka, který má setřídit hromadu karet, přičemž na každé kartě je natištěno tříciferné číslo. Jeden z rozumných postupů je asi tento: vytvořit deset hromádek, na první dávat karty s čísly menšími než 100, na druhou karty s čísly 100 až 199 atd. Každou z těchto deseti hromádek pak znovu roztřídit stejným způsobem nebo pokud je na hromádce karet málo, setřídit je jednoduchým způsobem. Popsaná metoda, je jednoduchou ukázkou Radix Sortu o základě M=10. Pro počítač je logicky lepší pracovat se základem M=2. ALGI 2010/2011 42
Př.: Je dána posloupnost COW DOG SEA RUG ROW MOB BOX TAR BAR EAR TAB DIG BIG TEA NOW FOX. Setřiďte ji metodou Radix Sort Po 1. kroku setřídění podle 1.znaku (výpis kromě prázdných přihrádek) B: BOX BAR BIG C: COW D: DOG DIG E: EAR F: FOX M: MOB N: NOW R: RUG ROW S: SEA T: TAR TAB TEA Po 2.kroku setřídění podle 2. znaku : B: BAR BIG BOX C: COW D: DIG DOG E: EAR F: FOX M: MOB N: NOW R: ROW RUG S: SEA T: TAR TAB TEA ALGI 2010/2011 43
Po 3. kroku setřídění podle 3. znaku: B: BAR BIG BOX C: COW D: DIG DOG E: EAR F: FOX M: MOB N: NOW R: ROW RUG S: SEA T: TAB TAR TEA BAR BIG BOX COW DIG DOG EAR FOX MOB NOW ROW RUG SEA TAB TAR TEA ALGI 2010/2011 44
Radix sort Princip implementace: Předpokládejme, že přeskupujeme záznamy v poli tak, že záznamy jejichž klíče začínají bitem 0 předcházejí záznamy s klíči začínajícími bitem 1. Tato úvaha vede na rekurzivní třídící algoritmus typu QuickSort: jestliže jsou dvě části pole setříděny, potom je setříděno i celé pole. Při výměnách záznamů v poli postupujeme zleva a hledáme klíč začínající na 1, stejně tak zprava hledáme klíč začínající na 0. Tyto záznamy vyměníme a pokračujeme dokud se indexy testovaných záznamů uprostřed pole nepřekříží. Tato implementace je velice podobná QuickSortu, s tím rozdílem, že jako pivot je použito číslo 2 b místo nějakého prvku z pole. ALGI 2010/2011 45
Radix sort Složitost: určení složitosti v porovnání s asociatvními algoritmy není tak jednoduché. Více než počet klíčů (vstupních dat) nás musí zajímat počet bajtů klíče a základu (čísla 2 b ). Nejhorší případ znamená prozkoumat všechny bajty všech klíčů. ALGI 2010/2011 46