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

©2026 mgr Jerzy Wałaszek

Drzewa Trie

SPIS TREŚCI
Tematy pomocnicze
Podrozdziały

Budowa drzewa Trie

Drzewo Trie (ang. trie, digital tree, prefix tree, czytaj traj) jest drzewem poszukiwań, które używa się do  przechowywania kluczy tekstowych. Umożliwia ono szybkie wyszukiwanie klucza w  zbiorze w czasie O(n), gdzie n oznacza liczbę znaków tworzących klucz. Drzewo Trie składa się z węzłów, które zawierają przynajmniej dwa elementy:

Tablica triref[ ] posiada tyle komórek, z ilu znaków składa się alfabet używany przez klucze, jeśli są to litery A...Z (bez polskich znaków), to tablica triref[ ] będzie miała 26 komórek indeksowanych od 0 do 25. Każda komórka tej tablicy zawiera albo wskazanie puste nil, albo wskazanie węzła Trie. Węzły nie przechowują bezpośrednio  informacji o literach kluczy. Informacja ta jest zawarta w polu prefend oraz w komórkach tablicy triref[ ] kolejnych węzłów.

Pole prefend jest polem logicznym i zawiera informację o końcu znaków klucza (stan true). Poznamy to na przykładach.

Puste drzewo Trie (nie zawierające żadnego klucza) składa się tylko z jednego węzła Trie - korzenia. W korzeniu pole prefend ma zawsze wartość false, co oznacza, iż żaden klucz tutaj się nie kończy. Tablica triref[ ] korzenia pustego drzewa Trie składa się z samych wskazań pustych nil. Oprócz powyższych pól każdy węzeł Tri może przechowywać dodatkowe dane. Węzły Trie definiowane są następująco:

Pascal
type
  PTRInode = ^TRInode;
  TRInode  = record
    prefend : Boolean;
    triref  : array[0..25] of PTRInode;
    Data: typ_danych;
  end;
C++
struct TRInode
{
  bool prefend;
  TRInode * triref[26];
  typ_danych data;
};
Basic
Type TRInode
  prefend As Boolean
  triref(0 To 25) As TRInode Ptr
  data As typ_danych
End Type
Python (dodatek)
# węzeł TRI
#----------
class TRInode:


    def __init__(self):
        self.prefend = False
        self.triref  = [None] * 26
        self.data    = dane

do podrozdziału  do strony 

Wstawianie klucza do drzewa Trie

Drzewa Trie służą do efektywnego przechowywania kluczy tekstowych (słów). Prześledźmy na przykładzie wstawianie pierwszego klucza "AND" do  pustego drzewa Trie.

Puste drzewo Trie składa się tylko z korzenia, który jest
zwykłym węzłem Trie. Tablica triref[ ] zawiera tylko puste
wskazania. Pole prefend ma wartość false, co oznacza,
iż żaden klucz nie kończy się w tym węźle.
Do drzewa Tri zostanie wstawiony klucz "AND".
Rozpoczynamy "wstawianie" od pierwszej litery klucza
"AND". W tym celu wyliczamy pozycję
pierwszej litery "A" w tablicy triref[ ]:
pozycjakod("A") - kod("A") = 65 - 65 = 0
Następnie sprawdzamy, czy triref[0] wskazuje węzeł Trie.
Nie wskazuje, zatem tworzymy nowy, pusty węzeł Trie
i jego adres wstawiamy do triref[0]. Przechodzimy
do nowo-utworzonego węzła Trie.
Będąc w nowym węźle Trie (A) wyliczamy pozycję litery
"N" w jego tablicy triref[ ], ponieważ klucz "AND" jeszcze
się nie kończy na tej literze:
pozycjakod("N") - kod("A") = 78 - 65 = 13
Sprawdzamy, czy triref[13] zawiera jakieś wskazanie.
Nie zawiera, zatem tworzymy nowy węzeł Trie,
wpisujemy jego adres do triref[13] i przechodzimy
do nowego węzła.
Jesteśmy w utworzonym węźle Trie (N). Wyliczamy pozycję
litery "D" w tablicy triref[ ]:
pozycjakod("D") - kod("A") = 68 - 65 = 3
Sprawdzamy, czy triref[3] zawiera jakieś wskazanie.
Nie zawiera, zatem tworzymy nowy węzeł Trie (D),
wpisujemy jego adres do triref[3] i przechodzimy do niego.
Ponieważ litera "D" była ostatnią literą klucza "AND", to nie
tworzymy już nowego węzła Trie, natomiast wpisujemy
true
do pola prefend. Wstawianie jest skończone.

Węzły drzewa Trie same nie przechowują liter wstawionych kluczy. Informacja o literach znajduje się pośrednio w ich tablicach triref[ ]. Jeśli element tej tablicy wskazuje kolejny węzeł Trie, to oznacza to, iż kolejną literą klucza może być powiązana z tym elementem litera. O tym, czy tak jest, informuje z kolei pole prefend. Jeśli ma ono wartość false, to oznacza, iż klucz nie kończy się tutaj, lecz posiada dalszą literę, o której informuje zawartość tablicy triref[ ].

Do naszego drzewa Trie wstawiliśmy klucz "AND" i drzewo wygląda następująco:

Teraz wstawimy do naszego drzewa klucz "ANY":

Wstawianie rozpoczynamy zawsze od korzenia drzewa
Trie. W tym przypadku drzewo Trie zawiera już klucz "AND".
Będąc w korzeniu obliczamy pozycję pierwszej litery klucza
"ANY" w jego tablicy triref[ ]:
pozycjakod("A") - kod("A") = 65 - 65 = 0
Następnie sprawdzamy, czy element triref[0] wskazuje jakiś
węzeł Tri. Tutaj wskazuje, zatem przechodzimy do
wskazywanego węzła Tri. Oznacza to, iż w drzewie Trie są już
klucze rozpoczynające się od prefiksu "A...".
Będąc w węźle A obliczamy pozycję drugiej litery klucza
"ANY" w jego tablicy triref[ ]:
pozycjakod("N") - kod("A") = 78 - 65 = 13
Sprawdzamy, czy element trieref[13] wskazuje węzeł Trie.
U nas wskazuje, zatem przechodzimy do wskazywanego
węzła (N). Oznacza to, iż w drzewie Tri są klucze
rozpoczynające się od prefiksu "AN...".
Teraz przetwarzamy ostatnią literę "Y". Jesteśmy w węźle N.
Obliczamy pozycję litery "Y" w tablicy triref[ ] węzła N:
pozycja
kod("Y") - kod("A") = 89 - 65 = 24
Sprawdzamy, czy element triref[24] wskazuje węzeł Trie.
Nie wskazuje, zatem tworzymy nowy węzeł Trie
i przechodzimy do niego. Ponieważ litera "Y" była ostatnią
literą klucza "ANY", to w pole prefend wstawiamy wartość
logiczną true.
Drzewo Trie zawiera dwa klucze: "AND" i "ANY". Węzeł Y
jest liściem drzewa Trie.

Wynika stąd następujący algorytm wstawiania klucza do drzewa Tre:

Algorytm wstawiania klucza do drzewa Trie

tri_insert(r, s)

Wejście:

r : korzeń drzewa Trie.
k : łańcuch znaków wstawianego klucza.

Wyjście:

Drzewo Trie ze wstawionym kluczem k.
Adres ostatniego węzła powiązanego z kluczem k.

Elementy pomocnicze:

p : wskazanie węzła drzewa Trie.
i : indeks znaku w k.
c : pozycja powiązana ze znakiem z k w tablicy triref[ ].
kod(znak): zwraca kod ASCII znaku.

Lista kroków:

K01: pr ; rozpoczynamy od korzenia
K02: Dla i = 0,1,...,|k|-1: ; przeglądamy k
     wykonuj kroki K3...K7
K03:   ckod(k[i])-65 ; pozycja znaku w triref[]
K04:   Jeśli ptriref[c] ≠ nil,
       to idź do kroku K07
K05:   Utwórz nowy, pusty węzeł Tri
K06:   ptriref[c] ← adres nowego węzła Tri
K07:   pptriref[c] ; przechodzimy do węzła
K08: pprefendtrue
K09: Zakończ z wynikiem p ; zwracamy wskazanie węzła
     ; powiązanego z ostatnim znakiem klucza

do podrozdziału  do strony 

Wyszukiwanie klucza w drzewie Trie

Standardowy algorytm wyszukiwania klucza w drzewie Trie zwraca logiczne true, jeśli klucz znajduje się w drzewie Tri, inaczej zwraca logiczne false, jeśli drzewo Tri nie przechowuje danego klucza. W zastosowaniach drzew Trie w węzłach umieszcza się zwykle dodatkowe dane powiązane z przechowywanymi kluczami. Najczęściej węzeł skojarzony z ostatnią literą klucza zawiera pożądane dane. Z tego powodu umówmy się, iż nasz algorytm będzie zwracał wskazanie puste, jeśli szukanego klucza brak w drzewie, inaczej będzie zwracał wskazanie węzła powiązanego z ostatnią literą klucza. Ten sposób pracy algorytmu będzie dla nas bardziej użyteczny.

Wyszukiwanie klucza w drzewie Trie jest podobne do wstawiania, różni się tym, iż nie są tu dodawane do drzewa węzły, jedynie sprawdza się, czy dla każdej litery klucza jest w drzewie Trie odpowiedni węzeł oraz czy dla ostatniej litery jej węzeł ma ustawione pole prefend na true. Jeśli te warunki są spełnione, to drzewo Trie zawiera sprawdzany klucz.
Jeśli któryś z warunków jest niespełniony, sprawdzanego klucza brak w drzewie. Wykonywane są następujące operacje:

Algorytm wyszukiwania klucza w drzewie Trie

tri_find(r, k)

Wejście:

r : korzeń drzewa Trie.
k : łańcuch znaków poszukiwanego klucza.

Wyjście:

Wskazanie węzła Trie skojarzonego z ostatnią literą w  poszukiwanym kluczu k, jeśli drzewo Trie zawiera ten klucz lub wskazanie nil, jeśli klucza k brak w drzewie.

Elementy pomocnicze:

p : wskazanie węzła drzewa Trie.
i : indeks znaku w ks.
c : pozycja znaku z k w tablicy triref[ ].
kod(znak): zwraca kod ASCII znaku.

Lista kroków:

K01: pr ; rozpoczynamy od korzenia
K02: Dla i = 0,1,...,|k|-1: ; przeglądamy litery
     wykonuj kroki K03...K05 ; poszukiwanego klucza k
K03:   c ← kod(k[i])-65; ; pozycja litery klucza w triref[]
K04:   Jeśli ptriref[c] = nil, ; jest węzeł Tri dla litery?
       to idź do kroku K08
K05:   pptriref[c] ; tak, przechodzimy do węzła
K06: Jeśli pprefendtrue, ; ostatnia litera?
     to idź do kroku K08 ; brak klucza k
K07: Zakończ z wynikiem p
K08: Zakończ z wynikiem nil

do podrozdziału  do strony 

Usuwanie klucza z drzewa Trie

Usuwanie klucza z drzewa Trie jest trochę bardziej skomplikowane. Musimy tutaj rozważyć kilka przypadków.

  1. Jeśli klucza nie ma w drzewie Trie, to drzewo nie powinno być modyfikowane.
  2. Jeśli klucz znajduje się w drzewie Trie i nie jest on prefiksem innego słowa, ani żaden jego prefiks nie jest innym słowem, to usuwamy wszystkie węzły klucza.
  3. Jeśli klucz jest prefiksem innego, dłuższego słowa, to zerujemy pole prefend w ostatnim węźle związanym z tym kluczem.
  4. Jeśli klucz zawiera prefiks należący do innego klucza, to usuwamy wszystkie węzły od końca klucza do węzła poprzedzającego koniec najdłuższego prefiksu.

Brzmi to nieco skomplikowanie, ale zobaczmy na przykłady:

1. Brak klucza w drzewie Trie:

W drzewie TRIE znajdują się klucze:

Ostatni węzeł klucza zaznaczony jest kolorem żółtym tła oraz czerwonym litery. Chcemy usunąć z drzewa klucz BARKA. Jednakże takiego klucza brak w drzewie. Zatem nic nie robimy.

2. Klucz unikalny, nie będący prefiksem innego klucza oraz nie zawierający jako prefiks innego klucza:

Tym razem chcemy usunąć klucz AGATA. Klucz ten jest w drzewie TRIE i nie jest on ani częścią innego klucza, ani sam nie zawiera jako prefiks innego klucza:

W takiej sytuacji usuwamy wszystkie węzły tego klucza:


3. Klucz jest prefiksem innego klucza:

Usuwamy klucz BAT, który jest prefiksem klucza BATALION. W tym wypadku ustawiamy pole prefend w węźle ostatniej litery na wartość false:


W efekcie w drzewie nie ma już klucza BAT, gdyż w węźle litery T nie kończy się żaden klucz.

4. Klucz posiada wspólne prefiksy z innymi kluczami w drzewie.

Usuwamy klucz DERKACZ. Klucz ten posiada wspólny prefiks z kluczem DERKA. W tym wypadku usuwamy, idąc od końca, wszystkie węzły aż do osiągnięcia najdłuższego wspólnego prefiksu:



W algorytmie usuwania klucza wykorzystuje się sprawdzanie, czy węzeł drzewa Trie nie wskazuje następnego węzła Trie (lub węzłów Trie). Operacja polega na przeglądnięciu tablicy triref[ ] węzła. Jeśli którykolwiek z jej elementów zawiera wskazanie węzła, to zwracamy logiczne false (węzeł Trie nie jest pusty). Jeśli wszystkie jej elementy zawierają wskazania puste nil, to zwracamy logiczne true (węzeł Trie jest pusty).

Algorytm sprawdzania, czy węzeł Trie jest pusty

trie_empty(r)

Wejście:

r : wskazanie węzła Trie.

Wyjście:

true: węzeł r jest pusty.
false: węzeł r nie jest pusty.

Elementy pomocnicze:

i : indeks w tablicy triref[ ].

Lista kroków:

K01: Dla i = 0,1,..., 25: ; Przeglądamy tablicę triref[]
     wykonuj krok K02
K02:   Jeśli triref[] ≠ nil, ; Wskazanie węzła?
       to zakończ z wynikiem false
K03: Zakończ z wynikiem true

Usuwanie klucza wykonywane jest rekurencyjnie.

Algorytm usuwania klucza z drzewa Trie

trie_delete(r,k,d)

Wejście:

r : wskazanie węzła Trie.
k : usuwany klucz.
d : pozycja znaku usuwanego klucza.

Wyjście:

Wskazanie węzła lub nil, jeśli węzeł został usunięty.

Elementy pomocnicze:

c : indeks w tablicy triref[ ].
trie_empty(r) : zwraca true, gdy węzeł r jest pusty.
kod(znak): zwraca kod ASCII znaku.

Lista kroków:

K01: Jeśli r = nil, ; sprawdzamy, czy węzeł r istnieje
     to zakończ z wynikiem nil ; jeśli nie, kończymy
K02: Jeśli d < |k|, ; ostatni znak klucza?
     to idź do kroku K08 ; jeśli nie, idź dalej
K03: rprefend ← false ; zerujemy znacznik końca
K04: Jeśli trie_empty(r) = false,
     to idź do kroku K07
K05: Usuń węzeł r z pamięci ; pusty węzeł
K06: r ← nil
K07: Zakończ z wynikiem r
K08: ckod(k[d])-65 ; obliczamy pozycję litery klucza
K09: rtriref[c] ← trie_delete(rtriref[c],k,d+1) ; rekurencja
K10: Jeśli trie_empty(r) = true i rprefend = false,
     to idź do kroku K05
     Inaczej idź do kroku K07

do podrozdziału  do strony 

Przejście przez drzewo Trie

Przejście drzewa Trie (ang. Trie tree traversal) ma na celu odwiedzenie wszystkich kluczy zawartych w drzewie. Operację tę wykonujemy rekurencyjnie w sposób następujący:

Procedura posiada dwa parametry:

trie_traversal(rk)

r : wskazanie bieżącego węzła drzewa Trie.
k : tworzony klucz.

Procedurę wywołujemy ze wskazaniem korzenia drzewa Trie oraz pustym kluczem k. W procedurze trie_traverse( ) sprawdzamy najpierw, czy wskaźnik r wskazuje węzeł Trie. Jeśli nie, to procedurę kończymy. Następnie sprawdzamy, czy pole prefend węzła r ma stan true. Jeśli tak, to parametr k jest znalezionym kluczem i możemy go przetworzyć. Następnie przeglądamy tablicę triref[ ]. Dla każdego elementu tej tablicy wywołujemy rekurencyjnie procedurę trie_traverse( ) z elementem tablicy triref[ ] oraz kluczem k zwiększonym o literę odpowiadającą elementowi tablicy triref[ ]. Po przetworzeniu wszystkich elementów triref[ ], kończymy.

Algorytm przejścia drzewa Trie

trie_traverse(r,k)

Procedurę wywołujemy ze wskazaniem korzenia drzewa Trie i pustym łańcuchem klucza k.

Wejście:

r : wskazanie węzła Trie.
k : tworzony klucz.

Wyjście:

Przejście przez wszystkie klucze przechowywane w drzewie Trie.

Elementy pomocnicze:

i : indeks w tablicy triref[ ].
chr(kod): zwraca znaku ASCII o danym kodzie.

Lista kroków:

K01: Jeśli r = nil, ; puste wskazanie?
     to zakończ
K02: Jeśli rprefend = true, ; koniec klucza?
     przetwarzaj k ; w tym miejscu można również
     ; przetwarzać węzeł r, który jest powiązany
     ; z ostatnią literą klucza k
K03: Dla i = 0,1,...,25: wykonuj ; przeglądamy triref[]
     trie_traverse(rtriref[i],k+chr(i+65)) ; rekurencja
K04: Zakończ

do podrozdziału  do strony 

Usuwanie drzewa Trie

Drzewo Trie usuwamy w sposób rekurencyjny.

Algorytm usuwania drzewa Trie

trie_remove(r)

Procedurę wywołujemy ze wskazaniem korzenia drzewa Trie. Po zakończeniu operacji korzeń można usunąć z pamięci.

Wejście:

r : wskazanie korzenia drzewa Trie.

Wyjście:

Puste drzewo tri, zawierające jedynie korzeń.

Elementy pomocnicze:

i : indeks w tablicy triref[ ].
trie_empty(r) : zwraca true, gdy węzeł r jest pusty.

Lista kroków:

K01: Jeśli r = nil to zakończ
K02: Dla i = 0,1,...,25: ; przeglądamy triref[]
     wykonuj kroki K03...K06
K03:   Jeśli rtriref[i] = nil, ; pomijamy puste wskazania
       to następny obieg pętli K01
K04:   Jeśli tri_empty(rtriref[i]) = false, ; jeśli węzeł nie jest pusty,
       to tri_remove(rtriref[i]) ; to rekurencyjnie usuwamy jego zawartość
K05:   Usuń węzeł rtriref[i] ; usuwamy sam węzeł z pamięci
K06:   rtriref[i] ← nil
K07: Zakończ

do podrozdziału  do strony 

Programy testowe

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.

W programie tworzone jest puste drzewo Trie, po czym zostają na nim umieszczone 10 razy klucze z puli 16 zdefiniowanych w programie, Następnie program sprawdza 10 losowych kluczy z puli, czy znajdują się na drzewie. Na koniec program usuwa z drzewa 8 razy klucze losowane z puli. Za każdym razem wyświetlana jest zawartość drzewa.
Pascal
// Drzewo TRIE
// Data: 30.10.2024
// (C)2024 mgr Jerzy Wałaszek
//---------------------------

program trie;

// Węzeł Trie  
type
  PTRInode = ^TRInode;
  TRInode  = record
    prefend : Boolean;
    triref  : array[0..25] of PTRInode;
  end;

// Inicjuje węzeł Trie
//--------------------
procedure tri_init(p : PTRInode);
var
  i : integer;

begin
  p^.prefend := false;
  for i := 0 to 25 do
    p^.triref[i] := nil;
end;

// Sprawdza, czy węzeł jest pusty
// r - wskazanie węzła
// Wynik:
// true - węzeł jest pusty
// false - węzeł nie jest pusty
//-------------------------------
function tri_empty(r : PTRInode)
                     : boolean;
var
  i : integer;

begin
  for i := 0 to 25 do
    if r^.triref[i] <> nil then
      exit(false);
  tri_empty := true;
end;

// Wstawia klucz k do drzewa r
// r - korzeń drzewa
// k - klucz
// Zwraca ostatni węzeł klucza
//----------------------------
function tri_insert(r : PTRInode;
                    k : string)
                      : PTRInode;
var
  p : PTRInode;
  i, c : integer;

begin
  p := r;
  for i := 1 to length(k) do
  begin
    c := ord(k[i])-65;
    if p^.triref[c] = nil then
    begin
      new(p^.triref[c]);
      tri_init(p^.triref[c]);
    end;
    p := p^.triref[c];
  end;
  p^.prefend := true;
  tri_insert := p
end;

// Wyszukuje klucz k w drzewie r
// r - korzeń
// k - szukany klucz
// Zwraca ostatni węzeł klucza lub nil
//------------------------------------
function tri_find(r : PTRInode;
                  k : string)
                    : PTRInode;
var
  p : PTRInode;
  i,c : integer;

begin
  p := r;
  for i := 1 to length(k) do
  begin
    c := ord(k[i])-65;
    if p^.triref[c] = nil then exit(nil);
    p := p^.triref[c];
  end;
  if p^.prefend = false then exit(nil);
  tri_find := p;
end;

// Usuwa klucz z drzewa r
// r - wskazanie korzenia
// k - usuwany klucz
// d - pozycja znaku usuwanego klucza.
// Zwraca wskazanie węzła
//------------------------------------
function tri_delete(r : PTRInode;
                    k : string;
                    d : integer)
                      : PTRInode;
var
  c : integer;

begin
  if r = nil then exit(nil);
  if d = length(k)+1 then
  begin
    r^.prefend := false;
    if tri_empty(r) = true then
    begin
      dispose(r);
      exit(nil);
    end;
    exit(r);
  end;
  c := ord(k[d])-65;
  r^.triref[c] :=
    tri_delete(r^.triref[c],k,d+1);
  if (tri_empty(r) = true) and
     (r^.prefend = false) then
  begin
    dispose(r);
    exit(nil);
  end;
  exit(r);
end;

// Przechodzi przez drzewo TRIE
// r - korzeń
// k - klucz
//-----------------------------
procedure tri_traverse(r : PTRInode;
                       k : string);
var
  i : integer;

begin
  if r = nil then exit();
  if r^.prefend = true then
    writeln(k);
  for i := 0 to 25 do
    tri_traverse(r^.triref[i],k+chr(i+65));
end;

// Usuwa drzewo TRIE
// r - korzeń
//------------------
procedure tri_remove(r : PTRInode);
var
  i : integer;

begin
  if r <> nil then
    for i := 0 to 25 do
    begin
      if r^.triref[i] = nil then continue;
      if tri_empty(r^.triref[i]) = false then
        tri_remove(r^.triref[i]);
      dispose(r^.triref[i]);
      r^.triref[i] := nil;
    end;
end;

// Program główny
//---------------

var
  // Klucze
 keys : array[0..15] of string =
    ('ALGA', 'ALGORYTM',
     'ALT', 'ARGON',
     'BRAMA', 'BRAWO',
     'KOMAR','KOC',
     'KOCZKODAN','LAWETA',
     'LAWA','LEN',
     'MORZE','MORA',
     'MAT','MATA');

  i,j  : integer;
  root : PTRInode;

begin
  randomize();

  // Tworzymy puste drzewo TRIE
  new(root);
  tri_init(root);

  // W drzewie umieszczamy 10 losowych kluczy
  writeln('DODAJEMY:');
  for i := 1 to 10 do
  begin
    j := random(16);
    writeln(keys[j]);
    tri_insert(root,keys[j])
  end;
  writeln;
  writeln('DRZEWO TRIE:');
  tri_traverse(root,'');
  writeln;

  // Szukamy 10 losowych kluczy
  for i := 1 to 10 do
  begin
    j := random(16);
    write('KLUCZ ',keys[j],' ');
    if tri_find(root,keys[j]) = nil then
      write('NIE');
    writeln('OBECNY');
  end;
  writeln;

  // Usuwamy 8 losowych kluczy
  writeln('USUWAMY:');
  for i := 1 to 8 do
  begin
    j := random(16);
    writeln(keys[j]);
    root := tri_delete(root,keys[j],1);
  end;
  writeln;
  writeln('DRZEWO TRIE:');
  tri_traverse(root,'');
  writeln;

  // Usuwamy drzewo
  tri_remove(root);
  dispose(root);
end.
C++
// Drzewo TRIE
// Data: 30.10.2024
// (C)2024 mgr Jerzy Wałaszek
//---------------------------

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>

using namespace std;

// Węzeł Trie
struct TRInode
{
  bool prefend;
  TRInode * triref[26];
};

// Inicjuje węzeł Trie
//--------------------
void tri_init(TRInode * p)
{
  int i;

  p->prefend = false;
  for(i = 0; i < 26; i++)
    p->triref[i] = nullptr;
}

// Sprawdza, czy węzeł jest pusty
// r - wskazanie węzła
// Wynik:
// true - węzeł jest pusty
// false - węzeł nie jest pusty
//-------------------------------
bool tri_empty(TRInode * r)
{
  int i;

  for(i = 0; i < 26; i++)
    if(r->triref[i]) return false;
  return true;
}

// Wstawia klucz k do drzewa r
// r - korzeń drzewa
// k - klucz
// Zwraca ostatni węzeł klucza
//----------------------------
TRInode * tri_insert(TRInode * r,
                     string k)
{
  TRInode * p;
  int i, c;

  p = r;
  for(i = 0; i < (int) k.length(); i++)
  {
    c = k[i]-65;
    if(!p->triref[c])
    {
      p->triref[c] = new(TRInode);
      tri_init(p->triref[c]);
    }
    p = p->triref[c];
  }
  p->prefend = true;
  return p;
}

// Wyszukuje klucz k w drzewie r
// r - korzeń
// k - szukany klucz
// Zwraca ostatni węzeł klucza lub nil
//------------------------------------
TRInode * tri_find(TRInode * r,
                   string k)
{
  TRInode * p;
  int i, c;

  p = r;
  for(i = 0; i < (int)k.length(); i++)
  {
    c = k[i]-65;
    if(!p->triref[c]) return nullptr;
    p = p->triref[c];
  }
  if(!p->prefend) return nullptr;
  return p;
}

// Usuwa klucz z drzewa r
// r - wskazanie korzenia
// k - usuwany klucz
// d - pozycja znaku usuwanego klucza.
// Zwraca wskazanie węzła
//------------------------------------
TRInode * tri_delete(TRInode * r,
                     string k,
                     int d)
{
  int c;

  if(!r) return nullptr;
  if(d == (int)k.length())
  {
    r->prefend = false;
    if(tri_empty(r))
    {
      delete r;
      return nullptr;
    }
    return r;
  }
  c = k[d]-65;
  r->triref[c] =
    tri_delete(r->triref[c],k,d+1);
  if(tri_empty(r) && !r->prefend)
  {
    delete r;
    return nullptr;
  }
  return r;
}

// Przechodzi przez drzewo TRIE
// r - korzeń
// k - klucz
//-----------------------------
void tri_traverse(TRInode * r,
                  string k)
{
  int i;

  if(!r) return;
  if(r->prefend)
    cout << k << endl;
  for(i = 0; i < 26; i++)
    tri_traverse(r->triref[i],k+char(i+65));
}

// Usuwa drzewo TRIE
// r - korzeń
//------------------
void tri_remove(TRInode * r)
{
  int i;

  if(r)
    for(i = 0; i < 26; i++)
    {
      if(!r->triref[i]) continue;
      if(!tri_empty(r->triref[i]))
        tri_remove(r->triref[i]);
      delete r->triref[i];
      r->triref[i] = nullptr;
    }
}

// Program główny
//---------------
main()
{

  // Klucze
  string keys[16] =
    {"ALGA","ALGORYTM",
     "ALT", "ARGON",
     "BRAMA","BRAWO",
     "KOMAR","KOC",
     "KOCZKODAN","LAWETA",
     "LAWA","LEN",
     "MORZE","MORA",
     "MAT","MATA"};
  int i,j;
  TRInode * root;

  // Inicjujemy generator pseudolosowy
  srand(time(NULL));

  // Tworzymy puste drzewo TRIE
  root = new(TRInode);
  tri_init(root);

  // W drzewie umieszczamy 10 losowych kluczy
  cout << "DODAJEMY:" << endl;
  for(i = 0; i < 10; i++)
  {
    j = rand() % 16;
    cout << keys[j] << endl;
    tri_insert(root,keys[j]);
  }
  cout << endl
       << "DRZEWO TRIE:" << endl;
  tri_traverse(root,"");
  cout << endl;

  // Szukamy 10 losowych kluczy
  for(i = 0; i < 10; i++)
  {
    j = rand() % 16;
    cout << "KLUCZ " << keys[j] << " ";
    if(!tri_find(root,keys[j]))
      cout << "NIE";
    cout << "OBECNY" << endl;
  }

  // Usuwamy 8 losowych kluczy
  cout << endl
       << "USUWAMY:" << endl;
  for(i = 0; i < 8; i++)
  {
    j = rand() % 16;
    cout << keys[j] << endl;
    root = tri_delete(root,keys[j],0);
  }
  cout << endl
       << "DRZEWO TRIE:" << endl;
  tri_traverse(root,"");
  cout << endl;
  // Usuwamy drzewo
  tri_remove(root);
  delete root;
}
Basic
' Drzewo TRIE
' Data: 30.10.2024
' (C)2024 mgr Jerzy Wałaszek
'---------------------------

' Węzeł Trie
Type TRInode
  prefend As Boolean
  triref(0 To 25) As TRInode Ptr
End Type

' Inicjuje węzeł Trie
'--------------------
Sub tri_init(ByVal p As TRInode Ptr)
  Dim i As Integer

  p->prefend = False
  For i = 0 To 25
    p->triref(i) = 0
  Next
End Sub

' Sprawdza, czy węzeł jest pusty
' r - wskazanie węzła
' Wynik:
' true - węzeł jest pusty
' false - węzeł nie jest pusty
'-------------------------------
Function tri_empty(ByVal r As TRInode Ptr) _
                           As Boolean
  Dim i As Integer
  
  For i = 0 To 25
    If r->triref(i) <> 0 Then Return False
  Next
  Return True
End Function

' Wstawia klucz k do drzewa r
' r - korzeń drzewa
' k - klucz
' Zwraca ostatni węzeł klucza
'----------------------------
Function tri_insert(ByVal r As TRInode Ptr,_
                    ByVal k As String) _
                            As TRInode Ptr
  Dim p As TRInode Ptr
  Dim As Integer i, c

  p = r
  For i = 0 To Len(k) - 1
    c = k[i] - 65
    If p->triref(c) = 0 Then
      p->triref(c) = New TRInode
      tri_init(p->triref(c))
    End If
    p = p->triref(c)
  Next
  p->prefend = True
  Return p
End Function

' Wyszukuje klucz k w drzewie r
' r - korzeń
' k - szukany klucz
' Zwraca ostatni węzeł klucza lub 0
'----------------------------------
Function tri_find(ByVal r As TRInode Ptr, _
                  ByVal k As String) _
                          As Trinode Ptr
  Dim p As TRInode Ptr
  Dim As Integer i, c

  p = r
  For i = 0 To Len(k) - 1
    c = k[i] - 65
    If p->triref(c) = 0 Then Return 0
    p = p->triref(c)
  Next
  If p->prefend = False Then Return 0
  Return p
End Function

' Usuwa klucz z drzewa r
' r - wskazanie korzenia
' k - usuwany klucz
' d - pozycja znaku usuwanego klucza.
' Zwraca wskazanie węzła
'------------------------------------
Function tri_delete(ByVal r As TRInode Ptr, _
                    ByVal k As String, _
                    ByVal d As Integer) _
                            As TRInode Ptr
  Dim c As Integer

  If r = 0 Then Return 0
  If d = Len(k) Then
    r->prefend = False
    If tri_empty(r) = True Then
      Delete r
      Return 0
    End If
    Return r
  End If
  c = k[d] - 65
  r->triref(c) = _
    tri_delete(r->triref(c),k,d + 1)
  If (tri_empty(r) = True) AndAlso _
     (r->prefend = False) Then
    Delete r
    Return 0
  End If
  Return r
End Function

' Przechodzi przez drzewo TRIE
' r - korzeń
' k - klucz
'-----------------------------
Sub tri_traverse(ByVal r as TRInode Ptr, _
                 ByVal k As String)
  Dim i As Integer

  If r = 0 Then Return
  If r->prefend = True Then _
    Print k
  For i = 0 To 25
    tri_traverse(r->triref(i),k+chr(i+65))
  Next
End Sub

' Usuwa drzewo TRIE
' r - korzeń
'------------------
Sub tri_remove(ByVal r As TRInode Ptr)
  Dim i As Integer

  If r <> 0 Then 
    For i = 0 To 25
      If r->triref(i) = 0 Then Continue For
      If tri_empty(r->triref(i)) = False Then _
        tri_remove(r->triref(i))
      Delete r->triref(i)
      r->triref(i) = 0
    Next
  End If
End Sub  

' Program główny
'---------------

' Klucze
Dim As String keys(15) = _
    {"ALGA","ALGORYTM",_
     "ALT", "ARGON",_
     "BRAMA","BRAWO",_
     "KOMAR","KOC",_
     "KOCZKODAN","LAWETA",_
     "LAWA","LEN",_
     "MORZE","MORA",_
     "MAT","MATA"}
Dim As Integer i,j
Dim root As TRInode Ptr

' Inicjujemy generator pseudolosowy
Randomize

' Tworzymy puste drzewo TRIE
root = new TRInode
tri_init root

' W drzewie umieszczamy 10 losowych kluczy
Print "DODAJEMY:"
For i = 1 To 10
  j = Int(Rnd * 16)
  Print keys(j)
  tri_insert root,keys(j)
Next
Print
Print "DRZEWO TRIE:"
tri_traverse root,""
Print

' Szukamy 10 losowych kluczy
For i = 1 To 10
  j = Int(Rnd * 16)
  Print "KLUCZ "; keys(j);" ";
  If tri_find(root,keys(j)) = 0 Then _
    Print "NIE";
  Print "OBECNY"
Next  
Print

' Usuwamy 8 losowych kluczy
Print "USUWAMY:"
For i = 1 To 8
  j = Int(Rnd * 16)
  Print keys(j)
  root = tri_delete(root,keys(j),0)
Next
Print
Print "DRZEWO TRIE:"
tri_traverse root,""
Print

' Usuwamy drzewo
tri_remove root
Delete root
End
Python (dodatek)
# Drzewo TRIE
# Data: 30.10.2024
# (C)2024 mgr Jerzy Wałaszek
#---------------------------

import random

# węzeł TRI
class TRInode:
    def __init__(self):
        self.prefend = False
        self.triref  = [None] * 26


# Sprawdza, czy węzeł jest pusty
# r - wskazanie węzła
# Wynik:
# true - węzeł jest pusty
# false - węzeł nie jest pusty
#-------------------------------
def tri_empty(r):
    for i in range(26):
        if r.triref[i]:
            return False
    return True


# Wstawia klucz k do drzewa r
# r - korzeń drzewa
# k - klucz
# Zwraca ostatni węzeł klucza
def tri_insert(r, k):
    p = r
    for i in range(len(k)):
        c = ord(k[i]) - 65
        if not p.triref[c]:
            p.triref[c] = TRInode()
        p = p.triref[c]
    p.prefend = True
    return p


# Wyszukuje klucz k w drzewie r
# r - korzeń
# k - szukany klucz
# Zwraca ostatni węzeł klucza lub 0
def tri_find(r, k):
    p = r
    for i in range(len(k)):
        c = ord(k[i]) - 65
        if not p.triref[c]:
            return None
        p = p.triref[c]
    if not p.prefend:
        return None
    return p


# Usuwa klucz z drzewa r
# r - wskazanie korzenia
# k - usuwany klucz
# d - pozycja znaku usuwanego klucza.
# Zwraca wskazanie węzła
def tri_delete(r, k, d):
    if not r: return None
    if d == len(k):
        r.prefend = False
        if tri_empty(r):
            del r
            r = None
        return r
    c = ord(k[d]) - 65
    r.triref[c] = tri_delete(r.triref[c],k,d+1)
    if tri_empty(r) and not r.prefend:
        del r
        r = None
    return r


# Przechodzi przez drzewo TRIE
# r - korzeń
# k - klucz
def tri_traverse(r, k):
    if not r: return
    if r.prefend: print(k)
    for i in range(26):
        tri_traverse(r.triref[i],k+chr(i+65))


# Usuwa drzewo TRIE
# r - korzeń
def tri_remove(r):
    if r:
        for i in range(26):
            if not r.triref[i]: continue
            if not tri_empty(r.triref[i]):
                tri_remove(r.triref[i])
            r.triref[i] = None


# Program główny
#---------------

# Klucze
keys = ["ALGA","ALGORYTM",
        "ALT", "ARGON",
        "BRAMA","BRAWO",
        "KOMAR","KOC",
        "KOCZKODAN","LAWETA",
        "LAWA","LEN",
        "MORZE","MORA",
        "MAT","MATA"]
root = TRInode()

# W drzewie umieszczamy 10 losowych kluczy
print("DODAJEMY:")
for i in range(10):
    j = random.randrange(16)
    print(keys[j])
    tri_insert(root, keys[j])
print()
print("DRZEWO TRIE:")
tri_traverse(root, "")
print()
# Szukamy 10 losowych kluczy
for i in range(10):
    j = random.randrange(16)
    print("KLUCZ", keys[j], end=" ")
    if not tri_find(root,keys[j]):
        print("NIE", end="")
    print("OBECNY")
print()
print("USUWAMY:")
for i in range(8):
    j = random.randrange(16)
    print(keys[j])
    root = tri_delete(root, keys[j],0)
print()
print("DRZEWO TRIE:")
tri_traverse(root, "")
print()
tri_remove(root)
del root
Wynik:
DODAJEMY:
ALGORYTM
BRAMA
KOC
BRAWO
KOCZKODAN
KOMAR
KOCZKODAN
MORZE
ARGON
KOCZKODAN

DRZEWO TRIE:
ALGORYTM
ARGON
BRAMA
BRAWO
KOC
KOCZKODAN
KOMAR
MORZE

KLUCZ MATA NIEOBECNY
KLUCZ ARGON OBECNY
KLUCZ LAWA NIEOBECNY
KLUCZ MORZE OBECNY
KLUCZ ARGON OBECNY
KLUCZ BRAWO OBECNY
KLUCZ ALGA NIEOBECNY
KLUCZ MAT NIEOBECNY
KLUCZ BRAWO OBECNY
KLUCZ LEN NIEOBECNY

USUWAMY:
ARGON
ALGORYTM
KOMAR
KOCZKODAN
ALGORYTM
LEN
KOCZKODAN
BRAMA

DRZEWO TRIE:
BRAWO
KOC
MORZE

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

Informacje dodatkowe.