Wykład 9 - struktury dynamiczne uporządkowane (część 2) 9.1. Drzewa (c.d.)
9.2. Definicje
9.3. Obroty w węzłach
9.4. Wstawianie do korzenia drzew binarnych 9.5. Wyważanie drzew binarnych
9.6. Przejście prze drzewo
9.2. Złożoność obliczeniowa drzew i list
Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 91
9.1.1. Definicje drzew Definicja 1:
Drzewa to matematyczna abstrakcja, która umożliwia:
· opisywanie własności algorytmów ( np algorytmy: dziel i zwyciężaj” , kopcowanie)
· opisywanie konkretnych struktur danych, które są realizacjami drzew (np.
drzewa poszukiwań binarnych, drzewa czerwono-czarne, B-drzewa).
Klasyfikacja drzew:
· drzewa binarne i m-drzewa
· drzewa z korzeniem
· drzewa uporządkowane
· drzewa swobodne
w ęzeł
zew nętrzny
w ęzeł
w ew nętrzny 20
10 30
35
40 50
60
Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 9
Definicja 2:
Drzewo binarne to węzeł zewnętrzny lub dołączony do pary drzew
binarnych, które nazywa się odpowiednio lewym i prawym poddrzewem tego węzła.
Definicja 3:
M-drzewo to węzeł zewnętrzny lub węzeł wewnętrzny dołączony do uporządkowanego ciągu drzew, które są również m-drzewami.
Definicja 4: Drzewo z korzeniem (lub drzewo nieuporządkowane) to węzeł (nazywany korzeniem) połączony z wielozbiorem drzew z korzeniem.
Taki wielozbiór nazywamy jest lasem nieuporządkowanym.
Drzewa nieuporządkowane są często reprezentowane w programach jako drzewa uporządkowane.
2
ojciec
Syn(następca) węzeł
brat
liść korzeń
10 20 40
35 50 60
30
Definicja 6: Istnieje jednoznaczne odwzorowanie drzew binarnych na lasy uporządkowane i na odwrót.
20
20 10
19 13
15 16
17
10 19
13 15 16 17
10 19
13 15 16
20
17 20
10
19 13
15
16
17
Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 9
Definicja 5: Drzewo uporządkowane to węzeł (nazywany korzeniem) dołączony do ciągu rozłącznych drzew. Taki ciąg nazywany jest lasem. W przeciwieństwie do m-drzew może mieć dowolną liczbę synów ( następców), lecz ustala się ich kolejność (porządek).
3
Definicja 7: Drzewo swobodne czyli drzewo bez korzenia to graf, który zawiera n-1 krawędzi i nie ma cykli, jest spójny, każde dwa wierzchołki łączy dokładnie jedna ścieżka prosta.
Graf jest parą zbiorów węzłów i krawędzi łączących po dwa różne węzły, przy czym każde dwa węzły łączy co najwyżej jedna krawędź.
Ścieżka prosta to ciąg krawędzi prowadzący od jednego węzła do innego, w którym nie powtarza się żaden węzeł dwukrotnie.
Graf jest spójny, jeśli jego dowolne dwa węzły można połączyć ścieżką prostą.
Ścieżka jest cyklem wtedy, gdy różni się od ścieżki prostej tylko tym, że pierwszy i ostatni węzeł to ten sam węzeł.
Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 94
9.1.2. Obroty w węzłach
· obrót w lewo
A
E
C
E
C A
procedure Obrot_L(var Wezel : POsobaD);
var P : POsobaD;
begin
P := Wezel^.Prawy;
Wezel^.Prawy := P^.Lewy;
P^.Lewy := Wezel;
Wezel := P;
end;
· obrót w prawo
E A
C
A
C
E
procedure Obrot_P(var Wezel : POsobaD);
var P : POsobaD;
begin
P := Wezel^.Lewy;
Wezel^.Lewy := P^.Prawy;
P^.Prawy := Wezel;
Wezel := P;
end;
Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 95
9.1.3. Wstawianie do korzenia drzewa
· Wstaw następujący ciąg: 8, 6, 7, 9, 3, 11, 2, 5, 4, 10, 15, 13 do drzewa binarnego jako liście
8
6 9
3
1
2 4
5 1 8
8
6
8
6 9
1 2
1
2 4
8
6 9
3
5
11 1 2
1
2 4
5
8
6
7 8
6 9
3 11
1
2 4
5 6
8
6 9
3 11
2
1
2 4
5 6
8
6 9
3
1
2 4
5
11 6
6
8
6 9
3
5 10
11
2
1
2 4
5
8 10
6
7 8
6 9
3
5 10
11
2
1
2 4
5
8 10
6 7
7
8
6 9
3
5
4 11
2
1
2 4
5
8
9 6
7
4 9
4 9
15 11 2
7
5 8
4 9
10 10
15 11
13 12
7 7 7
7 7 7
7 7 7
3
3
3 3
3
3
3 3
3
8
6 1 2
7 3
Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 96
· Wstaw następujący ciąg: 8, 6, 7, 9, 3, 11, 2, 5, 4, 10, 15, 13 wstawiając do korzenia drzewa
6
7
8 8
6
6
8
9
3
8
7
6 9
8
9
7
6
3
7
6 8
9
11
2
7
8
5 6
9
11
6 8
8 7
3
7 9
7
3
6 8
9 3
8 6
7
11 9 3
8 6
7
2 3
9 11
6 7
8
2
11
7
6 8 9 3
6 2
11
7
5 8 9 3
8 2
11
5
7
6 9 3
8 2
11
9
7
6 5 3
8 2
11
9
7
6 5
3
8 2
5
9
7
6
11 3
8 5
3 9
7
6 2 11
4
8 5
4 9
7
6 2 11
3
8 5
2 9
7
6 4 11
3
8 4
9 11
7
6 2 5
3
1 1
2
2
1
3
2
3
1
3
1 2
4
2
3
1 4
4
3
2 1
5
4 3
5 1
2
4 5
3
2 1
5
3 6
2 1
4
5
6
4
5
7
3
2 1
4
3
2 1
6
6
7
5
4
7
6
5
4
7 7
6
5
4
5
4
3
2 1
3
2 1
8
3
8 1
2
5
8
8 4
3 3
2 1 2 1
7
6 6
2 1
5 4
8
3 7
6
7 8 8
8
5 6
7 6
5 4
7 6 9
9 4 7
4 9
3
5 3 5
3
2 1 2 1 2
2 1
8
6 7
4
3
1
9
8
5 6
4
3
2 1
Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 97
8 4
9 11
7 6 2 5
3
10
8 4
9
11
7 6 2 5
3
10
8 4
9 10
7 6 2 5
3
11
8 4
9 11
7 6 2 10
3 5
8 10
5 15
7 6
11 2
3 4
9
8 10
5 11
7 6
15 2
3 4
9
8 10
5
7 6
11 2
3 4
9 15
13
10
5
7
13 2
3 4
9 15
11
10
5
7
11 2
3 4
9 13
15
10
5
7
11 2
3 4
9 13
15
8
8 6
6
6 8
9 7
5
8
6
4
9
7 8
5
7 9
6 5
8
10
10
4
9
7 10
5 8 6
6 4
3
2 1
3
2 1
3 10 4
2 1 3
2 1
10
9 6
10
9 11
7 8 11 7 8 6 9
5 4
3
5 4
3
7 8
5
2 1 2 1
11
10
6
12
4
3
2 1
11 11
10 12
12 10
9 12 10
7 8 6 9 6
9
7 8
6
8
7 5
5 4
5 4
3
2 1 3
2 1
3 4
2 1
11
procedure Wstaw_korzen(var Wezel,Nowy : POsobaD);
begin
if Wezel = nil then Wezel := Nowy else
if Wezel^.Dane.Nazwisko > Nowy^.Dane.Nazwisko then begin
Wstaw_korzen(Wezel^.Lewy, Nowy);
Obrot_P(Wezel);
end else
if Wezel^.Dane.Nazwisko < Nowy^.Dane.Nazwisko then begin
Wstaw_korzen(Wezel^.Prawy, Nowy);
Obrot_L(Wezel);
end else begin
Dispose(Nowy); Nowy:= nil;
end;
end;
9.1.4. Wyważanie drzewa
10
5
7
11
2
3 4
9 13
15
8
10
5
8
11
2
3 4
9 13
15
7 6
10
5
9 11
2
3 4
8 13
15
7 6
10
8
5
11 2
3 4
9 13
15
7 6 6
10
9 2
11 4
5 8
3
13 15
7 6
8
9 2
4 10
5 3
13 15
7 6
11
8
2 10 4 13
5 3
15
7 6
11
2 4
5
3 7
6
4 5
7 2 6
3
4
2
3
2 3
4 4
3 2
3 5
7
2 4 6
10 13
15
11
9
9
11 13
15
9 10
10 11
13
9 15
10 11
15
9 13 4
5
7
2 4 6
8
12 10
9
7 8
5 4
12 11
6
10 11
9 6
7 8
5 4
9 10
12
11
12
10 11
7 8
9 6
7 1
5 8 4
5 1
6
3 2
3 4
2 1
3
2 3
2 1
12
10 11
6 1
9 4
12
1 11
9 10
4
7 8 4 6
7 8
5 3
2
5 3
2
1
9 12
7 8 10 11
5 3 4 6
2
9
5 5
7 9 3
7 9 2
9
5
7 9
7
5 8
9 3
7 2
5 9
7 8
5 3
2
12
10 11
4 6
12
6
10
6
10 12
4 11
11
4
1
8
9
7 9
3
6
2 4
10 11
12
10 11
13 15
9
6
10
12 4
11
procedure Wywaz_drzewo(var Wezel : POsobaD);
begin
if (Wezel = nil) or (Wezel^.Licznik = 1) then exit;
Podzial(Wezel,Wezel^.Licznik div 2);
Wywaz_drzewo(Wezel^.Lewy);
Wywaz_drzewo(Wezel^.Prawy);
end;
procedure Podzial(var Wezel : POsobaD; Liczba : integer);
var il : integer;
begin
if Wezel^.Lewy = nil then il :=0 else il:= Wezel^.Lewy^.Licznik;
if il > Liczba then begin
Podzial(Wezel^.Lewy, Liczba);
Obrot_P(Wezel);
Oblicz_wezly(Wezel);
end else
if (il < Liczba) then begin
Podzial(Wezel^.Prawy, Liczba - il - 1);
Obrot_L(Wezel);
Oblicz_wezly(Wezel);
end;
end;
function Oblicz_wezly(Wezel: POsobaD) : integer;
begin
if Wezel <> nil then begin
if (Wezel^.Prawy = nil) and (Wezel^.Lewy = nil) then Wezel^.Licznik:=1
else
Wezel^.Licznik:= Oblicz_wezly(Wezel^.Lewy)+
Oblicz_wezly(Wezel^.Prawy)+1;
Oblicz_wezly:= Wezel^.Licznik;
end
else Oblicz_wezly := 0;
end;
procedure Obrot_LL(var Wezel : POsobaD);
var P : POsobaD; x1, x2, x3 : longint;
begin
x1:= 0; x2:= 0; x3:= 0;
if Wezel^.Lewy <> nil then x1:= Wezel^.Lewy^.Licznik;
if Wezel^.Prawy^.Lewy <> nil then x2:= Wezel^.Prawy^.Lewy^.Licznik;
if Wezel^.Prawy^.Prawy <> nil then x3:= Wezel^.Prawy^.Prawy^.Licznik;
P := Wezel^.Prawy; Wezel^.Prawy := P^.Lewy; P^.Lewy := Wezel;
Wezel := P;
Wezel^.Lewy^.Licznik:= x1+x2;
Wezel^.Licznik:= Wezel^.Lewy^.Licznik+x3;
end;
procedure Obrot_PL(var Wezel : POsobaD);
var P : POsobaD; x1, x2, x3 : longint;
begin
x1:= 0; x2:= 0; x3:= 0;
if Wezel^.Prawy <> nil then x1:= Wezel^.Prawy^.Licznik;
if Wezel^.Lewy^.Prawy <> nil then x2:= Wezel^.Lewy^.Prawy^.Licznik;
if Wezel^.Lewy^.Lewy <> nil then x3:= Wezel^.Lewy^.Lewy^.Licznik;
P := Wezel^.Lewy; Wezel^.Lewy := P^.Prawy; P^.Prawy := Wezel;
Wezel := P;
Wezel^.Prawy^.Licznik:= x1+x2;
Wezel^.Licznik:= Wezel^.Prawy^.Licznik+x3;
end;
procedure Podzial(var Wezel : POsobaD; Liczba : integer);
var il : integer;
begin
if Wezel^.Lewy = nil then il :=0 else il:= Wezel^.Lewy^.Licznik;
if il > Liczba then begin
Podzial(Wezel^.Lewy, Liczba);
Obrot_PL(Wezel);
end else
if (il < Liczba) then begin
Podzial(Wezel^.Prawy, Liczba-il-1);
Obrot_LL(Wezel);
end;
end;
9.1.5. Przejście przez drzewo
10 11
4 15 5
7 8
10 11
4 15 5
7 8
10 11
4 15 5
7 8
10 11 4 15
5 7
8
10 11 4 15
5 7
8
10 11 4 15
5 7
8 10
11 4 15
5 7
8
10 11 4 15
5 7
8
10 11
4 15 5
7 8
10 11
4 15 5
7 8
10 11 4 15
5 7
8
10 11 4 15
5 7
8
10 11
4 15 5
7 8
10 11 4 15
5 7
8
10 11
4 15 5
7 8
10 11 4 15
5 7
8
10 11 4 15
5 7
8
10 11
4 15 5
7 8
10 11 4 15
5 7
8
10 11 4 15
5 7
8 10
11 4 15
5 7
1) 2) 3) 8
1) Przejście przedrostkowe przez drzewo
procedure Dla_kazdego(Wezel : POsobaD; funkcja: zrob);
begin
if Wezel <> nil then begin
funkcja(Wezel^.Dane);
Dla_kazdego(Wezel^.Lewy,funkcja);
Dla_kazdego(Wezel^.Prawy, funkcja) end;
end;
2) Przejście uporządkowane przez drzewo
procedure Dla_kazdego(Wezel : POsobaD; funkcja: zrob);
begin
if Wezel <> nil then begin
Dla_kazdego(Wezel^.Lewy,funkcja);
funkcja(Wezel^.Dane);
Dla_kazdego(Wezel^.Prawy, funkcja) end;
end;
3) Przejście przyrostkowe przez drzewo
procedure Dla_kazdego(Wezel : POsobaD; funkcja: zrob);
begin
if Wezel <> nil then begin
Dla_kazdego(Wezel^.Lewy,funkcja);
Dla_kazdego(Wezel^.Prawy, funkcja) funkcja(Wezel^.Dane);
end;
end;
program Drzewo_wywazone;
uses Crt, Rozne, Modul, MDrzewoW;
const Tab_menu : Lancuchy = ('1 : Wstawianie do korzenia drzewa ', '2 : Wstawianie jako lisc drzewa ', '3 : Usuwanie z drzewa',
'4 : Wyswietlenie elementu drzewa','5 : Wywazanie drzewa',
'6 : Wydruk drzewa', '7 : Usun drzewo', 'K/k - Koniec programu','','','');
type wstawianie= (do_korzenia, jako_lisc);
procedure Wstaw_do_drzewa(var Poczatek :POsobaD;Jak: wstawianie );
var Dana : Osoba; Nowy : POsobaD;
begin
Podaj_dane(Dana);
Nowy_Element_D(Nowy, Dana);
if Nowy = nil then exit;
if Jak = do_korzenia then Wstaw_Korzen(Poczatek, Nowy) else Wstaw(Poczatek, Nowy);
if Nowy <> nil then
Dla_jednego(Poczatek, Nowy^.Dane.Nazwisko, Wydruk_danych);
end;
function Klucz:lan;
var Pom: lan;
begin
repeat Write('Podaj nazwisko: '); Readln(Pom); until Pom <> '';
Klucz:= Pom;
end;
var Wybor, Z : char; Poczatek_D, Gdzie : POsobaD;
begin
ClrScr; Randomize; Inicjalizacja(Poczatek_D);
repeat
Menu(Tab_menu, 8, Wybor);
case Wybor of
'1' : Wstaw_do_drzewa(Poczatek_D, do_korzenia);
'2' : Wstaw_do_drzewa(Poczatek_D, jako_lisc);
'3' : Usun_element_drzewa(Poczatek_D, Klucz);
'4' : Dla_jednego(Poczatek_D, Klucz, Wydruk_danych);
'5' : begin Oblicz_wezly(Poczatek_D); Wywaz_Drzewo(Poczatek_D);end;
'6' : Dla_kazdego(Poczatek_D, Wydruk_danych);
'7' : begin Usun_drzewo(Poczatek_D); Poczatek_D := nil; end;
end;
Pauza(Z, False);
until Wybor = 'K'; end.
9.2. Złożoność obliczeniowa tablic, drzew i list
Typ struktury danych Przypadek najgorszy-N / Przypadek średni-Ś
i algorytmu wstawianie wyszukiwanie wybór
N Ś N Ś N
traf. chyb.
tablica uporządkowana
n n/2 n n/2 n/2 1tablica nieuporządkowana
1 1 n n/2 n n lg nlista uporządkowana
n n/2 n n/2 n/2 nlista nieuporządkowana
1 1 n n/2 n n lg nwyszukiwanie binarne (tablica)
n n/2 lg n lg n lg n 1