Předmět: Algoritmizace praktické aplikace Vytvořil: Roman Vostrý Zadání: Vytvoření funkcí na stromech (reprezentace stromu haldou). Zadané funkce: 1. Počet vrcholů 2. Počet listů 3. Součet 4. Hloubka 5. Šířka Halda (heap) Má tvar binárního stromu. Její výhodou je algoritmická jednoduchost a možnost snadné realizace v poli, známe-li horní odhad maximálního počtu prvků v haldě. Halda je binární strom, ve kterém jsou splněny následující podmínky: 1. V každé hladině od první až do předposlední je maximální možný počet uzlů, tzn. v k-té hladině je 2 k-1 uzlů. 2. V poslední hladině jsou všechny uzly umístěny co možná nejvíce vlevo, tzn. procházíme-li uzly předposlední hladiny zleva doprava, nejprve má několik z nich (popř. žádný) dva následníky, pak může být (ale nemusí) jeden uzel s jedním následníkem a zbývající uzly předposlední hladiny následníky nemají. 3. Pro každý uzel platí, že hodnota v něm uložená je menší než hodnota uložená v jeho libovolném následníkovi. Ze třetí vlastnosti přímo vyplývá, že v kořeni haldy je umístěna nejmenší hodnota.
1. Počet vrcholů stromu Počet vrcholů zjistíme pomocí postupného průchodu polem a přičítání výsledku. Použijeme k tomu algoritmus if (p[2*i]>0) or (p[2*i+1]>0) or (p[i]>0) then result:=result+1; Popis algoritmu: Pokud kořen, levý, nebo pravý následník je větší než nula, tzn. že vrchol existuje, pak se inkrementuje počet vrcholů. function Pocet_vrcholu(i:Integer):Integer; for i:=1 to StrToInt(Edit1.Text) do if (p[2*i]>0) or (p[2*i+1]>0) or (p[i]>0) then result:=result+1; 2. Počet listů Počet listů zjišťujeme opět průchodem pole. Použijeme algoritmus if (p[i] > 0) and (p[2*i]=0) and (p[2*i+1]=0) then result:=result+1; Popis algoritmu: Pokud je hodnota vrcholu větší než nula a jeho levý a současně i pravý následník je roven nule, tzn. že neexistuje, pak to znamená, že se jedná o list - počet listů se inkrementuje o 1.
function Pocet_listu(i:Integer):Integer; if (p[i] > 0) and (p[2*i]=0) and (p[2*i+1]=0) then result:=result+1; 3. Součet hodnot vrcholů Zatím jsme pracovali pouze s indexy pole a stromu. Nyní sečteme vlastní hodnoty vrcholů. Nejdříve si omezíme velikost sčítaného pole. if p[i] > 0 then result:=i; Projdeme celé pole a zjistíme největší index prvku v poli, nebo-li také nejhlubší prvek stromu, který existuje. To znamená, že je větší než nula. Toto číslo dosadíme za j a podle for i:=1 to j do result:=result+p[i]; sčítáme hodnoty jednotlivých prvků pole. function Soucet(i:Integer):Integer; if p[i] > 0 then result:=i; j:=result; for i:=1 to j do result:=result+p[i];
4. Hloubka stromu Znovu si příkazem if p[i] > 0 then result:=i; najdeme nejhlubší prvek stromu. Toto číslo pak dělíme dvěma, výsledek dosadíme místo i a pokračujeme tak dlouho, dokud i>0. Počet všech dělení minus 1 nám pak vrací výsledek funkce - hloubku stromu. Jako počáteční hodnotu výsledku musíme udat -1, protože první hladina má hodnotu 0. function hloubka(i: Integer): Integer; if p[i] > 0 then result:=i; i:=result; result:=-1; while i>0 do i:=i div 2; result:=result +1; 5. Počet vrcholů na úrovni Počet vrcholů na úrovni se zjistí funkcí urovne a funkcí hloubka. Nejdříve si program zjistí hloubku stromu a tu dosadí do příkazu for l:=0 to hloubka(u) do Pokud je např. hloubka stromu 2, výsledný řádek programu bude vypadat takto: for l:=0 to 2 do
Pak pokračuje vlastní funkcí. Nejprve začne s hodnotou 0, což odpovídá hloubce stromu 0, takže strom obsahuje pouze kořen. V úvodu funkce je dáno, že pokud se i = 0, výsledek je 1, funkce končí a vrací výsledek 1. if i=0 then result:=1; Pak začne prohledávat úroveň 1. Program zjistí, existuje-li levý následník, if p[2*q]>0 then result:=result+urovne(i-1,2*q); vrátí se o úroveň níže, tzn. do úrovně 0, která je zadána výsledkem 1. Pak zjišťuje existenci pravého následníka if p[2*q+1]>0 then result:=result+urovne(i-1,2*q+1); a pokud existuje, vrací se opět o úroveň níž a k výsledku připočítá opět 1. Takže konečný výsledek je 2. Pokračuje dál a prohledává druhou úroveň. Znova začíná od kořene, zjistí, že levý následník existuje a znovu volá rekurzivně funkci s tím, že jako kořen dosadí pole s indexem 2*q. Opět zjišťuje přítomnost následníků a připočítává je do výsledku. Pak prohledá stejným způsobem i pravou stranu stromu. function Urovne(i,q:integer):Integer; if i=0 then result:=1 else if p[2*q]>0 then result:=result+urovne(i-1,2*q); if p[2*q+1]>0 then result:=result+urovne(i-1,2*q+1);
6. Šířka stromu Tato funkce pracuje s funkcí urovne a funkcí hloubka, kde vlastně zjišťuje počet vrcholů na úrovních a největší počet vrcholů vrací jako výsledek šířky stromu. function sirka(i:integer): Integer; var w, p: Integer; for w:=0 to hloubka(u) do p:=urovne(w, 1); if p>result then result:=p Celý program: V programu je procedura na vytvoření pole, grafické znázornění stromu a vlastní funkce pro operace na stromě. {$R *.dfm} var p: array [1..100] of integer; i,u,j: Integer; procedure TForm1.Button1Click(Sender: TObject); var i:integer; p[i]:=0; for i:=1 to StrToInt(Edit1.Text) do p[i]:=2*i; procedure TForm1.Button2Click(Sender: TObject); procedure Kresli(i, x, y, sirka: Integer);
sirka:=sirka div 2; if p[2*i]<>0 then Image1.Canvas.MoveTo(x, y); Image1.Canvas.LineTo(x-sirka, y+30); Kresli(2*i, x-sirka, y+30, sirka) if p[2*i+1]<>0 then Image1.Canvas.MoveTo(x, y); Image1.Canvas.LineTo(x+sirka, y+30); Kresli(2*i+1, x+sirka, y+30, sirka) Image1.Canvas.TextOut(x-5, y-8, IntToStr(p[i])); Image1.Canvas.Brush.Color:=clWhite; Image1.Canvas.Brush.Style:=bsSolid; Image1.Canvas.Rectangle(0, 0, Image1.Width, Image1.Height); Kresli(1, Image1.Width div 2, 30, Image1.Width div 2) procedure TForm1.Button3Click(Sender: TObject); function Pocet_vrcholu(i:Integer):Integer; for i:=1 to StrToInt(Edit1.Text) do if (p[2*i]>0) or (p[2*i+1]>0) or (p[i]>0) then result:=result+1; function Pocet_listu(i:Integer):Integer; if (p[i] > 0) and (p[2*i]=0) and (p[2*i+1]=0) then result:=result+1; function Soucet(i:Integer):Integer; if p[i] > 0 then result:=i; j:=result;
for i:=1 to j do result:=result+p[i]; function hloubka(i: Integer): Integer; if p[i] > 0 then result:=i; i:=result; result:=-1; while i>0 do i:=i div 2; result:=result +1; function Urovne(i,q:integer):Integer; if i=0 then result:=1 else if p[2*q]>0 then result:=result+urovne(i-1,2*q); if p[2*q+1]>0 then result:=result+urovne(i-1,2*q+1); function sirka(i:integer): Integer; var w, p: Integer; for w:=0 to hloubka(u) do p:=urovne(w, 1); if p>result then result:=p var l:integer; Memo1.Lines.Clear;
Memo1.Lines.Add('Počet vrcholů je : '+IntToStr(Pocet_vrcholu(u))); Memo1.Lines.Add('Počet listů je : '+IntToStr(Pocet_listu(u))); Memo1.Lines.Add('Součet prvků je : '+IntToStr(Soucet(u))); Memo1.Lines.Add('Hloubka stromu je : '+IntToStr(Hloubka(u))); Memo1.Lines.Add('Šířka stromu je : '+IntToStr(Sirka(u))); for l:=0 to hloubka(u) do Memo1.Lines.Add('Na '+IntToStr(l)+' úrovni je vrcholů : '+IntToStr(urovne(l,1))); end.