Drzewa BST

czarownik

Ogólnie pomysł drzew jest bardzo prosty: Mając jeden element główny (zwany węzłęm głównym), tworzymy jego "dzieci", które są połączone z węzłem głównym z lewej i prawej strony (tzw. dziec - z lewej dziecko o mniejszej wartości a z prawej o większej). Każde dziecko może posiadać kolejną dwójkę dzieci (lewe i prawe). Węzeł główny (jak i dzieci) to nic innego jak rekordy w pamięci, skłądające się takich pól jak: dane różnych typów, oraz zmiennych typu takiego jak drzewko (lewy i prawy potomek). Jest to prosty przykład, jak korzystać z takich struktur danych jak drzewa BST. Poniżej zamieszczam kod:

uses
  SysUtils;
type
  TDana = integer; // deklaracja jakiejś danej
  Drzewo = ^TDrzewo; // typ wskazujący na drzewko bo przecież musimy pamiętac jego potomków...
  TDrzewo = record   // drzewko
    etykieta: TDana;  // to jest nasza dana, może być ich oczywiście więcej 
    lewy, prawy: Drzewo;  // potomkowie
  end;

var
  i, a, n: integer;
  dana: TDana;
  drzewko: Drzewo;

// procedura wstawiania
procedure Wstaw(var W : Drzewo; Co : TDana);
begin
  if W = nil then
  begin
    new(W);
    if W = nil then
      exit;
    W^.lewy:=nil;
    W^.prawy:=nil;
    W^.etykieta:=Co;
  end
  else
  if W^.etykieta > Co then
    Wstaw(W^.lewy,Co)
  else
  if W^.etykieta < Co then
    Wstaw(W^.prawy,Co);
end;

// procedura usuwania
procedure Usun(var W : Drzewo; Co : TDana);
var
  T,X,Y,Z: Drzewo; {X?rodzic, Y-usuwany, Z-dziecko}
begin
  X:=nil;
  Y:=W;
  while Y<>nil do
  begin
  if Y^.etykieta = Co then
    break
  else
  begin
    X:=Y;
    if Y^.etykieta > Co then
      Y:=Y^.lewy
    else
      Y:=Y^.prawy;
  end;
  end;
  if Y<>nil then
    if (Y^.lewy= nil) or (Y^.prawy=nil) then
    begin
      if (Y^.lewy = nil) and (Y^.prawy = nil) then
        Z:=nil
      else
        if (Y^.lewy =nil) then
          Z:=Y^.prawy
        else
          Z:=Y^.lewy;
      if X=nil then
        W:=Z
      else
        if Y=X^.lewy then
          X^.lewy:=Z
        else
          X^.prawy:=Z;
      dispose(Y);
    end
    else
    begin
      Z:=Y^.prawy;
      if Z^.lewy=nil then
        Y^.prawy:= Z^.prawy
      else
      begin
        repeat
          T:=Z;
          Z:=Z^.lewy;
        until
          Z^.lewy=NIL;
        T^.lewy:=Z^.prawy;
      end;
      Y^.etykieta:= Z^.etykieta;
      dispose(Z);
    end;
end;

{ 
  procedura wyświetlania. tutaj użyłem metody Inorder (lewe dziecko, dana, prawe dziecko).
  ale są jeszcze dwie: Postorder (lewe dziecko, prawe dziecko, dana) i 
  Preorder (dana, lewe dziecko i prawe dziecko).
}
procedure drukuj(W : Drzewo);
begin
  if W <> nil then
  begin
    drukuj(W^.Lewy);
    Writeln(W^.Etykieta);
    drukuj(W^.Prawy);
  end;
end;

// procedura szukania - zwykłe przejście przed drzewo
procedure szukaj(W : Drzewo; dana: tdana);
begin
  if W <> nil then
  begin
    szukaj(W^.Lewy, dana);
    if W^.etykieta = dana then
    begin
      Writeln('znaleziona: ', W^.etykieta);
      Exit;
    end;
    szukaj(W^.Prawy, dana);
  end;
end;

// program główny - wywołanie tego co napisałem wyżej...
begin
  Writeln('Podaj liczbe wartosci');
  Readln(a);
  Writeln('Podaj ', a, ' liczb');
  for i:= 1 to a do
  begin
    Readln(n);
    Wstaw(drzewko, n);
  end;
  writeln;
  Writeln('zawartosc drzewa:');
  drukuj(drzewko);
  Writeln;
  Writeln('podaj szukana wartosc:');
  Readln(a);
  szukaj(Drzewko, a);
  Writeln;
  Writeln('podaj wartosc do usuniecia');
  readln(a);
  usun(drzewko, a);
  writeln;
  drukuj(Drzewko);
  Readln;
end.

A oto implementacja drzewa BST w języku C. Algorytm wstawiania jest rekurencyjny. Przykład pochodzi z witryny: http://programmuj.blogspot.com/2011/08/implementacja-drzewa-bstbinarnego.html

    #include  <stdlib.h>
    #include  <stdio.h>
    #include  <string.h>
     
     
    struct node{
    int key;
    struct node *lewy;
    struct node *prawy;
    }*korzen=NULL;
     
     
     
    void push(struct node *&korzen,int x)
    {
         if(korzen==NULL)
         {
           korzen=(struct node*)malloc(sizeof(struct node));
           korzen->lewy=NULL;
           korzen->prawy=NULL;
           korzen->key=x;
           return;
           }else
           {
                if(x<korzen->key)
                push(korzen->lewy,x);
                else push(korzen->prawy,x);
                }
    }
     
     
     
    void showrek(struct node *korzen) //lewe poddrzewo, prawe,rekurencyjnie
    {
         
    if(korzen)
    {
           
         
              showrek(korzen->lewy);
              printf("%d ",korzen->key);
              showrek(korzen->prawy);
    }        
    }
     
     
    int main()
    {
        int n,i,x;
        printf("Ile elementow dodad do drzewa??\n");
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
          scanf("%d",&x);
          push(korzen,x);
         }
       showrek(korzen);
    system("PAUSE");
     
    }

No i to byłoby na tyle. Sądze, że nikt nie powinien mieć problemu ze zrozumieniem tego. Wspomnę jeszcze (dla tych co nie wiedzą), że mamy jeszcze inne drzewka - drzewa AVL (znane jako drzewa "wyważone"), drzewa 2-3-4 i drzewa czerwono - czarne - ale o tym może w następnym artykule.

4 komentarzy

Ta procedura szukania jest mało przydatna lepiej jak by zwracała wskaźnik na element drzewa:)

witam potrzebuje kodu do drzewa AVL. Mój @ to pawelpodlak@o2.pl
dzieki pozdrawiam

tak... ja tez mialem na studiach drzewa... ale nie pisalm egzaminu :) piwo dla tego ktory wymyslil przepis z laboratoriow na egzamin dla piatkowiczow :)

Dobry artykuł. Przypomniał mi o egzaminie z programowania, na którym to na pierwszym terminie dostaliśmy program oparty o drzewa... o zgrozo... nikt tego nie umiał, ale jakoś niektórzy zdali ;)