• Nie Znaleziono Wyników

9.3. Obroty w węzłach

N/A
N/A
Protected

Academic year: 2021

Share "9.3. Obroty w węzłach"

Copied!
1
0
0

Pełen tekst

(1)

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 przez drzewo

9.2. Złożoność obliczeniowa drzew i list

Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 91

(2)

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ł

zewnętrzny

węzeł

wewnę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

(3)

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

Definicja 7: Drzewo swobodne czyli drzewo bez korzenia to graf, który

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

(4)

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

(5)

9.1.2. Obroty w węzłach

· obrót w lewo

A

E

C

E

C A

void Obrot_L(PELEMENTD& Wezel) { PELEMENTD P;

P = Wezel->Prawy;

Wezel->Prawy = P->Lewy;

P->Lewy = Wezel;

Wezel = P;

}

· obrót w prawo

E A

C

A

C

E

void Obrot_P(PELEMENTD& Wezel) { PELEMENTD P;

P = Wezel->Lewy;

Wezel->Lewy = P->Prawy;

P->Prawy = Wezel;

Wezel = P;

}

Autor: Zofia Kruczkiewicz, p.325 C3 Algorytmy i struktury danych, Wykład 95

(6)

·

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

(7)

· 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 8 5

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)

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

(9)

void Wstaw_korzen(PELEMENTD& Wezel,PELEMENTD& Pozycja) {

if (Wezel == NULL) Wezel = Pozycja;

else

if (strcmp(Pozycja->Dane.Nazwisko,Wezel->Dane.Nazwisko)<0) {

Wstaw_korzen(Wezel->Lewy, Pozycja);

Obrot_P(Wezel);

} else

if (strcmp(Pozycja->Dane.Nazwisko,Wezel->Dane.Nazwisko)>0) {

Wstaw_korzen(Wezel->Prawy, Pozycja);

Obrot_L(Wezel);

} else {

delete Pozycja;

Pozycja=NULL;

}

}

(10)

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

9

12 10 8

2 5

1 4

12 1

1

10 1

8 1

2 5

1 4

8 10

12

1

12

10 1

2 5

8 1

2 5

1 3 1

1 4

1

2 1

2 1

1 3

2

1

3 1 1

12 10 1

1 8

6 1

12

10 1

6 3

4

2 3 1 1

2 3

1 2

1

1 2

1

12

6 5

2 3 3 1

1 2 1 1

1

6 3 3

1 1 2

1 1 1

3

2 1 3

2

1 6

3 2

2 1

1 6

2 3

1 2

1

(11)

10 13

15 9 11

11 13

15

9 10

10 11

13 9 15

10 11

15 9 13

4 5

7 2 4 6

5 8

3 1

1 1

5 3

2

5

2 2

1 1

1

1

12

6

3

1 1

2

5

1 1

2 2

1

10 11

13 15 9

5

2

1 1

2

(12)

int Wywaz_drzewo( PELEMENTD& Wezel)

{ if (Wezel == NULL || Wezel->Licznik == 1) return 0;

Podzial(Wezel,Wezel->Licznik / 2);

Wywaz_drzewo(Wezel->Lewy);

Wywaz_drzewo(Wezel->Prawy);

return 1;

}

void Podzial( PELEMENTD& Wezel, int Liczba) { int il;

if ( Wezel->Lewy == NULL) il =0;

else il= Wezel->Lewy->Licznik;

if (il > Liczba) {

Podzial(Wezel->Lewy, Liczba);

Obrot_P(Wezel );

Oblicz_wezly(Wezel);

} else

if (il < Liczba)

{ Podzial(Wezel->Prawy, Liczba-il-1);

Obrot_L(Wezel);

Oblicz_wezly(Wezel);

} }

int Oblicz_wezly(PELEMENTD Wezel) {

if (Wezel != NULL) {

if (Wezel->Prawy == NULL && Wezel->Lewy == NULL) Wezel->Licznik=1;

else

Wezel->Licznik=Oblicz_wezly(Wezel->Lewy)+

Oblicz_wezly(Wezel->Prawy)+1;

return Wezel->Licznik;

}

else return 0;

}

(13)

void Obrot_LL(PELEMENTD& Wezel) { PELEMENTD P;

long x1,x2,x3;

x1=x2=x3=0L;

if (Wezel->Lewy != NULL) x1= Wezel->Lewy->Licznik;

if (Wezel->Prawy->Lewy !=NULL) x2= Wezel->Prawy->Lewy->Licznik;

if (Wezel->Prawy->Prawy != NULL) 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;

}

void Obrot_PP(PELEMENTD& Wezel) { PELEMENTD P;

long x1,x2,x3;

x1=x2=x3=0L;

if (Wezel->Prawy != NULL) x1= Wezel->Prawy->Licznik;

if (Wezel->Lewy->Prawy != NULL) x2= Wezel->Lewy->Prawy->Licznik;

if (Wezel->Lewy->Lewy != NULL) 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;

}

void Podzial( PELEMENTD& Wezel, int Liczba) { int il;

if ( Wezel->Lewy == NULL) il =0;

else il= Wezel->Lewy->Licznik;

if (il > Liczba)

{ Podzial(Wezel->Lewy, Liczba);

Obrot_PP(Wezel); //Obrot_P(Wezel);

//Oblicz_wezly(Wezel);

} else

if (il < Liczba)

{ Podzial(Wezel->Prawy, Liczba-il-1);

Obrot_LL(Wezel); //Obrot_L(Wezel);

//Oblicz_wezly(Wezel);

} }

9.1.5. Przejście przez drzewo

(14)

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

(15)

1) Przejście przedrostkowe przez drzewo

void Dla_kazdego (PELEMENTD Wezel, zrob funkcja) {

if (Wezel!= NULL)

{ funkcja(Wezel->Dane);

Dla_kazdego(Wezel->Lewy, funkcja);

Dla_kazdego(Wezel->Prawy, funkcja); }}

2) Przejście uporządkowane przez drzewo

void Dla_kazdego (PELEMENTD Wezel, zrob funkcja) {

if (Wezel!= NULL)

{Dla_kazdego(Wezel->Lewy, funkcja);

funkcja(Wezel->Dane);

Dla_kazdego(Wezel->Prawy, funkcja);}}

3)

Przejście przyrostkowe przez drzewo

void Dla_kazdego (PELEMENTD Wezel, zrob funkcja) {

if (Wezel!= NULL)

{Dla_kazdego(Wezel->Lewy, funkcja);

Dla_kazdego(Wezel->Prawy, funkcja);

funkcja(Wezel->Dane);} }

Przykład - usunięcie drzewa

void Usun_pamiec(PELEMENTD Wezel) {

if (Wezel != NULL)

{ Usun_pamiec((Wezel)->Lewy);

Usun_pamiec((Wezel)->Prawy);

delete Wezel; }}

void Usun_drzewo(PELEMENTD &Wezel) { Usun_pamiec(Wezel);

Wezel=NULL;

}

(16)

#include <conio.h>

#include <string.h>

#include <stdio.h>

#include "mdrzewow.h"

#include "dodatki.h"

#include "we_wy.h"

char *Polecenia[]={ "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",

"Esc - Koniec programu"};

void Podaj_klucz(char *Klucz);

void Wstaw_(PELEMENTD &Korzen, int jak);

void Usun_(PELEMENTD &Korzen);

void Wywaz_drzewo_(PELEMENTD &Korzen);

void Dla_jednego_(PELEMENTD &Korzen);

void main(void) { char Co;

PELEMENTD Korzen;

Inicjalizacja(Korzen);

do

{ Co = Menu(8,Polecenia);

switch(Co) {

case '1' : Wstaw_(Korzen, 0); break;

case '2' : Wstaw_(Korzen, 1); break;

case '3' : Usun_(Korzen); break;

case '4' : Dla_jednego_(Korzen); break;

case '5' : Wywaz_drzewo_(Korzen); break;

case '6' : Dla_kazdego(Korzen, Pokaz_dane); break;

case '7' : Usun_drzewo(Korzen);break;

case 27 : Komunikat("\nKoniec programu");break ; default : Komunikat("\nZla opcja");

}

} while (Co!=27);

}

(17)

void Podaj_klucz(char* Klucz)

{ char bufor[DL+2]; bufor[0]=DL;

printf("\nPodaj klucz: ");

strcpy(Klucz,cgets(bufor)); }

void Wstaw_(PELEMENTD &Korzen, int jak) { OSOBA Dana; PELEMENTD Nowy;

Dana= Dane();

if ((Nowy= Nowy_element(Dana)) == NULL) Komunikat("\nBrak pamieci");

else

{ if (jak==0) Wstaw_korzen(Korzen, Nowy);

else Wstaw(Korzen, Nowy);

if (Nowy != NULL)

Dla_jednego(Korzen, Dana.Nazwisko, Pokaz_dane);

} }

void Usun_(PELEMENTD &Korzen) { char Klucz[DL];

if (Korzen==NULL)

{ Komunikat("\nDrzewo puste"); return; } Podaj_klucz(Klucz);

if (Usun(Korzen,Klucz)) Komunikat("\nNie znaleziono elementu");

else Komunikat("\nUsunieto element");

}

void Dla_jednego_(PELEMENTD &Korzen) { char Klucz[DL];

if (Korzen==NULL)

{ Komunikat("\nDrzewo puste"); return;}

Podaj_klucz(Klucz);

Dla_jednego(Korzen,Klucz,Pokaz_dane);

}

void Wywaz_drzewo_(PELEMENTD &Korzen) { if (Korzen==NULL)

{ Komunikat("\nDrzewo puste"); return; } Oblicz_wezly(Korzen);

if (Wywaz_drzewo(Korzen)) Komunikat("\nWywazono drzewo");

else Komunikat("\nNie wywazono drzewo-1 element");

}

(18)

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 1

tablica nieuporządkowana

1 1 n n/2 n n lg n

lista uporządkowana

n n/2 n n/2 n/2 n

lista nieuporządkowana

1 1 n n/2 n n lg n

wyszukiwanie binarne (tablica)

n n/2 lg n lg n lg n 1

binarne drzewo poszukiwań

n lg n n lg n lg n n

drzewo czerwono-czarne

lg n lg n lg n lg n lg n lg n

Cytaty

Powiązane dokumenty

Nieskończone drzewo binarne jest to drzewo z korzeniem, w którym każdy wierzchołek ma 2 potomków i wszystkie wierzchołki poza korzeniem mają jed- nego rodzica.. Czy te zmienne

Nieskończone drzewo binarne jest to drzewo z korzeniem, w którym każdy wierzchołek ma 2 potomków i wszystkie wierzchołki poza korzeniem mają jed- nego rodzica.. Czy te zmienne

Zdanie złożone podrzędnie (wykresy) - Zdania podrzędne przydawkowe.. Zdania

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

‡ Jednym z najprostszych sposobów reprezentowania drzewa jest wykorzystanie dla każdego węzła struktury składającej się z pola lub pól reprezentujących etykietę oraz

Dodatkowo: drzewo jest ukorzenione, co oznacza, że każdy węzeł (poza korzeniem) ma dokładnie jednego rodzica... inicjalizacja odbywa się bez

...lipy, których nikt nie kształtuje, nie obcina im gałęzi które rosną samotnie, zwłaszcza na szczytach pagórków, wyglądają wspaniale. Są zgrabne i kształtne, ugałęzione

- szukanie zer wielomianu n-tego stopnia w zadanym przedziale - liczenie wyznacznika metodą rekurencyjną i/lub