Implementace binárního stromu směrníky

Podobné dokumenty
1. Implementace funkce počet vrcholů. Předmět: Algoritmizace praktické aplikace (3ALGA)

1. D Y N A M I C K É DAT O V É STRUKTUR Y

Binární vyhledávací strom pomocí směrníků Miroslav Hostaša L06620

Předmět: Algoritmizace praktické aplikace

Binární vyhledávací stromy

Implementace seznamů do prostředí DELPHI pomocí lineárního seznamu

Algoritmy a datové struktury

Reprezentace aritmetického výrazu - binární strom reprezentující aritmetický výraz

Stromy. Strom: souvislý graf bez kružnic využití: počítačová grafika seznam objektů efektivní vyhledávání výpočetní stromy rozhodovací stromy

Abstraktní datové typy FRONTA

Binární vyhledávací strom. Proč binární? Vyhledávání

1. Převeďte dané číslo do dvojkové, osmičkové a šestnáctkové soustavy: a) b)

Dynamicky vázané metody. Pozdní vazba, virtuální metody

Stromy, haldy, prioritní fronty

STROMOVE ALGORITMY Prohledavani do sirky (level-order) Po vodorovnejch carach fronta

Dynamické datové struktury III.

Programování v C++ 1, 16. cvičení

5 Rekurze a zásobník. Rekurzivní volání metody

Cílem kapitoly je seznámit studenta se seznamem a stromem. Jejich konstrukci, užití a základní vlastnosti.

ADT STROM Lukáš Foldýna

Datové typy a struktury

Časová a prostorová složitost algoritmů

Programování v C++, 2. cvičení

Implementace aritmetického stromu pomocí směrníků

Dynamické datové struktury IV.

Vyhledávací stromy. Slouží jako pomůcka pro organizaci dat umožňující efektivní vyhledávání.

Dynamické datové struktury I.

Řešení: PŘENESVĚŽ (N, A, B, C) = přenes N disků z A na B pomocí C

Základní datové struktury III: Stromy, haldy

Čtvrtek 8. prosince. Pascal - opakování základů. Struktura programu:

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Binární vyhledávací stromy II

Programování 3. hodina. RNDr. Jan Lánský, Ph.D. Katedra informatiky a matematiky Fakulta ekonomických studií Vysoká škola finanční a správní 2015

Grafy. doc. Mgr. Jiří Dvorský, Ph.D. Katedra informatiky Fakulta elektrotechniky a informatiky VŠB TU Ostrava. Prezentace ke dni 13.

Rekurzivní algoritmy

Dynamické datové typy a struktury

Grafové algoritmy. Programovací techniky

Grafové algoritmy. Programovací techniky

Obsah prezentace. Základní pojmy v teorii o grafech Úlohy a prohledávání grafů Hledání nejkratších cest

Základní datové struktury

Algoritmizace prostorových úloh

Spojová implementace lineárních datových struktur

Úvod do teorie grafů

Struktura programu v době běhu

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

NMIN102 Programování /2 Z, Zk

Prohledávání do šířky = algoritmus vlny

Stromy. Karel Richta a kol. Katedra počítačů Fakulta elektrotechnická České vysoké učení technické v Praze Karel Richta a kol.

4 Stromy a les. Definice a základní vlastnosti stromů. Kostry grafů a jejich počet.

Select sort: krok 1: krok 2: krok 3: atd. celkem porovnání. výběr nejmenšího klíče z n prvků vyžaduje 1 porovnání

Vyučovací hodina. 1vyučovací hodina: 2vyučovací hodiny: Opakování z minulé hodiny. Procvičení nové látky

Pascal. Katedra aplikované kybernetiky. Ing. Miroslav Vavroušek. Verze 7

Programovací jazyk Pascal

ALGORITMIZACE 2010/03 STROMY, BINÁRNÍ STROMY VZTAH STROMŮ A REKURZE ZÁSOBNÍK IMPLEMENTUJE REKURZI PROHLEDÁVÁNÍ S NÁVRATEM (BACKTRACK)

Algoritmy výpočetní geometrie

Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě

Stromy. Jan Hnilica Počítačové modelování 14

Stromy. Příklady. Rekurzivní datové struktury. Základní pojmy

Zdůvodněte, proč funkce n lg(n) roste alespoň stejně rychle nebo rychleji než než funkce lg(n!). Symbolem lg značíme logaritmus o základu 2.

Pokročilé programování v jazyce C pro chemiky (C3220) Operátory new a delete, virtuální metody

NPRG030 Programování I, 2018/19 1 / :03:07

Algoritmizace Dynamické programování. Jiří Vyskočil, Marko Genyg-Berezovskyj 2010

Lineární spojový seznam (úvod do dynamických datových struktur)

Základní způsoby: -Statické (přidělění paměti v čase překladu) -Dynamické (přiděleno v run time) v zásobníku na haldě

Maturitní otázky z předmětu PROGRAMOVÁNÍ

IB108 Sada 1, Příklad 1 Vypracovali: Tomáš Krajča (255676), Martin Milata (256615)

Amortizovaná složitost. Prioritní fronty, haldy (binární, d- regulární, binomiální, Fibonacciho), operace nad nimi a jejich složitost

Semestrální práce 2 znakový strom

Základy algoritmizace c2005, 2007 Michal Krátký, Jiří Dvorský1/39

Algoritmizace I. Ak. rok 2015/2016 vbp 1. ze 132

Volné stromy. Úvod do programování. Kořenové stromy a seřazené stromy. Volné stromy

Algoritmizace prostorových úloh

type Obdelnik = array [1..3, 1..4] of integer; var M: Obdelnik;

Více o konstruktorech a destruktorech

Algoritmy II. Otázky k průběžnému testu znalostí

OSTRAVSKÁ UNIVERSITA V OSTRAVĚ Pedagogická fakulta Obor informační technologie ve vzdělávání Kombinované studium

Dijkstrův algoritmus

Úloha ve stavovém prostoru SP je <s 0, C>, kde s 0 je počáteční stav C je množina požadovaných cílových stavů

Pokročilé programování v jazyce C pro chemiky (C3220) Třídy v C++

Nový způsob práce s průběžnou klasifikací lze nastavit pouze tehdy, je-li průběžná klasifikace v evidenčním pololetí a školním roce prázdná.

Slepé prohledávání do šířky Algoritmus prohledávání do šířky Při tomto způsobu prohledávání máme jistotu, že vždy nalezneme koncový stav, musíme ale p

Dynamické datové struktury II.

Základy umělé inteligence

Definice. B-stromu. B-strom řádu m je strom, kde každý uzel má maximálně m následníků a ve kterém platí:

Programování II. Návrh programu I 2018/19

Obsah. Předmluva 13 Zpětná vazba od čtenářů 14 Zdrojové kódy ke knize 15 Errata 15

Homer. prvky. délka. přední 0 zadní 4. Použití fronty BUS STOP. 3 Lisa. 2 Bart. 4 Maggie. 1 Marge. Grafické znázornění předchozí animace:

2 Datové struktury. Pole Seznam Zásobník Fronty FIFO Haldy a prioritní fronty Stromy Hash tabulky Slovníky

Binární vyhledávací stromy pokročilé partie

Rekurze a zásobník. Jak se vypočítá rekurzivní program? volání metody. vyšší adresy. main(){... fa(); //push ret1... } ret1

Pole a kolekce. v C#, Javě a C++

Radek Mařík

Pointery II. Jan Hnilica Počítačové modelování 17

PODPROGRAMY PROCEDURY A FUNKCE

Profilová část maturitní zkoušky 2017/2018

Radomíra Duží L Datový typ množina

Algoritmizace prostorových úloh

Reliance 3 design OBSAH

Software602 Form Designer

Rekurze. Pavel Töpfer, 2017 Programování 1-8 1

Transkript:

Téma: Vypracoval: Zdeněk Alčer Implementace binárního stromu směrníky 1. Teorie stromu: Pojem strom je datová struktura, která je v teorii grafů formálně definována jako zvláštní případ grafu bez cyklů. Strom (viz obr. 1) je útvar složený z vrcholů (uzlů) a hran s následujícím tvarem. Jeden význačný vrchol zcela nahoře, kterým se vstupuje do celého stromu, se nazývá kořen stromu. Tento vrchol má několik následovníků (synů) se kterými je spojen hranami. Každý vrchol může mít své následovníky a ti zase svoje atd. Žádný vrchol není následovníkem dvou nebo více vrcholů současně, naopak každý vrchol s výjimkou kořene má pouze jednoho předchůdce (otce). Vrcholy, které nemají žádné další následovníky, se nazývají listy stromu. Vrcholy s výjimkou kořene jsou vnitřními vrcholy stromu. Útvar s prázdnou strukturou je prázdný strom. Četnost stromu je maximální počet následovníků, které má některý z jeho vrcholů. Cesta od kořene k některému z vrcholů se nazývá větev. Jelikož stromy neobsahují cykly, je větev jednoznačně určena. Hloubka stromu je délka cesty (počet hran) maximální větve. Udává maximální vzdálenost mezi kořenem stromu a některým z listů. Strom, který má maximálně 2 následovníky se nazývá binární strom (obr. 2). Obyčejný binární strom je binární strom bez jakékoliv organizované formy jednotlivých prvků. V programové reprezentaci řešení binárních stromů směrníky, jsou vrcholy záznamy a nesou jednak informaci a jednak odkazy na další vrcholy. Hrany jsou reprezentovány směrníky a určují vazby mezi jednotlivými vrcholy. Pro binární stromy, kde vrchol smí mít maximálně dva následovníky, užíváme směrníky s názvy Levý a Pravý, přičemž ukazují sestupování ve směru listů. Část nesené informace tvoří klíč (obr. 3). Strana 1 (celkem 16)

Stromy se nejčastěji zobrazují grafickou interpretací, viz následující obrázky. obr.1 Strom 1 Kořen 1 Vnitřní vrcholy 2,3,5,8 2 3 Listy 4,6,7,9 4 5 6 7 8 9 obr.2 Binární strom Kořen 1 2 3 Vnitřní vrcholy 2,3,4,8 Listy 5,6,7,9 1 4 5 6 7 8 9 obr.3 Binární strom se znázorněnými směrníky Strom Strom Klíč 1 Levý Pravý Klíč 2 Levý Pravý Klíč 3 Levý Pravý Klíč 4 Levý Pravý Klíč 5 Levý Pravý Klíč 6 Levý Pravý Klíč 7 Levý Pravý Klíč 8 Levý Pravý Klíč 9 Levý Pravý Strana 2 (celkem 16)

2. Datový typ směrník Pro implementace binárního stromu se směrníky se vrátíme ke zopakování obecných zásad datového typu směrník. Směrník (užíváno též ukazatel, anglicky pointer), představuje zcela odlišný způsob práce s pamětí. U všech statických proměnných lze jednoduše určit dobu jejich existence. Globální existují po celou dobu existence programu, lokální proměnné podprogramu vznikají v okamžiku jeho startu a jsou zrušeny, jakmile podprogram končí. Beze změn zůstávají jejich deklarované vlastnosti. Proměnná zpřístupněná prostřednictvím směrníku se nazývá dynamicky alokovaná proměnná. Příkaz k jejímu vytvoření musí být naprogramován. Obdobně musí být dán pokyn i pro její zrušení. Dynamicky alokované proměnné a z nich vytvořené konstrukce vznikají až za běhu programu podle současné situace. Není nutné předem stanovit, kolik jich přesně bude a kdy přesně budou existovat. Směrník v sobě neuchovává konkrétní hodnotu nějakého prvku, ale uchovává v sobě adresu prvku v operační paměti počítače. Adresa, kterou směrník obsahuje, může ukazovat do libovolné části operační paměti. Směrník ukazuje vždy na proměnnou určitého typu. Existují různé typy směrníku, vždy podle datového typu dynamické proměnné, na kterou směrník ukazuje. Každý nový směrník tedy slouží jedné dynamické proměnné. Definice směrníku obsahuje právě jméno daného typu s předchozím operátorem nepřímé adresace ^. Např. typ SmeInteger, který je směrníkem na Integer se definuje takto type SmeInteger = ^ Integer ; var Cislo : SmeInteger ; Strana 3 (celkem 16)

Proměnná Cislo takto bude obsahovat směrník na dynamicky alokovanou proměnnou typu Integer. Obsahem proměnné Cislo bude adresa, která má být interpretována jako adresa počátku proměnné typu Integer. Alokace paměti Alokování paměti se vyžádá prostřednictvím standardní procedury New ( <Směrník> ) ; Jejím parametrem je proměnná typu směrník. New zjistí typ tohoto směrníku a najde někde kousek paměti odpovídající velikosti. Tento kousek paměti si označí za obsazený a do proměnné uloží adresu jeho začátku. Pro náš započatý případ provedeme New ( Cislo ) ; Tím se alokuje v paměti místo pro proměnnou typu Integer a jeho adresa se uloží do proměnné Cislo. Od tohoto okamžiku Cislo ukazuje na tuto dynamicky alokovanou proměnnou. Graficky znázorněno Tímto je proměnné přidělena paměť a směrník naplněn adresou. Zápis, který uloží trojku do proměnné, na kterou ukazuje Cislo zapíšeme takto Cislo^ := 3; a graficky zobrazeno Strana 4 (celkem 16)

Na tutéž dynamicky alokovanou proměnnou může odkazovat několik směrníků, stačí jen přiřadit mezi sebou jejich hodnoty. Např. použijeme další deklarovanou proměnnou Nejmenši typu Integer a zapíšeme příkazy New ( Cislo ) ; Cislo^ := 3; Nejmensi := Cislo; přičemž vzniká tato situace, kdy oba směrníky obsahují adresu stejné proměnné. Pozor na zdánlivě obdobnou možnost New ( Cislo ) ; Cislo^ := 3; New ( Nejmensi ); Nejmensi^ := Cislo^; Zde čtvrtý příkaz říká do proměnné, na kterou ukazuje Nejmensi, ulož obsah proměnné, na kterou ukazuje Cislo. Zde se jedná o dvě zcela samostatně dynamicky alokované proměnné, jejichž obsahy přiřazujeme. Pak znázorněno Uvolnění paměti Dynamicky alokované proměnné jsou ručně vytvářeny a stejně i zanikají, pro odstranění se používá procedura Strana 5 (celkem 16)

Dispose ( <Směrník> ) Parametrem je opět proměnná typu směrník. Dynamicky alokovaná proměnná na kterou ukazuje, bude zrušena a jí vyhražená paměť se uvolní pro další použití. Obsah směrníku je po provedení Dispose nedefinován. Příkaz Dispose ( Cislo); povede k likvidaci proměnné, na kterou ukazuje Cislo. Konstanta nil. Tato speciální konstanta symbolizuje, že daný směrník nikam nevede. Nil je univerzální a lze ji přiřadit libovolnému směrníku bez ohledu na jeho konkrétní typ. Je nutno dobře rozlišovat směrník s nedefinovanou hodnotou a směrník s hodnotou nil. Hodnota směrníku je na začátku nebo po provedení Dispose nedefinována. Pokud však směrníku přiřadíme nil, jeho hodnota definována je, jen její směrník právě neukazuje na žádnou dynamickou proměnnou. Směrníky stejného typu lze navzájem porovnávat, povoleny jsou však pouze testy na rovnost ( = ) a nerovnost ( < > ). Dva směrníky jsou si rovni, pokud obsahují stejnou adresu (ukazují na tutéž proměnnou). 3. Implementace binárních stromů Strana 6 (celkem 16)

Strukturu typu strom lze definovat jako prázdnou strukturu, tj. prázdný strom, nebo jako vrchol (prvek), ke kterému je připojen konečný počet stromových struktur, nazývaných podstromy. Jinak řečeno každý strom je tvořen dalšími stromy, pro které platí tatáž definice. Definice stromu je tedy rekurzivní, což se promítne v použitých algoritmech, které budou obsahovat rekurzivní podprogramy. Vrchol u stromové struktury lze obecně deklarovat takto: Type SmeVrchol = ^vrchol; vrchol = record datovaslozka : TypDatoveSlozky; levypodstrom, pravypodstrom : SmeVrchol Vrcholy jsou reprezentovány dynamickými proměnnými stejného typu záznam. Ze zápisu je patrné, že položky levypodstrom a pravypodstrom jsou opětně definovány jako typ směrník na strom. Při realizaci určité funkce či procedury, která má být uskutečněna nad všemi vrcholy, je třeba celým stromem projít a všechny vrcholy navštívit. K průchodu binárním stromem nám slouží tři rekurzivní metody, které se od sebe liší vzájemným pořadím provedení dané operace nad daným vrcholem (uzlem) a průchodem oběma podstromy. Metody s názvy Preorder, Inorder a Postorder si ukážeme na programové realizaci procedury, jejímž parametrem je směrník na zpracovávaný vrchol. 1. Procedura Preorder nejprve provádí danou operaci nad daným vrcholem (uzlem), poté provede průchod levým podstromem a nakonec pravým podstromem. procedure Preorder(Strom : SmeVrchol); if Strom <> nil then {neprázdný vrchol pro prohledávání? } {operace nad daným vrcholem} Preorder(Strom^.levypodstrom); {průchod levým podstromem} Preorder(Strom^.pravypodstrom); {průchod pravým podstromem} Strana 7 (celkem 16)

2. Procedura Inorder projde nejdříve levým podstromem, na to zpracuje operaci nad daným vrcholem a nakonec projde pravým podstromem. procedure Inorder(Strom : SmeVrchol); if Strom <> nil then Inorder(Strom^.levypodstrom); Inorder(Strom^.pravypodstrom); {průchod levým podstromem} {operace nad daným vrcholem} {průchod pravým podstromem} 3. Procedura Postorder projde nejdříve levým podstromem, na to projde pravým podstromem a nakonec zpracuje operaci nad daným vrcholem. procedure Preorder(Strom : SmeVrchol); if Strom <> nil then Preorder(Strom^.levypodstrom); Preorder(Strom^.pravypodstrom); {průchod levým podstromem} {průchod pravým podstromem} {operace nad daným vrcholem} Pokud bychom aplikovali tyto tři metody průchodu binárním stromem pro obrázek č. 2 (respektive také obr. 3), získali bychom výpisy s pořadím číselných položek: preorder: 1, 2, 4, 8, 9, 5, 3, 6, 7 inorder: 4, 8, 9, 2, 5, 1, 6, 3, 7 postorder: 9, 8, 4, 5, 2, 6, 7, 3, 1 Strana 8 (celkem 16)

5. Aplikace konkrétního programu s demonstrací operací pro binární strom. 5.1 Vytvoření binárního stromu Deklarace pro řešený příklad: type TStrom = ^vrchol; vrchol = record Klic: Integer; levy, pravy: TStrom var St,nalezeny: TStrom; {deklarace směrníku na kořen stromu} {a pomocného směrníku pro hledání vrcholu } Idx: Integer; {pomocné počítadlo vrcholů} Vytvoření stromu je prováděno pomocí globální procedury VytvorStrom. V ní probíhá vždy náhodný výběr pro nastavení směrníků a tím určení cesty doleva nebo doprava. Následuje zjišťování, zda existuje volná pozice pro nový vrchol (uzel), pro vybraný směrník. Následně proběhne vytvoření vrcholové proměnné pro pomocný směrník, uložení hodnoty do nového vrcholu, vynulování pomocných směrníků pro nové následovníky (potomky) a napojení tohoto vrcholu (prozatímního listu) na směrník předchůdce (otce). Tím je dosaženo vytvoření stromu s předem nedefinovanou strukturou. procedure VytvorStrom(var S: TStrom; cis: Integer); var pom: TStrom; if random(2) = 0 then {náhodný výběr cesty doleva-doprava} if S^.levy = nil then {zjištění volné pozice pro nový vrchol (uzel)} new(pom); pom^.klic := cis; {odkaz na proměnnou kam ukazuje směrník } pom^.levy := nil; pom^.pravy := nil; {vynulování pro vytvoření listu} Strana 9 (celkem 16)

S^.levy := pom else VytvorStrom(S^.levy, cis) {rekurzívně pokračování do levého podstromu} else if S^.pravy = nil then new(pom); pom^.klic := cis; pom^.levy := nil; pom^.pravy := nil S^.pravy := pom else VytvorStrom(S^.pravy, cis) {rekurzívně pokračování do pravého podstromu} K iniciování globální procedury VytvorStrom je sestavena procedura Vytvor_BSClick. V jejím těle probíhá operace zajišťující vytvoření kořenu s hodnotou 1 a následných vrcholů s hodnotami až do velikosti žádané hodnoty. procedure TForm1.Vytvor_BSClick(Ser: TObject); var i: Integer; {část programu pro vytvoření stromu s voláním procedury VytvorStrom} new(st);st^.levy := nil; St^.pravy := nil; St^.Klic := 1; for i := 2 to StrToInt(Edit_vytvor.text) do VytvorStrom(St,i); Idx := StrToInt(Edit_vytvor.text); Pro inicializaci náhodného generátoru hodnot je použito příkazu Randomize procedure TForm1.FormCreate(Ser: TObject); Randomize 5.2 Vykreslení a tisk vytvořeného binárního stromu Pro vykreslení struktury stromu je použita procedura Kresli_BSClick, která s využitím rekurzívní lokální procedury vykreslí na plátno grafickou strukturu vytvořeného stromu metodou postorder. procedure TForm1.Kresli_BSClick(Ser: TObject); procedure Kresli(S: TStrom; x, y, sirka: Integer); sirka := sirka div 2; if S <> nil then {neprázdný vrchol pro kreslení? } if S^.levy <> nil then {vykreslení hran vlevo} Strana 10 (celkem 16)

Image1.Canvas.MoveTo(x, y); Image1.Canvas.LineTo(x-sirka,y+30); Kresli(S^.levy, x-sirka, y+30, sirka); if S^.pravy <> nil then {vykreslení hran vpravo} Image1.Canvas.MoveTo(x, y); Image1.Canvas.LineTo(x+sirka,y+30); Kresli(S^.pravy, x+sirka, y+30, sirka); Image1.Canvas.TextOut(x-5, y-8, IntToStr(S^.Klic)); {zápis potomka} {tělo procedury zajišťující vymazání plátna a parametrizování volané procedury} Image1.Canvas.Brush.Color := clwhite; Image1.Canvas.Brush.Style := bssolid; Image1.Canvas.Rectangle(0, 0, Image1.Width, Image1.Height); Kresli(St, Image1.Width div 2, 30, Image1.Width div 2) Tisk stromu pracuje při tisku s typem řetězec, nemá tedy při výpisu řešeno zobrazení hran a pro jistou zjednodušenost řešení je zobrazená struktura pootočena o devadesát stupňů proti směru hodinových ručiček. Tvorba zobrazení je opět řešena rekurzívní lokální procedurou. procedure TForm1.Tisk_BSClick(Ser: TObject); procedure tisk(s: TStrom; h: Integer); var S1: String; j: Integer; if S <> nil then {realizace rozepsání vrcholů} tisk(s^.pravy, h+1); {hloubka (sloupec) pro pravého následníka} s1 := ''; for j := 1 to h do s1 := s1+' '; s1 := s1+inttostr(s^.klic); {realizace zvyšování hloubky následníkům} Memo1.Lines.Add(s1); {výpis hodnoty vrcholu} tisk(s^.levy, h+1) Memo1.Lines.Clear; tisk(st, 1) {hloubka (sloupec) pro levého následníka} 5.3 Prohledávání a uspořádání vytvořené struktury binárního stromu Strana 11 (celkem 16)

K prohledávání stromu používáme metody preorder, inorder a postorder dle obecného základu vysvětleného výše. V řešeném příkladu je vždy pro jednotlivé metody sestavena lokální procedura s výpisem zjištěných posloupností hodnot (pro ukázku metoda preorder): procedure TForm1.PreorderClick(Ser: TObject); procedure Preorder(S: TStrom); if S <> nil then {neprázdný vrchol pro prohledávání? } Memo2.Lines.Add(IntToStr(S^.Klic)); Preorder(S^.levy); Preorder(S^.pravy) {výpis hodnoty klíče} Memo2.Lines.Clear; Preorder(St) {vymazání obsahu okna pro výpis} Pro konkrétní příklad byly vytvořeny tři globální procedury Preorder_Hledej, Inorder_Hledej a Postorder_Hledej, které jsou používány i pro další algoritmy demonstrující základní operace na stromech. Při nalezení je nastaven pomocný globální směrník nalezeny jako směrník na nalezený hledaný vrchol(uzel). Ukázkou je sestavená procedura Preorder_Hledej: procedure Preorder_Hledej(S:TStrom; Hledany: Integer); if S <> nil then {neprázdný vrchol pro prohledávání? } if (S^.Klic = Hledany) then nalezeny := S; {směrník nastaven na hledaný} {vrchol} if(nalezeny = nil ) then Preorder_Hledej(S^.levy,Hledany); {pokud nenalezen prohledává se dále} {rekurzívní postup do levého podstromu} if(nalezeny = nil ) then Preorder_Hledej(S^.pravy,Hledany); {rekurzívní postup do pravého podstromu} Strana 12 (celkem 16)

5.4 Přidání vrcholu (uzlu) do vytvořeného binárního stromu Přidání vrcholu je sestaveno s pomocí procedury jedné ze tří metod průchodu stromem. Lze rozhodovat o směru strany kde se po vyhledání určující hodnoty vytvoří levý nebo pravý následovník. Do něj je pak vložena hodnota pomocného globálního počitadla Idx, které je při vytvoření a přidání vrcholu zvyšována. Jelikož jsou procedury shodné, závislé jsou jen od určení metod a směru je ukázkou jen sestavená procedura Pridej_Preorder_PClick (pro směr doprava): procedure TForm1.Pridej_Preorder_PClick(Ser: TObject); var kampridat,novy:tstrom; nalezeny := nil; Preorder_Hledej(St,StrToInt(Edit_kam.text)); {vyhledání vrcholu, kde se nový přidá} kampridat := nalezeny; if(kampridat <> nil) then {existuje vrchol kde se navazuje? } if(kampridat^.pravy = nil) then {pokud je pravý směrník volný, } { navazuj nový vrchol} new(novy); inc(idx); novy^.klic := Idx; novy^.levy := nil; novy^.pravy := nil; kampridat^.pravy := novy; 5.5 Vyhledání hodnoty ve vytvořeném binárním stromě K vyhledání vrcholu je využito globální procedury Preorder_Hledej (případně dalšími metodami). Nalezená hodnota je porovnávána s hledanou hodnotou a následně je indikován výsledek hledání. procedure TForm1.Hledej_PreorderClick(Ser: TObject); nalezeny := nil; Preorder_Hledej(St,StrToInt(Edit_hledej.Text)); If (nalezeny <> nil) then Label1.Caption := 'NALEZENO' else Label1.Caption := 'NENALEZENO'; 5.6 Rušení vrcholu (uzlu) vytvořeného binárního stromu Strana 13 (celkem 16)

Odstranění vrcholu (uzlu) ze stromu je poněkud složitější záležitost, zvláště pak jedná-li se o nijak neuspořádaný binární strom a nelze použít některých zjednodušujících operací s jasnými pravidly pro strukturu stromu. Složitost přináší fakt, že existují rozdílnosti vrcholu, listu a kořene, ale zejména nemá dojít k rozpadu struktury binárního stromu. Uváděné řešení rušení vrcholu (uzlu) probíhá ve třech fázích : - kontrolní hledání, odpojení od rodiče a samotné rušení vrcholu (uzlu). Tělo procedury Zrus_VrcholClick vykonává nejdříve hledání žádaného vrcholu (uzlu) pomocí definované globální procedury Preorder_Hledej. Když nenalezne žádanou hodnotu vrcholu, tak hledání končí s indikací stavu. Při nalezení hodnoty je zjišťováno zda jde o list. Následně pak odpojíme tento vrchol (uzel) od předchůdce (otce) ve stromu (pokud není kořenem). Pokud je žádaný vrchol kořenem, rušíme přímo známý kořen. Pokud není kořen, rušíme nalezený obecný nekořenový vrchol. Pokud se vůbec nejedná o list, použije se funkce prenesprvnilist. V ní hledaný uzel není fyzicky rušen, ale jeho hodnota je nahrazena některou (dle podmínek) z listových z jeho podstromu. Použitý list je odebrán ze struktury stromu. procedure TForm1.Zrus_VrcholClick(Ser: TObject); {funkce, která vybere hodnotu (klíč) přenášeného listu nahrazujícího rušený vrchol} function prenesprvnilist(var S:TStrom):Integer; var pom:integer; {pokud je levý směrník neprázdný pokračuj v hledání vhodného listu} if (S^.levy <> nil) then result := prenesprvnilist(s^.levy) else if(s^.pravy <> nil) then result := prenesprvnilist(s^.pravy) else {nalezen list jehož hodnota je předána rušenému uzlu} pom := S^.Klic; dispose(s); S := nil; result := pom; {vracíme hodnotu nalezeného listu} { je vybírán ukazatel na skutečného předchůdce mazaného vrcholu stromu a ten je následně} { ztotožněn (pomoci var delkarace) s globálním pomocným ukazatelem pojmenovaný nalezeny } procedure Preorder_Hledej_Vymaz(var S:TStrom; Hledany: Integer); if S <> nil then if (S^.Klic=Hledany) then nalezeny:=s; if(nalezeny = nil ) then Strana 14 (celkem 16)

Preorder_Hledej_Vymaz(S^.levy,Hledany); {pokud je nalezený hledaný vrchol mým levým potomkem pak jsem jeho předchůdcem} if( (nalezeny <> nil) and (S^.levy^.Klic = Hledany) ) then S^.levy := nil; if(nalezeny = nil ) then Preorder_Hledej_Vymaz(S^.pravy,Hledany); {pokud je nalezený hledaný vrchol mým pravým potomkem pak jsem jeho předchůdcem} if( (nalezeny <> nil) and (S^.pravy^.Klic = Hledany)) then S^.pravy := nil; nalezeny := nil; {klasické nalezení vrcholu} Preorder_Hledej(St,StrToInt(Edit_zrus.Text)); if(nalezeny = nil) then Label2.Caption := 'NENÍ HODNOTA' else {zjištění jestli je nalezený ukazatel na list stromu} if( (nalezeny^.levy = nil) and (nalezeny^.pravy = nil)) then nalezeny := nil; {předchůdci mazaného vrcholu odejmeme směrník na nalezený hledaný vrchol} {a zároveň znovu nalezneme hledaný vrchol} Preorder_Hledej_Vymaz(St,StrToInt(Edit_zrus.Text)); {pokud nemá klíč předchůdce, je kořenem a může byt zrušen } { (dealokován a směrník na kořen je nastaven na nil) } if(st^.klic = nalezeny^.klic) then dispose(st); St := nil; else dispose(nalezeny); nalezeny := nil; else {nalezený-rušený není listem, je nutné použít 'pouze' přenos hodnoty z listu} {do rušeného vrcholu, tedy tento vrchol není fyzicky odebrán ze stromu, } {pouze jeho hodnota je nahrazena hodnotou prvního nalezeného listu z jeho } { podstromu, který je také následně zrušen} Strana 15 (celkem 16)

if(nalezeny <> nil) then nalezeny^.klic := prenesprvnilist(nalezeny); Na závěr lze uvést případné zrušení celé struktury binárního stromu. Algoritmus by byl již několikrát opakovaný postup rekurzívního průchodu stromem s metodou postorder. Takto by došlo k vymazání a vynulování všech vrcholů (uzlů) ve stromu. Pro prázdný strom dojde k indikaci stavu. procedure TForm1.Zrus_BS_s_pruchodemClick(Ser: TObject); procedure Vymaz(var S: Strom) if S = nil then Label2.Caption := 'NENÍ UŽ STROM' else if S^.levy<>nil then Vymaz(S^.levy); if S = nil then Label2.Caption := 'NENÍ UŽ STROM' else if S^.pravy<>nil then Vymaz(S^.pravy); Dispose(S); S := nil Vymaz(St) Jistě by šlo i zvážit jednoduchou proceduru smazání a vynulování pouze kořene procedure TForm1.Zrus_BS_korenClick(Ser: TObject); Dispose(St); St := nil; Binární strom i se svou strukturou bude zdánlivě zrušen, je potřeba si uvědomit, že v paměti zůstaly alokovány původní vrcholy (adresy s hodnotami), což by mohlo vést u rozsáhlých stromů, respektive znovu vytvářených stromů, až k zablokování systému! K závěru uvádím, že v případně realizovaném příkladu dle uváděných programových struktur je nutno pro demonstraci zkoušené operace vždy znovu iniciovat kreslení, respektive tisk struktury binárního stromu. Toto není řešeno uváděnými programy. Strana 16 (celkem 16)