C/C++ & Visual C++DatovΘ struktury a algoritmy (14.) |
|
┌vodem | DatovΘ struktury | Kurz DirectX | Downloads | Otßzky a odpov∞di | 2001 | 2002 | 2003 | 2004 |
|
Minule jsme si ukßzali metody, kter²mi lze navÜtφvit ka₧d² uzel stromu, byly to metody preorder, inorder a takΘ postorder. VÜechny tyto metody prochßzely strom do hloubky. V dneÜnφm pokraΦovßnφ se podφvßme na pr∙chod stromem do Üφ°ky. Teorie je velice p∞knß v∞c, ale lepÜφ jsou praktickΘ ukßzky vyu₧itφ pr∙chodu stromem a tak se i my podφvßme na dva p°φklady. Jeden bude dnes a na ten druh² se podφvßme p°φÜt∞. 14.1. Pr∙chod stromem do Üφ°kyOp∞t se jednß o ·lohu, kdy je naÜφm cφlem navÜtφvit vÜechny uzly stromu. U metod, se kter²mi jsme se seznßmili minule, jsme postupovali do hloubky, vyÜli jsme z ko°enu a prochßzeli jsme nap°φklad jeho lev²m podstromem, a₧ jsme se dostali k list∙m stromu. U pr∙chodu do Üφ°ky prochßzφme jednotlivΘ hladiny stromu. Jako prvnφ tedy navÜtφvφme op∞t ko°en, potΘ se podφvßme na vÜechny jeho nßsledovnφky a pokraΦujeme a₧ op∞t a₧ k list∙m. Navφc volφme sm∞r zleva doprava. U prochßzenφ do hloubky, tedy jejφ nerekurzivnφ verze, jsme vyu₧ili datovΘ struktury zßsobnφku. Pro realizaci pr∙chodu do Üφ°ky vyu₧ijeme frontu, kterou op∞t p°epφÜeme do dynamickΘ reprezentace, abychom mohli prochßzet libovoln∞ rozsßhlΘ stromy. Nejprve vlo₧φme do fronty uzel a p°i ka₧dΘm pr∙chodu z fronty jeden uzel vyjmeme a zpracujeme ho. PotΘ vlo₧φme do fronty nßsledovnφky, pokud n∞jakΘ mß. Jestli₧e je nßsledovnφku vφce, pak je vlo₧φme v po°adφ zleva doprava. FunkΦnost, jak jsme si ji popsali v²Üe, pak zajistφ ji₧ fronta. Nejprve si ukß₧eme implementaci fronty: #ifndef CDYNFRONTA_H Pou₧φvßme ukazatel na konec i zaΦßtek fronty pro urychlenφ prßce. Pokud bychom m∞li ukazatel jen na zaΦßtek, bylo by p°i ka₧dΘm vklßdßnφ nutnΘ projφt frontou prvk∙ od zaΦßtku a nelΘzt poslednφ prvek. Nynφ si ukß₧eme metodu vykonßvajφcφ pr∙chod stromem do Üφ°ky: template<class T> void CBinStrom<T>::PruchodStromem5() P°idal jsem podmφnku pro ov∞°enφ, zda-li je strom prßzdn², jinak bychom uklßdali do fronty nesmyslnou hodnotu a doÜlo by k vyvolßnφ v²jimky. V minulΘm dφlu tato podmφnka chyb∞la u nerekurzivnφho pr∙chodu stromem do hloubky. P°ipomeneme si, jak nßÜ strom vypadß a ukß₧eme si v²stup programu po zavolßnφ metody PruchodStromem5():
V²stup programu bude: 8, 5, 9, 4, 7, 13, 11. K≤d naleznete v sekci Downloads (projekt Strom). 14.2. Vyu₧itφ prohledßvßnφ do hloubky a do Üφ°kyUkß₧eme si dva p°φklßdky na vyu₧itφ pr∙chodu stromem, jeden bude vyu₧φvat pr∙chod do hloubky a druh² do Üφ°ky. Pokud budeme programovat nap°φklad n∞jakou hru, pak se budeme na poΦßtku nachßzet v n∞jakΘm stavu. R∙zn²mi p°echody do dalÜφch stav∙ se budeme sna₧it dojφt a₧ k °eÜenφ ·lohy. ╪eÜenφ ·lohy m∙₧e b²t jednoznaΦnΘ nebo m∙₧e b²t vφce stav∙, kterΘ jsou °eÜenφm, ·loha je pak mnohoznaΦnß. Zßkladnφmi ·lohami, kterΘ se uvßd∞jφ u pr∙chod∙ jsou logickΘ ·lohy na Üachovnici. Po ka₧dΘm provedenΘm tahu se nßm nask²tß vφce mo₧nostφ na dalÜφ tah, p°iΦem₧ nikdy nevφme, a samoz°ejm∞ to nelze ani p°edem spoΦφtat, jestli nßmi vybran² tah povede ke sprßvnΘmu °eÜenφ. Jako prvnφ ·lohu budeme °eÜit problΘm, jak kon∞m umφst∞n²m na libovolnΘm mφst∞ Üachovnice proskßkat vÜechna pole, navφc budeme chtφt, aby ka₧dΘ pole bylo navÜtφveno pouze jednou. Jako druhou ·lohu si zvolφme nalezenφ nejkratÜφ cesty kon∞m mezi dv∞ma libovoln²mi mφsty na Üachovnici. Nejprve si tedy povφme pravidla Üachu. K∙≥ se pohybuje do tvaru pφsmene L, pohyb lze tedy vykonat o jedno pole v jednom sm∞ru a potΘ o dv∞ pole ve sm∞ru na n∞j kolmΘm. Dßma ohro₧uje pole, kterß le₧φ vlevo, vpravo, naho°e a dole od nφ a navφc jeÜt∞ pole na diagonßlßch. Vrhn∞me se nynφ na navr₧enφ datov²ch struktur pro pohyby kon∞m. Pohyby kon∞, je jich celkem osm, ulo₧φme do pole struktur. Tyto struktury budou obsahovat prßv∞ sou°adnice mo₧n²ch skok∙ kon∞m. Vzhledem k tomu, ₧e strom vÜech mo₧n²ch tah∙ kon∞m by byl velice rozsßhl², budeme vytvß°et pr∙b∞₧n∞ s ka₧d²m tahem. Tedy v pam∞ti poΦφtaΦe se nikdy nebude vyskytovat kompletnφ strom. Nynφ si rozebereme p°φklady podrobn∞ji a zvlßÜ¥ a to v po°adφ v jakΘm jsme si ukßzali algoritmy pr∙chodu. 14.2.1. Prohledßvßnφ do hloubky┌loha o projitφ celΘho hracφho pole kon∞m vede na pr∙chod stromem do hloubky. Vrcholy stromu majφ v²znam jednotliv²ch situacφ na hernφm poli. Jako ko°en mßme stav, kdy k∙≥ stojφ na urΦitΘm mφst∞. V ka₧dΘm nßsledujφcφm tahu mßme podle pozice kon∞ a₧ osm mo₧nostφ, jak lze kon∞m tßhnout. MenÜφ poΦet mo₧nostφ bude jednak u mφst kterß jsou blφzko kraj∙m Üachovnice, ale s postupn²m prochßzenφm Üachovnice i u vnit°nφch polφ, abychom vyhov∞li podmφnce o pouze jednΘ nßvÜt∞v∞ polφΦka (a hned s prvnφm pohybem bude maximßlnφ poΦtu mo₧n²ch tah∙ jen 7). Situace, kdy k∙≥ nem∙₧e pokraΦovat, a¥ u₧ proto, ₧e dosßhl °eÜenφ ·lohy nebo nem∙₧e splnit pravidla pro pohyb v dalÜφm kroku, jsou reprezentovßna listy pomyslnΘho stromu. Tak₧e nejprve si vytvo°φme strukturu pro tahy kon∞m a definujeme n∞kterΘ konstanty: #define SirkaPole 8 Na po°adφ tah∙ v poli mo₧n²ch tah∙ nezßle₧φ, nebo¥ °eÜenφ nalezneme ve vÜech p°φpadech. OvÜem n∞kterΘ kombinace mohou trvat velmi dlouho, proto₧e v nep°φzniv²ch p°φpadech budeme muset projφt velkou Φßst pomyslnΘho stromu. Tahy kon∞m budeme provßd∞t na Üachovnici, definovanΘ jako pole cel²ch Φφsel. Dßle napφÜeme metody pro tisk hracφho pole a pro jeho inicializaci. Hodnota -1 bude znamenat, ₧e pole jeÜt∞ nebylo kon∞m navÜtφveno. Ostatnφ Φφsla znamenajφ, v kterΘm tahu k∙≥ danΘ pole navÜtφvil a Φφslovat zaΦφnßme od 0: int Sachovnice[SirkaPole][VyskaPole]; Nynφ u₧ k vlastnφ funkci, kterß bude provßd∞t jednotlivΘ tahy. Jejφmi parametry budou Φφslo tahu, pozice kon∞ a odkazem p°edßvanß prom∞nnß, kterß signalizuje, zda je cesta nalezena, nebo ne: void UdelejTah(int _iCislo, int _PozX, int _PozY, bool *_bTahOK) Funkce jednoduÜe provßdφ tahy podle po°adφ v poli mo₧n²ch tah∙. K p∙vodnφ pozici kon∞, kterß je p°edßna jako parametr p°iΦte pohyb kon∞. Pokud toto pole le₧φ uvnit° Üachovnice, tak tento tah provede. PoslΘze ov∞°φ, zda nebylo dosud provedeno Üφ°ka * v²Üka zmenÜenß o 1 tah∙, co₧ by znamenalo, ₧e celß Üachovnice je obsazena. Pokud ne, zkusφ ud∞lat dalÜφ tah. P°es parametr se vrßtφ hodnota true nebo false podle toho, zda tato posloupnost tah∙ vede k °eÜenφ. Jestli tomu tak nenφ, pak jednoduÜe tah vrßtφme nastavenφm polφΦka na -1 a p°ejdeme k dalÜφmu pr∙chodu cyklem - zkusφme z pole mo₧n²ch tah∙ nßsledujφcφ tah. Funkce main() pak vypadß nßsledovn∞: int main(int argc, char* argv[]) Zeptßme se u₧ivatele na pozici kon∞, velikost Üachovnice se dß m∞nit jen pomocφ konstant a tedy i nßslednΘ rekompilace. Nebyl by vÜak problΘm zm∞nit statickou alokaci na dynamickou. Ov∞°φme, zda pozice kon∞ le₧φ uvnit° Üachovnice. Pokud ano, pak nastavφme prvnφ pole jako v²chozφ (dßme na n∞j 0). PotΘ u₧ jen zavolßme v²Üe popsanou rekurzivnφ metodu. K≤d naleznete v sekci Downloads (projekt PruchodKonem1). 14.3. Co bude p°φÜt∞Jak jsme si slφbili v ·vodu, v p°φÜtφm dφlu se podφvßme na pr∙chod stromem do Üφ°ky v podob∞ p°φkladu. Mo₧nß si jeÜt∞ ukß₧eme jednu velice znßmou ·lohu na pr∙chod stromem do Üφ°ky. A pak budeme porovnßvat oba algoritmy z hlediska pou₧itelnosti. T∞Üφm se nashledanou u dalÜφho dφlu. |
|