Serwis Edukacyjny w I-LO w Tarnowie Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej Autor artykułu: mgr Jerzy Wałaszek |
©2024 mgr Jerzy Wałaszek |
ProblemDla danego drzewa binarnego należy określić:
|
Na pierwszy rzut oka zadanie wydaje się być skomplikowane. Jednakże rozwiążemy je za pomocą opisanego wcześniej przejścia DFS:preorder. Algorytm DFS gwarantuje nam odwiedzenie każdego węzła drzewa, jeśli węzłem startowym będzie jego korzeń. Do wykonania naszego zadania w strukturze węzła będziemy potrzebowali dodatkowe pole level, w którym zostanie umieszczony numer poziomu zawierającego dany węzeł.
Pascaltype PBTnode = ^BTnode; BTnode = record left : PBTnode; right : PBTnode; level : Integer; data : typ_danych; end; |
struct BTnode { BTnode * left; BTnode * right; int level; typ_danych data; }; |
BasicType BTnode left As BTnode Ptr right As BTnode Ptr level As Integer data As typ_danych End Type |
Python (dodatek) |
# klasa węzłów drzewa class BTnode: def __init__(self, l, r, lv, d): self.left = l self.right = r self.level = lv self.data = d |
Kolejnym problemem jest sposób wprowadzania drzewa. Można go rozwiązać na kilka sposobów. Tutaj postąpimy w sposób następujący:
Kolejne dane występują jako n trójek liczb. Każdy węzeł jest opisany jedną trójką liczb. Pierwsza trójka odnosi się do węzła nr 0, druga do węzła nr 1, itd.
Trójka liczb dla danego węzła określa kolejno: daną dla węzła, numer węzła będącego lewym synem, numer węzła będącego prawym synem. Jeśli węzeł nie posiada syna, to jego numer wynosi 0 (nie spowoduje to dwuznaczności, ponieważ numer 0 jest zarezerwowany dla korzenia, a korzeń nie jest synem żadnego węzła).
Przykład:
12 5 1 2 11 3 4 7 5 6 32 7 8 -16 0 9 21 10 11 -2 0 0 3 0 0 17 0 0 -5 0 0 4 0 0 1 0 0 |
Liczba węzłów węzeł 0: synowie 1 i 2 węzeł 1: synowie 3 i 4 węzeł 2: synowie 5 i 6 węzeł 3: synowie 7 i 8 węzeł 4: prawy syn 9 węzeł 5: synowie 10 i 11 węzeł 6: brak synów węzeł 7: brak synów węzeł 8: brak synów węzeł 9: brak synów węzeł 10: brak synów węzeł 11: brak synów |
---|
Zasada odczytu danych będzie następująca:
W trakcie wykonywania DFS zwiększamy o 1 licznik o indeksie równym zawartości pola level – zliczymy węzeł na danym poziomie. Po przejściu drzewa wyświetlamy zawartości liczników od 0 do maxpath.
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
Program odczytuje ze standardowego wejścia definicję drzewa, tworzy drzewo binarne, przechodzi je algorytmem rekurencyjnym DFS:preorder, przetwarza węzły i wypisuje wyniki. |
Dane przykładowe (przekopiuj do schowka i
wklej do okna konsoli):
12 5 1 2 11 3 4 7 5 6 32 7 8 -16 0 9 21 10 11 -2 0 0 3 0 0 17 0 0 -5 0 0 4 0 0 1 0 0 |
Pascal// Badanie drzewa binarnego // Data: 24.01.2013 // (C)2013 mgr Jerzy Wałaszek //------------------------------ program explore_BT; // Typ węzłów drzewa type PBTnode = ^BTnode; // wskazanie węzła BTnode = record // rekord węzła left : PBTnode; // lewy syn right : PBTnode; // prawy syn level : integer; // numer poziomu data : integer; // dane węzła end; // Zmienne globalne var maxpath : integer; // długość najdłuższej // ścieżki/wysokość drzewa minpath : integer; // długość najkrótszej // ścieżki levelcount : array of Integer; // liczniki leafcount : integer; // liczba liści onechildcount : integer; // liczba węzłów // z jedynakiem nodesum : integer; // suma danych węzłów n : integer; // liczba węzłów root : PBTnode; // wskazanie korzenia drzewa // Procedura inicjuje dane, odczytuje definicję // drzewa ze standardowego wejścia i tworzy jego // strukturę w pamięci. Na wyjściu w zmiennej // root zostaje umieszczony adres korzenia drzewa //----------------------------------------------- procedure read_bt; var vp : array of PBTnode; // tablica wskaźników i, d, l, r : integer; begin read(n); // odczytujemy liczbę węzłów // drzewa binarnego SetLength(vp, n); // tworzymy tablicę // dynamiczną wskaźników for i := 0 to n-1 do new(vp[i]); // tworzymy dynamicznie węzeł for i := 0 to n-1 do begin readln(d, l, r); // odczytujemy trójkę liczb vp[i]^.level := 0; // zerujemy poziom węzła vp[i]^.data := d; // wprowadzamy // do węzła dane if l > 0 then vp[i]^.left := vp[l] // ustawiamy lewego // syna, else vp[i]^.left := nil; // jeśli istnieje if r > 0 then vp[i]^.right := vp[r] // ustawiamy prawego // syna, else vp[i]^.right := nil; // jeśli istnieje end; root := vp [0]; // zapamiętujemy korzeń drzewa SetLength(vp, 0); // usuwamy tablicę wskaźników maxpath := 0; // ustawiamy zmienne globalne minpath := MAXINT; SetLength(levelcount, n); for i := 0 to n-1 do levelcount[i] := 0; leafcount := 0; onechildcount := 0; nodesum := 0; end; // Procedura przechodzi drzewo algorytmem // DFS:preorder i odpowiednio przetwarza węzły // zapisując wyniki w zmiennych globalnych //-------------------------------------------- procedure dfs(v : PBTnode); var children : integer; begin if v <> nil then begin // przetwarzamy bieżący węzeł children := 0; // liczba synów, 0, 1 lub 2 if v^.left <> nil then begin inc(children); v^.left^.level := v^.level+1; end; if v^.right <> nil then begin inc(children); v^.right^.level := v^.level+1; end; // test na najdłuższą ścieżkę if v^.level > maxpath then maxpath := v^.level; // test na najkrótszą ścieżkę do liścia // i zliczanie liści if children = 0 then begin if v^.level < minpath then minpath := v^.level; inc(leafcount); end; // zliczanie węzłów na bieżącym poziomie inc(levelcount[v^.level]); // zliczanie węzłów z jednym synem if children = 1 then inc(onechildcount); // sumowanie zawartości węzłów inc(nodesum, v^.data); dfs(v^.left); // przechodzimy lewe // poddrzewo dfs(v^.right); // przechodzimy prawe // poddrzewo end; end; // Procedura wyświetla wyniki końcowe //----------------------------------- procedure write_bt; var i : integer; begin writeln; writeln('maxpath = ', maxpath); writeln('minpath = ', minpath); writeln; for i := 0 to maxpath do writeln('level ', i, ' : number of nodes = ', levelcount[i]); writeln; writeln('leafcount = ', leafcount); writeln('onechildcount = ', onechildcount); writeln('nodesum = ', nodesum); writeln; end; // Procedura DFS:postorder usuwająca drzewo //----------------------------------------- procedure dfs_release (v : PBTnode); begin if v <> nil then begin dfs_release(v^.left); // usuwamy lewe // poddrzewo dfs_release(v^.right); // usuwamy prawe // poddrzewo dispose(v); // usuwamy sam węzeł end; end; // Procedura sprząta pamięć //------------------------- procedure delete_bt; begin SetLength(levelcount, 0); dfs_release(root); // wykorzystujemy // DFS:postorder // do usunięcia drzewa end; //********************** //*** PROGRAM GŁÓWNY *** //********************** begin read_bt; // odczytaj i utwórz drzewo dfs(root); // przetwórz drzewo write_bt; // wypisz wyniki delete_bt; // posprzątaj pamięć end. |
// Badanie drzewa binarnego // Data: 24.01.2013 // (C)2013 mgr Jerzy Wałaszek //--------------------------- #include <iostream> using namespace std; // Typ węzłów drzewa struct BTnode { BTnode * left; BTnode * right; int level; int data; }; // Zmienne globalne int maxpath = 0; // długość najdłuższej // ścieżki/wysokość drzewa // długość najkrótszej ścieżki int minpath = 2147483647; // tablica liczników int * levelcount; // liczba liści int leafcount = 0; // liczba węzłów z jedynakiem int onechildcount = 0; // suma danych w węzłach int nodesum = 0; // liczba węzłów int n; // wskazanie korzenia drzewa BTnode * root; // Procedura inicjuje dane, odczytuje // definicję drzewa ze standardowego // wejścia i tworzy jego strukturę // w pamięci. Na wyjściu w zmiennej root // zostaje umieszczony adres korzenia drzewa //------------------------------------------ void read_bt(void) { BTnode ** vp; // tablica wskaźników int i, d, l, r; // odczytujemy liczbę węzłów // drzewa binarnego cin >> n; // tworzymy tablicę dynamiczną wskaźników vp = new BTnode * [n]; for(i = 0; i < n; i++) // tworzymy dynamicznie węzeł vp[i] = new BTnode; for(i = 0; i < n; i++) { // odczytujemy trójkę liczb cin >> d >> l >> r; // zerujemy poziom węzła vp[i]->level = 0; // wprowadzamy do węzła dane vp[i]->data = d; // ustawiamy lewego syna, // jeśli istnieje vp[i]->left = l ? vp[l] : NULL; // ustawiamy prawego syna, // jeśli istnieje vp[i]->right = r ? vp[r] : NULL; } root = vp[0]; // zapamiętujemy korzeń drzewa delete [] vp; // usuwamy tablicę wskaźników // tworzymy tablicę liczników // elementów na poziomach levelcount = new int[n]; for(i = 0; i < n; i++) levelcount[i] = 0; } // Procedura przechodzi drzewo algorytmem // DFS:preorder i odpowiednio przetwarza węzły // zapisując wyniki w zmiennych globalnych //-------------------------------------------- void dfs(BTnode * v) { if(v) { // przetwarzamy bieżący węzeł //--------------------------- // liczba synów, 0, 1 lub 2 int children = 0; if(v->left) { children++; v->left->level = v->level+1; } if(v->right) { children++; v->right->level = v->level+1; } // test na najdłuższą ścieżkę if(v->level > maxpath) maxpath = v->level; // test na najkrótszą ścieżkę do liścia // i zliczanie liści if(!children) { if(v->level < minpath) minpath = v->level; leafcount++; } // zliczanie węzłów na bieżącym poziomie levelcount [v->level] ++; // zliczanie węzłów z jednym synem if(children == 1) onechildcount++; // sumowanie zawartości węzłów nodesum += v->data; // przechodzimy lewe poddrzewo dfs(v->left); // przechodzimy prawe poddrzewo dfs(v->right); } } // Procedura wyświetla wyniki końcowe //----------------------------------- void write_bt() { cout << endl << "maxpath = " << maxpath << endl << "minpath = " << minpath << endl << endl; for(int i = 0; i <= maxpath; i++) cout << "level " << i << ": number of nodes = " << levelcount [i] << endl; cout << endl << "leafcount = " << leafcount << endl << "onechildcount = " << onechildcount << endl << "nodesum = " << nodesum << endl << endl; } // Procedura DFS:postorder usuwająca drzewo //----------------------------------------- void dfs_release(BTnode * v) { if(v) { // usuwamy lewe poddrzewo dfs_release(v->left); // usuwamy prawe poddrzewo dfs_release(v->right); delete v; // usuwamy sam węzeł } } // Procedura sprząta pamięć //------------------------- void delete_bt() { delete [] levelcount; // wykorzystujemy DFS:postorder // do usunięcia drzewa dfs_release(root); } //********************** //*** PROGRAM GŁÓWNY *** //********************** int main() { read_bt(); // odczytaj i utwórz drzewo dfs(root); // przetwórz drzewo write_bt(); // wypisz wyniki delete_bt(); // posprzątaj pamięć return 0; } |
Basic' Badanie drzewa binarnego ' Data: 24.01.2013 ' (C)2013 mgr Jerzy Wałaszek '------------------------------ ' Typ węzłów drzewa Type BTnode left As BTnode Ptr right As BTnode Ptr level As Integer data As Integer End Type ' Zmienne globalne '----------------- ' długość najdłuższej ścieżki / wysokość drzewa Dim Shared As Integer maxpath = 0 ' długość najkrótszej ścieżki Dim Shared As Integer minpath = 2147483647 ' tablica liczników Dim Shared As Integer Ptr levelcount ' liczba liści Dim Shared As Integer leafcount = 0 ' liczba węzłów z jedynakiem Dim Shared As Integer onechildcount = 0 ' suma danych węzłów Dim Shared As Integer nodesum = 0 ' liczba węzłów Dim Shared As Integer n ' wskazanie korzenia drzewa Dim Shared As BTnode Ptr root ' Procedura inicjuje dane, odczytuje ' definicję drzewa ze standardowego ' wejścia i tworzy jego strukturę ' w pamięci. Na wyjściu w zmiennej ' root zostaje umieszczony adres ' korzenia drzewa '----------------------------------- Sub read_bt() ' tablica wskaźników Dim As BTnode Ptr Ptr vp Dim As Integer i, d, l, r Open Cons For Input As #1 ' odczytujemy liczbę węzłów drzewa binarnego Input #1, n ' tworzymy tablicę dynamiczną wskaźników vp = new BTnode Ptr [n] For i = 0 To n-1 ' tworzymy dynamicznie węzeł vp [i] = new BTnode Next For i = 0 To n-1 ' odczytujemy trójkę liczb Input #1, d, l, r ' zerujemy poziom węzła vp[i]->level = 0 ' wprowadzamy do węzła dane vp[i]->data = d ' ustawiamy lewego syna, jeśli istnieje If l > 0 Then vp[i]->left = vp[l] Else vp[i]->Left = 0 End If ' ustawiamy prawego syna, jeśli istnieje If r > 0 Then vp[i]->right = vp[r] Else vp[i]->Right = 0 End If Next Close #1 ' zapamiętujemy korzeń drzewa root = vp[0] ' usuwamy tablicę wskaźników delete [] vp ' tworzymy tablicę liczników elementów na poziomach levelcount = new Integer[n] For i = 0 To n-1 levelcount[i] = 0 Next End Sub ' Procedura przechodzi drzewo algorytmem ' DFS:preorder i odpowiednio przetwarza ' węzły zapisując wyniki w zmiennych globalnych '---------------------------------------------- Sub dfs(v As BTnode Ptr) Dim As Integer children = 0 If v Then ' przetwarzamy bieżący węzeł If v->Left Then children += 1 v->left->level = v->level+1 End If If v->Right Then children += 1 v->right->level = v->level+1 End If ' test na najdłuższą ścieżkę If v->level > maxpath Then _ maxpath = v->level ' test na najkrótszą ścieżkę do liścia ' i zliczanie liści If children = 0 Then If v->level < minpath Then _ minpath = v->level leafcount += 1 End If ' zliczanie węzłów na bieżącym poziomie levelcount[v->level] += 1 ' zliczanie węzłów z jednym synem If children = 1 then onechildcount += 1 ' sumowanie zawartości węzłów nodesum += v->Data ' przechodzimy lewe poddrzewo dfs(v->left) ' przechodzimy prawe poddrzewo dfs(v->right) End If End Sub ' Procedura wyświetla wyniki końcowe '----------------------------------- Sub write_bt() Dim As Integer i Print Print "maxpath = ";maxpath Print "minpath = ";minpath Print For i = 0 To maxpath Print "level ";i;": number of nodes = ";_ levelcount[i] Next Print Print "leafcount = ";leafcount Print "onechildcount = ";onechildcount Print "nodesum = ";nodesum Print End Sub ' Procedura DFS:postorder usuwająca drzewo '----------------------------------------- sub dfs_release(v As BTnode Ptr) If v Then ' usuwamy lewe poddrzewo dfs_release (v->left) ' usuwamy prawe poddrzewo dfs_release (v->right) ' usuwamy sam węzeł delete v End If End Sub ' Procedura sprząta pamięć '------------------------- Sub delete_bt() delete [] levelcount ' wykorzystujemy DFS:postorder ' do usunięcia drzewa dfs_release (root) End Sub '********************** '*** PROGRAM GŁÓWNY *** '********************** read_bt() ' odczytaj i utwórz drzewo dfs(root) ' przetwórz drzewo write_bt() ' wypisz wyniki delete_bt() ' posprzątaj pamięć End |
Python (dodatek) |
# Badanie drzewa binarnego # Data: 6.07.2024 # (C)2024 mgr Jerzy Wałaszek # ------------------------------ # klasa węzłów drzewa class BTnode: def __init__(self): self.left = None self.right = None self.level = 0 self.data = 0 # zmienne globalne # ----------------- # długość najdłuższej ścieżki / wysokość drzewa maxpath = 0 # długość najkrótszej ścieżki minpath = 2147483647 # liczba liści leafcount = 0 # liczba węzłów z jedynakiem onechildcount = 0 # suma danych węzłów nodesum = 0 # liczba węzłów n = 0 # wskazanie korzenia drzewa root = None # tablica liczników elementów na poziomach levelcount = [0] vp = [None] # Procedura inicjuje dane, odczytuje # definicję drzewa ze standardowego # wejścia i tworzy jego strukturę # w pamięci. Na wyjściu w zmiennej # root zostaje umieszczony adres # korzenia drzewa # ----------------------------------- def read_bt(): global n, root, levelcount, vp # odczytujemy liczbę węzłów drzewa n = int(input()) # tworzymy tablicę dynamiczną wskaźników vp = [] for i in range(n): vp.append(BTnode()) for i in range(n): # odczytujemy trójkę liczb x = input().split() d = int(x[0]) l = int(x[1]) r = int(x[2]) # tworzymy odwołania if l: l = vp[l] else: l = None if r: r = vp[r] else: r = None # tworzymy węzeł vp[i].left = l vp[i].right = r vp[i].data = d # zapamiętujemy korzeń drzewa root = vp[0] # usuwamy tablicę wskaźników vp = None # tworzymy tablicę liczników # elementów na poziomach levelcount = [0] * n # Procedura przechodzi drzewo # algorytmem DFS:preorder # i odpowiednio przetwarza węzły # zapisując wyniki w zmiennych # globalnych # ------------------------------- def dfs(v): global levelcount, leafcount global maxpath, minpath global onechildcount, nodesum children = 0 if v: # przetwarzamy bieżący węzeł if v.left: children += 1 v.left.level = v.level + 1 if v.right: children += 1 v.right.level = v.level + 1 # test na najdłuższą ścieżkę if v.level > maxpath: maxpath = v.level # test na najkrótszą ścieżkę # do liścia i zliczanie liści if not children: if v.level < minpath: minpath = v.level leafcount += 1 # zliczanie węzłów # na bieżącym poziomie levelcount[v.level] += 1 # zliczanie węzłów z jednym synem if children == 1: onechildcount += 1 # sumowanie zawartości węzłów nodesum += v.data # przechodzimy lewe poddrzewo dfs(v.left) # przechodzimy prawe poddrzewo dfs(v.right) # procedura wyświetla wyniki końcowe # ----------------------------------- def write_bt(): global maxpath, minpath, levelcount global leafcount, onechildcount global nodesum print() print("maxpath =", maxpath) print("minpath =", minpath) print() for i in range(maxpath + 1): print("level ", i, ": number of nodes = ", levelcount[i], sep="") print() print("leafcount =", leafcount) print("onechildcount =", onechildcount) print("nodesum =", nodesum) print() # procedura DFS:postorder usuwająca drzewo # ----------------------------------------- def dfs_release(v): if v: # usuwamy lewe poddrzewo dfs_release(v.left) # usuwamy prawe poddrzewo dfs_release(v.right) # usuwamy odwołania v.left = None v.right = None # procedura sprząta pamięć # ------------------------- def delete_bt(): global levelcount, root levelcount = None # wykorzystujemy DFS:postorder # do usunięcia drzewa dfs_release(root) root = None # ********************** # *** PROGRAM GŁÓWNY *** # ********************** read_bt() # odczytaj i utwórz drzewo dfs(root) # przetwórz drzewo write_bt() # wypisz wyniki delete_bt() # posprzątaj pamięć |
Wynik: |
12 5 1 2 11 3 4 7 5 6 32 7 8 -16 0 9 21 10 11 -2 0 0 3 0 0 17 0 0 -5 0 0 4 0 0 1 0 0 maxpath = 3 minpath = 2 level 0: number of nodes = 1 level 1: number of nodes = 2 level 2: number of nodes = 4 level 3: number of nodes = 5 leafcount = 6 onechildcount = 1 nodesum = 78 |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2024 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.