|
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 |
©2026 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 ©2026 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.