C/C++ & Visual C++DatovΘ struktury a algoritmy (11.) |
|
┌vodem | DatovΘ struktury | Kurz DirectX | Downloads | Otßzky a odpov∞di |
|
Uplynul dalÜφ m∞sφc a je tu tedy dalÜφ
dφl kurzu o datov²ch strukturßch. Minule jsme dokonΦili implementaci
obousm∞rnΘho spojovΘho seznamu, mohli jsme tedy nap°φklad na tento
seznam pou₧φt, narozdφl od jeho jednosm∞rnΘho brat°φΦka, algoritmy
t°φd∞nφ bublinkovou metodou a dalÜφ. Dnes se seznßmφme s dalÜφ
strukturou, kterß najde svΘ uplatn∞nφ v mnoha oblastech programovßnφ.
Touto strukturou je strom. My se budeme nejprve zab²vat obecn²m stromem
a pak si ukß₧eme n∞kterΘ specializovan∞jÜφ formy, nap°φklad binßrnφ
vyhledßvacφ strom.11.1 Pojmy a zßkladyStromy jsou, podobn∞ jako lineßrnφ spojovΘ seznamy, slo₧eny z uzl∙ (angl. nodes). Tyto uzly jednak obsahujφ data a pak obsahujφ takΘ ukazatele na dalÜφ uzly. Tφm nßm vznikß rekurzivnφ datovß struktura. Ukß₧eme si grafickou interpretaci obecnΘho stromu:
Pokud si obrßzek obrßtφte, pak uvidφte proΦ tuto datovou strukturu naz²vßme stromem. Uvedeme si n∞kterΘ pojmy, kterΘ se vyskytujφ ve spojitosti se stromy:
Prvky, kterΘ nejsou listy se takΘ n∞kdy oznaΦujφ jako vnit°nφ uzly stromu a listy se n∞kdy oznaΦujφ jako koncovΘ uzly. Typ stromu je pak urΦen tφm, kolik potomk∙ majφ jednotlivΘ uzly. OznaΦme n poΦet potomk∙ uzlu, pak pro:
Pokud polo₧φme n = 1, vidφme, ₧e datovou strukturou, kterou dostaneme je jednosm∞rn² lineßrnφ spojov² seznam. DalÜφ d∙le₧itou v∞cφ, kterou vidφme v diagramu je, ₧e ka₧d² uzel stromu vlastn∞ tvo°φ nov² strom - °φkßme mu podstrom. StaΦφ vzφt uzel 4 a dostßvßme strom s ko°enem 4 a jeho dv∞ma potomky - uzly 6 a 7. Pokud bychom cht∞li, a v naÜφ implementaci se nßm to hodilo, pak je mo₧nΘ do ka₧dΘho uzlu navφc ulo₧it i ukazatel na rodiΦe tohoto uzlu, co₧ by v n∞kter²ch p°φpadech ulehΦilo pr∙chod stromem. Spojov² seznam byla vlastn∞ Φßra, na kterΘ byly ulo₧eny jednotlivΘ uzly - ostatn∞ proto jsme mu takΘ °φkali lineßrnφ. Narozdφl od toho, u strom∙ zavßdφme hladiny. Vφce nßm o tom povφ obrßzek:
Na 0-tΘ hladin∞ le₧φ pouze ko°en a vÜichni jeho potomci majφ hladinu o jedna vyÜÜφ. Jako poΦßteΦnφ hladinu jsme si zvolili 0, nebo¥ pole nßm v naÜem oblφbenΘm C/C++ zaΦφnajφ takΘ od nuly. 11.2 ObecnΘ stromyTo jsou stromy, jejich₧ uzly ukazujφ na nekoneΦn² poΦet dalÜφch uzl∙. A₧ si prohlΘdnete obrßzek, uvidφte, ₧e se v ₧ivot∞ pou₧φvajφ celkem Φasto:
Jak takov²to strom, hlavn∞ s ohledem na nekoneΦn² poΦet potomk∙ jednotliv²ch uzl∙ realizovat? JednoduÜe, staΦφ si na pomoc vzφt spojov² seznam a do ka₧dΘho uzlu stromu umφstit jen odkaz na prvnφho potomka uzlu. Samoz°ejm∞ to nenφ jedinß mo₧nost, lze pou₧φt i dynamicky se zv∞tÜujφcφ pole nebo jinou strukturu. Uzly tedy budou v tomto p°φpad∞ obsahovat dva ukazatele - ukazatel na prvnφho potomka a na uzly na stejnΘ hladin∞ (dalo by se °φci na sourozence). To ovÜem krom∞ ko°ene, kter² bude mφt ukazatel na sourozence s hodnotou NULL. V reßlnΘm problΘmu se nßm m∙₧e takov²to obecn² strom hodit t°eba k rozhodovßnφ um∞lΘ inteligence poΦφtaΦovΘ hry. V uzlu by byla nap°φklad otßzka, zda postava vidφ ·toΦnφka, mo₧nosti by byly ano/ne. V²hodou pak je, ₧e vybrßnφm nap°. mo₧nosti ano vylouΦφme vÜechny otßzky nßsledujφcφ v podstrom∞ ne, Φφm₧ se vyhneme zkoumßnφ mnoha neperspektivnφch otßzek a tedy i ·spo°e Φasu. Zpracovßvat stromy rekurzivn∞ m∙₧eme celkem t°emi zp∙soby. Zpracovßnφm rozumφme provedenφ urΦitΘ operace nade vÜemi uzly stromu. U obecn²ch strom∙ se pou₧φvajφ dv∞ metody, kterΘ nßm zajistφ pr∙chod vÜemi uzly stromu - jsou to pre-order a post-order (t°etφ metoda se naz²vß in-order). O funkci vÜech t∞chto t°φ metod se zmφnφme pozd∞ji. 11.3 Binßrnφ stromy a binßrnφ vyhledßvacφ stromMy se nynφ budeme zab²vat a takΘ implementujeme strom, kter² se pou₧φvß velice Φasto. Je to p°φpad stromu pro n = 2, tedy ka₧d² uzel stromu bude ukazovat na dva dalÜφ uzly - oznaΦme si je t°eba lev² a prav². Datov²m prvkem kter² budeme vklßdat do stromu pak bude Φasto hodnota typu int. Pro vklßdßnφ prvku si zavedeme pravidlo, ₧e pokud je prvek menÜφ ne₧li hodnota v uzlu, pak prvek ulo₧φme do levΘ v∞tve uzlu. V opaΦnΘm p°φpad∞ do pravΘ. Pokud prvek bude ve strom∞ ji₧ obsa₧en, nestane se nic. Strom, kter² spl≥uje tyto specißlnφ podmφnky naz²vßme prßv∞ binßrnφ vyhledßvacφ strom a slou₧φ k rychlΘmu zjiÜt∞nφ, zda je hodnota ve strom∞ ulo₧ena Φi ne. JinΘ u₧itΘ pro binßrnφ stromy je pak reprezentace aritmetickΘho v²razu v pam∞ti poΦφtaΦe, pop°. k implementaci datovΘ struktury nazvanΘ halda, se kterou se setkßme v n∞kterΘm z dalÜφch dφl∙. N∞kdy lidΘ oznaΦujφ binßrnφ stromy jako B-stromy, co₧ ale nenφ sprßvnΘ. B-strom je ·pln∞ jinß datovß struktura, kterß nachßzφ uplatn∞nφ t°eba v souborovΘm systΘmu. Implementujeme si tedy takov² binßrnφ strom: #ifndef BINSTROM_H A nynφ k jednotliv²m metodßm. Jako prvnφ vezmeme metodu pro zjiÜt∞nφ, zda je strom prßzdn², co₧ nastane jen je-li ukazatel na ko°en NULL:
template<class T> bool CBinStrom<T>::JePrazdny() Nynφ metody pro novou inicializaci stromu a tedy i smazßnφ stromu:
template<class T> bool CBinStrom<T>::VytvorPrazdny() Vidφme, ₧e mazßnφ stromu je rekurzivnφ zßle₧itost. Prost∞ sma₧eme levou podv∞tev, pravou podv∞tev a nakonec vlastnφ uzel. Pro jistotu nastavφme uzlu hodnotu NULL. Proto nestaΦφ p°edßvat jako parametr ukazatel - nemohli bychom ho toti₧ v t∞le funkce m∞nit. Nynφ se podφvßme na vklßdßnφ prvku do stromu, kterΘ musφ probφhat podle naÜich pravidel - prvky menÜφ ne₧li prvek v uzlu jdou do levΘho podstromu, prvky v∞tÜφ do pravΘho. Prvky nejsou v seznamu obsa₧eny vφcekrßt ne₧ jednou. Metody budou dv∞, jedna kterß vykonß veÜkerou prßci. Ta umφstφ prvek na sprßvnΘ mφsto ve strom∞ pod prvkem, kter² ji p°edßme jako parametr. Druhß funkce pak u₧ jen zajistφ vlo₧enφ prvku do celΘho stromu:
template<class T> bool CBinStrom<T>::VlozDoStromu(CUzel<T>* &_lpUzel,
const T& _Data) V t∞le funkce op∞t m∞nφme ukazatel p°edan² jako argument, tak₧e pou₧φvßme op∞t referenci na ukazatel. Tato funkce jde samoz°ejm∞, vzhledem k vlastnostem strom∙, napsat takΘ rekurzivn∞. K tomu se dostaneme jeÜt∞ v p°φÜtφm dφlu. A nynφ metoda pro nalezenφ hodnoty v tomto vyhledßvacφm strom∞:
template<class T> CUzel<T>* CBinStrom<T>::NajdiVeStromu(CUzel<T> *_lpUzel,
const T& _Data) K≤d naleznete v sekci Downloads (projekt Strom). 11.4 Co bude p°φÜt∞Tak dnes jsme si ukßzali zßkladnφ implementaci stromu a p°φÜt∞ si ukß₧eme n∞kterΘ nev²hody tΘto implementace. Povφme si o n∞kter²ch vlastnostech strom∙ jako je vyvß₧enost a ·plnost stromu. TakΘ jsme nakousli prochßzenφ vÜemi uzly stromu, ke kterΘmu se p°φÜt∞ vrßtφme a ukß₧eme si jak strom prochßzet do hloubky. U dalÜφho dφlu nashledanou. |
|