ALG 04 Zsobnk Fronta Operace Enqueue Dequeue Front
ALG 04 Zásobník Fronta Operace Enqueue, Dequeue, Front, Empty. . Cyklická implementace fronty Průchod stromem do šířky Grafy průchod grafem do šířky průchod grafem do hloubky Ořezávání a heuristiky 2011 A 4 B 33 ALG-04 1
Zásobník / stack Prvky se před zpracováním vkládají na vrchol zásobníku. Vrchol / top 84 75 60 1373 84 14 55 11 71 08 44 23 74 Prvky se odebírají z vrcholu zásobníku a pak se zpracovávají. Operace Vlož na vrchol Odeber z vrcholu Čti začátek Je prázdný? 2011 Push Pop Top Empty A 4 B 33 ALG-04 2
Fronta / queue 8475 Čelo / front Konec / tail 60 1373 84 14 55 11 71 08 44 23 Prvky se před zpracováním vkládají na konec fronty. 74 Prvky se odebírají z čela fronty a pak se zpracovávají. Operace Vlož na konec Enqueue / Insert. Last / Push. . . Odeber ze začátku Dequeue / del. Front / Pop. . . Čti začátek Front / Peek. . . Je prázdná? Empty 2011 A 4 B 33 ALG-04 3
Fronta Čelo Jednoduchý příklad života fronty 2011 Konec Prázdná Vlož(24) 24 Vlož(11) 24 11 Vlož(90) 24 11 90 Odeber() 11 90 Vlož(43) 11 90 43 Odeber() 43 Vlož(79) 43 79 A 4 B 33 ALG-04 4
Cyklická implementace fronty polem Čelo Konec Prázdná fronta v poli pevné délky 24 11 90 43 70 Vlož 24, 11, 90, 43, 70. Odeber, odeber. 2011 43 70 Vlož 10, 20. 20 43 70 10 Odeber, odeber. 20 10 Vlož 55, 22, 33. 20 55 22 33 10 Odeber, odeber. 55 22 33 A 4 B 33 ALG-04 5
Cyklická implementace fronty polem Index/ukazatel konce fronty ukazuje na první volnou pozici za posledním prvkem fronty. Index/ukazatel čela fronty ukazuje na první obsazenou pozici. Pokud oba ukazují tamtéž, fronta je prázdná. class Queue { Node q []; int size; int front; int tail; Queue(int qsize) { size = qsize; q = new Node[size]; front = 0; tail = 0; } boolean Empty() { return (tail==front); } 2011 void Enqueue(Node node) { if ((tail+1 == front) || (tail-front == size-1)). . . // queue full, fix it q[t++] = node; if (tail==size) tail=0; } Node Dequeue() { Node n = q[front++]; if (front==size) front=0; return n; } } // end of Queue A 4 B 33 ALG-04 6
Průchod stromem do šířky Strom s naznačeným směrem průchodu 30 21 71 12 03 52 13 82 63 54 Pořadí uzlů 73 93 64 30 21 71 12 52 82 03 13 63 73 93 54 64 Struktura stromu ani rekurzivní přístup tento průchod nepodporují. 2011 A 4 B 33 ALG-04 7
Průchod stromem do šířky Inicializace Vytvoř prázdnou frontu 30 21 12 03 71 52 13 63 54 Výstup 82 73 Do fronty vlož kořen stromu 93 30 64 2. Čelo Konec Hlavní cyklus Dokud není fronta prázdná, opakuj: 1. Odeber první uzel z fronty a zpracuj ho. 2. Do fronty vlož jeho potomky, pokud existují. 2011 A 4 B 33 ALG-04 8
Průchod stromem do šířky x 1. x = Odeber(), tisk (x. key). 30 12 03 71 52 13 63 73 2. Vlož(x. left), vlož(x. right). *) 93 64 54 Výstup 30 82 21 30 x 1. x = Odeber(), tisk(x. key). 30 21 12 03 71 2011 71 52 13 21 82 63 54 Výstup 71 73 *) pokud existuje 21 93 2. Vlož(x. left), vlož(x. right). *) 64 71 12 30 21 A 4 B 33 ALG-04 9
Průchod stromem do šířky 30 12 03 71 52 13 Výstup 12 71 82 63 73 2. Vlož(x. left), vlož(x. right). *) 93 64 54 30 21 71 12 x 12 03 Výstup 2011 71 52 52 13 73 82 12 82 63 82 1. x = Odeber(), tisk(x. key). 30 21 52 *) pokud existuje 21 1. x = Odeber(), tisk (x. key). x 93 2. Vlož(x. left), vlož(x. right). *) 54 64 30 21 71 12 52 A 4 B 33 ALG-04 82 03 13 10
Průchod stromem do šířky 1. x = Odeber(), tisk (x. key). 30 12 03 71 52 13 Výstup 63 73 12 82 Výstup 2011 03 13 63 1. x = Odeber(), tisk(x. key). x 71 52 13 13 2. Vlož(x. left), vlož(x. right). *) 93 54 64 30 21 71 12 52 21 03 52 82 30 03 82 03 73 63 82 82 63 13 *) pokud existuje 21 x 93 2. Vlož(x. left), vlož(x. right). *) 54 64 30 21 71 12 52 82 03 A 4 B 33 ALG-04 13 63 73 93 11
Průchod stromem do šířky 1. x = Odeber(), tisk (x. key). 30 12 03 71 52 13 Výstup 73 03 Výstup 2011 13 63 73 93 x 71 52 13 93 1. x = Odeber(), tisk(x. key). 30 12 73 2. Vlož(x. left), vlož(x. right). *) 93 54 64 30 21 71 12 52 82 03 21 63 03 82 63 13 63 73 93 13 82 63 73 *) pokud existuje 21 x 93 2. Vlož(x. left), vlož(x. right). *) 54 64 30 21 71 12 52 82 03 13 A 4 B 33 ALG-04 63 73 93 12
Průchod stromem do šířky 1. x = Odeber(), tisk (x. key). 30 12 03 71 52 13 Výstup 73 12 Výstup 2011 93 54 64 x 71 52 13 73 1. x = Odeber(), tisk(x. key). 30 03 2. Vlož(x. left), vlož(x. right). *) 93 54 64 30 21 71 12 52 82 03 13 63 21 93 63 82 63 73 93 73 64 73 82 63 54 *) pokud existuje 21 x 93 2. Vlož(x. left), vlož(x. right). *) 54 64 30 21 71 12 52 82 03 13 63 73 A 4 B 33 ALG-04 93 54 64 13
Průchod stromem do šířky 1. x = Odeber(), tisk (x. key). 30 12 03 71 52 13 Výstup 73 12 Výstup 2011 x 71 52 13 64 1. x = Odeber(), tisk(x. key). 30 03 2. Vlož(x. left), vlož(x. right). *) 93 54 64 54 30 21 71 12 52 82 03 13 63 73 93 21 64 93 82 63 54 54 82 63 73 64 *) pokud existuje 21 x 93 2. Vlož(x. left), vlož(x. right). *) 54 64 64 30 21 71 12 52 82 03 13 63 73 93 54 A 4 B 33 ALG-04 14
Průchod stromem do šířky 30 21 12 03 Výstup 71 52 13 x 64 82 63 73 93 2. Vlož(x. left), vlož(x. right). *) 54 64 30 21 71 12 52 82 03 13 63 73 93 54 64 *) pokud existuje 1. x = Odeber(), tisk (x. key). Fronta je prázdná, průchod stromem končí. V neprázdné frontě jsou vždy právě -- některé (třeba všechny) uzly jednoho patra -- a všichni potomci těch uzlů tohoto patra, které už nejsou ve frontě. Někdy jsou ve frontě přesně všechny uzly jednoho patra. Viz výše. 2011 A 4 B 33 ALG-04 15
Průchod stromem do šířky void list. Breadth (Node node) { if (node == null) return; Queue q = new Queue(); // init q. Enqueue(node); // root into queue while (!q. Empty()) { node = q. Dequeue(); print(node. key); // process node if (node. left != null) q. Enqueue(node. left); if (node. right != null) q. Enqueue(node. right); } } 2011 A 4 B 33 ALG-04 16
Grafy • graf je uspořádaná dvojice o množiny vrcholů o množiny hran Va E c G = (V, E) e • • příklad: • V = {a, b, c, d, e} • E = {{a, b}, {b, e}, {b, c}, {c, e}, {e, d}} 2011 b a d A 4 B 33 ALG-04 17
Grafy - orientovanost • neorientovaný graf o hrana je neuspořádaná dvojice vrcholů • E = {{a, b}, {b, e}, {b, c}, {c, e}, {e, d}} • orientovaný graf o hrana je uspořádaná dvojice vrcholů • E = {{a, b}, {b, e}, {b, c}, {c, e}, {e, d}} b a c c e e d 2011 b a d A 4 B 33 ALG-04 18
Grafy – matice sousednosti G = (V, E) je graf s n vrcholy • Označme vrcholy v 1, …, vn (v nějakém libovolném pořadí) • Nechť • Matice sousednosti grafu G je čtvercová matice definovaná předpisem 2011 A 4 B 33 ALG-04 19
Grafy – matice sousednosti • pro orientovany graf 2011 a b c d e a 0 1 0 0 0 b 0 0 1 c 0 0 1 d 0 0 0 e 0 0 0 1 0 A 4 B 33 ALG-04 b a c e d 20
Grafy – seznam sousedů G = (V, E) je (ne)orientovaný graf s n vrcholy • Označme vrcholy v 1, …, vn (v nějakém libovolném pořadí) • Seznam sousedů grafu G je pole P ukazatelů velikosti n • kde P[i] ukazuje na spojový seznam vrcholů, se kterými je vrchol vi spojen hranou • Nechť 2011 a b b a c c b e b a e c d e e c e b d d A 4 B 33 ALG-04 21
Průchod grafem do hloubky Inicializace Vytvoř prázdný zásobník a b c d e Do zásobníku vlož počáteční uzel a Výstup Vrchol Hlavní cyklus Dokud není zásobník prázdný, opakuj: 1. Odeber první uzel za zásobníku a zpracuj ho. 2. Do zásobníku vlož jeho sousedy, pokud existují. 2011 A 4 B 33 ALG-04 22
Průchod grafem do hloubky 1. node = Pop(), print (node. key). a node b a c 2. e d Push(node. Neighbors()). b Výstup d a 1. node = Pop(), print(node. key). a node b b c e d d 2. Push(node. Neighbors()). c Výstup 2011 e a d ab A 4 B 33 ALG-04 23
Průchod grafem do hloubky 1. a node b node = Pop(), print(node. key). e 2. e d Push(node. Neighbors()). b a node b e a d node = Pop(). e e a d b c e d 2011 e abc 1. Výstup d c c Výstup a abc A 4 B 33 ALG-04 24
Průchod grafem do hloubky 1. node = Pop(), print(node. key). a node b e 2. e d Push(node. Neighbors()). b a node b c e a d node = Pop(). d c e a d b c e d 2011 d abce 1. Výstup d e c Výstup a abce A 4 B 33 ALG-04 25
Průchod grafem do hloubky 1. node = Pop(), print(node. key). a node b c 2. e d e c e a d abced node = Pop(). 1. a node b e c e a d a c e d 2011 d Push(node. Neighbors()). a Výstup a d c Výstup e …. Pop() KONEC abced A 4 B 33 ALG-04 26
Průchod grafem do hloubky void graph. Depth (Node start. Node) { Set visited = new Set(); Stack q = new Stack (); // init q. Push(start. Node); // start. Node into queue while (!q. Empty()) { node = q. Pop(); if (node not in visited) { visited. add(node); print(node. key); // process node forall x in node. Neighbors() q. Push(x); } } 2011 A 4 B 33 ALG-04 27
Průchod grafem do hloubky – urychlení void graph. Depth 2 (Node start. Node) { Set touched = new Set(); Stack q = new Stack(); // init q. Push(start. Node); // start. Node into queue touched. add(start. Node); while (!q. Empty()) { node = q. Pop(); print(node. key); // process node forall x in node. Neighbors() if (x not in touched) { q. Push(x); touched. add(x); } } 2011 A 4 B 33 ALG-04 28
Průchod grafem do šířky Inicializace Vytvoř prázdnou frontu a b c d e Do fronty vlož počáteční uzel a Výstup Čelo Konec Hlavní cyklus Dokud není fronta prázdná, opakuj: 1. Odeber poslední uzel z fronty a zpracuj ho. 2. Do fronty vlož jeho sousedy, pokud existují. 2011 A 4 B 33 ALG-04 29
Průchod grafem do šířky 1. node = Dequeue(), print (node. key). a node b a c 2. Enqueue(node. Neighbors()). e d b Výstup d a 1. node = Dequeue(), print (node. key). a node b d c e d b 2. Enqueue(node. Neighbors()). e Výstup 2011 a b ad A 4 B 33 ALG-04 30
Průchod grafem do šířky 1. node = Dequeue(), print (node. key). a node b c 2. e d Enqueue(node. Neighbors()). a Výstup a node b e e a node = Dequeue(). a c e e a c e d 2011 c adb 1. Výstup a adb A 4 B 33 ALG-04 31
Průchod grafem do šířky 1. node = Dequeue(), print (node. key). a node b a 2. e d Enqueue(node. Neighbors()). b a node b c a c e node = Dequeue(). b d c a c e d 2011 d adbe 1. Výstup e e c Výstup c adbe A 4 B 33 ALG-04 32
Průchod grafem do šířky 1. node = Dequeue(), print (node. key). a node b b 2. e d e b d c a adbec 1. a node b node = Dequeue(). b e b d c a c e d 2011 a Enqueue(node. Neighbors()). b Výstup c c c Výstup d …. Dequeue() KONEC adbec A 4 B 33 ALG-04 33
Průchod grafem do šířky void graph. Breadth (Node start. Node) { Set visited = new Set(); Queue q = new Queue (); // init q. Enqueue(start. Node); // start. Node into queue while (!q. Empty()) { node = q. Dequeue(); if (node not in visited) { visited. add(node); print(node. key); // process node forall x in node. Neighbors() q. Enqueue(x); } } 2011 A 4 B 33 ALG-04 34
Ořezávání • Urychlení prohledávání • Ořezávání neperspektivních větví • Pokud jsme schopni na základě vyhodnocení momentálního stavu zjistit, • že je to stav neperspektivní a • že rozhodně nepovede k řešení úlohy • „odřízneme“ ze stromu celý podstrom momentálního stavu Strom prohledávání Momentální stav 2011 A 4 B 33 ALG-04 35
Příklad ořezávání – magický čtverec • Magický čtverec řádu N o čtvercové schéma čísel velikost Nx. N o obsahuje právě jednou každé celé číslo od 1 do N 2 o součet čísle ve všech řádcích a ve všech sloupcích stejný 2 9 4 • Příklad 7 5 3 6 1 8 • Triviální řešení: generování všech možných rozmístění čísel od 1 do N 2 • Ořezávání: kdykoliv je součet na řádku neperspektivní ½ N 2 (N 2+1) 2 o součet čísel na řádku je ½ N (N +1) o součet všech čísel čtverce je 2011 A 4 B 33 ALG-04 36
Heuristiky • Heuristika je návod, který nám říká, jaký postup řešení úlohy vede obvykle k rychlému dosažení výsledku. • Nezaručuje vždy zrychlení výpočtu. • Heuristika se používá pro stanovení pořadí, • v jakém se zkoumají možné průchody stromem/grafem • Příklad: úloha projít šachovým koněm celou šachovnici Nx. N • účinná heuristika: nejprve se navštíví ta dosud nenavštívená pole, z nichž bude nejméně možností dalšího bezprostředního pokračování cesty koně. • urychlení na šachovnici 2011 8 x 8 až stotisíckrát. A 4 B 33 ALG-04 37
- Slides: 37