Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

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
I LO w Tarnowie

Badanie drzewa binarnego

SPIS TREŚCI
Tematy pomocnicze

Problem

Dla danego drzewa binarnego należy określić:

  1. Długość najdłuższej ścieżki od korzenia do liścia (czyli wysokość drzewa).
  2. Długość najkrótszej ścieżki od korzenia do liścia.
  3. Liczbę węzłów na każdym poziomie.
  4. Liczbę liści.
  5. Liczbę węzłów zawierających tylko jednego syna
  6. Sumę danych zawartych w węzłach.

Rozwiązanie

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ł.

Pascal
type
  PBTnode = ^BTnode;
  BTnode  = record
    left  : PBTnode;
    right : PBTnode;
    level : Integer;
    data  : typ_danych;
  end;
C++
struct BTnode
{
  BTnode * left;
  BTnode * right;
  int level;
  typ_danych data;
};
Basic
Type 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:

Pierwsza liczba n będzie określała ilość wszystkich węzłów w drzewie. Umówmy się, że węzły ponumerujemy kolejnymi liczbami od 0 do n–1 idąc od strony lewej do prawej na kolejnych poziomach.

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:

Na rysunku poniżej przedstawione jest drzewo binarne. Wewnątrz węzłów znajdują się przechowywane w tych węzłach liczby. Numery węzłów są  podane w kolorze czerwonym pod każdym węzłem. Na przykład węzeł nr 3 przechowuje liczbę 32 i posiada dwóch synów: lewego – węzeł 7 i prawego – węzeł 8.
obrazek   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:

  1. Odczytujemy n.
  2. Tworzymy dynamicznie tablicę n wskaźników do węzłów drzewa.
  3. Dynamicznie tworzymy n węzłów i ich adresy zapamiętujemy we wskaźnikach.
  4. Odczytujemy n trójek liczb. Numer trójki określa numer węzła. Pierwszą liczbę wstawiamy w pole data, następne dwie liczby, jeśli są różne od zera, dadzą numery wskaźników w tablicy, które należy przepisać odpowiednio w pole leftright węzła.
  5. Po odczycie danych zapamiętujemy w osobnej zmiennej wskazanie korzenia, czyli pierwszy wskaźnik w tablicy wskaźników.
  6. Tablicę dynamiczną wskaźników usuwamy z pamięci.

Długość najdłuższej ścieżki

Tworząc węzły, zerujemy w  nich pola level. Przed rozpoczęciem przeglądania drzewa tworzymy zmienną maxpath, w której umieszczamy wartość 0. W trakcie przechodzenia drzewa przetwarzamy węzeł:
  1. Jeśli posiada syna, to w polu level syna umieszczamy zawartość pola level węzła powiększoną o 1. W ten sposób synowie będą miały zawsze numer poziomu o 1 większy od swoich ojców.
  2. Porównujemy pole level przetwarzanego węzła ze zmienną maxpath. Jeśli level ma wartość większą, to zapisujemy ją w maxpath. Po przejściu całego drzewa maxpath będzie zawierał największą wartość poziomu, czyli wysokość drzewa.

Długość najkrótszej ścieżki do liścia

Przed rozpoczęciem przeglądania drzewa tworzymy zmienną minpath, w której umieszczamy największą wartość całkowitą (dla liczb 32  bitowych jest to 2147483647). W trakcie przechodzenia drzewa sprawdzamy, czy węzeł jest liściem (tak będzie, jeśli pola left i right zawierają wskazanie puste). Jeśli tak, to porównujemy wartość pola level ze zmienną minpath. Jeśli jest mniejsze, zapamiętujemy je w minpath. Po przejściu całego drzewa minpath będzie zawierało długość najkrótszej ścieżki.

Liczba węzłów na każdym poziomie

Przed rozpoczęciem przeglądania drzewa tworzymy dynamicznie tablicę levelcount liczników i zerujemy je. Kolejne liczniki będą zliczały węzły na kolejnych poziomach. Tworząc tablicę musimy określić liczbę poziomów. W najbardziej niekorzystnym przypadku będzie ich n (drzewo binarne posiadające wszystkie węzły oprócz ostatniego z jednym synem). Dlatego tworzymy tablicę n elementową. Faktyczną wysokość drzewa poznamy dopiero po wykonaniu przejścia DFS.

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.

Liczba liści

Przed rozpoczęciem przeglądania drzewa tworzymy zmienną leafcount i nadajemy jej wartość 0. W trakcie przeglądania drzewa sprawdzamy, czy bieżący węzeł jest liściem (pola left i right zawierają wskazanie puste) i jeśli tak, to zwiększamy o 1 zmienną leafcount. Po przejściu drzewa zmienna zawiera liczbę liści.

Liczba węzłów z jednym synem

Przed rozpoczęciem przeglądania drzewa tworzymy zmienną onechildcount i nadajemy jej wartość 0. W trakcie przeglądania drzewa sprawdzamy, czy bieżący węzeł posiada tylko jednego syna (tylko jedno z pól left i right zawiera wskazanie puste) i jeśli tak, to zwiększamy o 1 zmienną onechildcount. Po przejściu drzewa zmienna zawiera liczbę węzłów z jednym synem.

Suma zawartości węzłów

Przed rozpoczęciem przeglądania drzewa tworzymy zmienną nodesum i nadajemy jej wartość 0. W trakcie przeglądania do zmiennej nodesum dodajemy zawartość pola data bieżącego węzła. Po przejściu drzewa w nodesum będzie suma zawartości wszystkich węzłów drzewa.

Przykładowe programy

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.
C++
// 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
obrazek

do podrozdziału  do strony 

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: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.