background image

Zajęcia nr 8/9

 

Struktury danych – dane dynamiczne

Algorytmy i struktury danych

Prowadzący:  

dr hab.inż. ANDRZEJ WALCZAK, 

prof.WAT

background image

2

Algorytmy i struktury danych, wykład 3

Wykład : Realizacje dynamicznych 

struktur danych

Dynamiczne realizacje struktur listowych (definiowanie 
elementu listy, dołączanie i usuwanie elementu listy, 
wyszukiwanie elementu w liście, przestawianie 
elementów w liście);

Dynamiczne realizacje struktur drzewiastych 
(definiowanie elementu drzewa, dołączanie i usuwanie 
elementu drzewa, wyszukiwanie elementu w drzewie);

Dynamiczne realizacje tablic;

background image

3

Algorytmy i struktury danych, wykład 3

Statyczna a dynamiczna struktura 

danych

Statyczna struktura danych: 

Posiada z góry ustalony rozmiar (bez możliwości jego 
zmiany);

Jej deklaracja poprzedza uruchomienie głównej 
procedury programu;

Liczba zmiennych o typie statycznych musi być z góry 
znana;

Pamięć jest przydzielana na wstępie a oddawana po 
zakończeniu programu;

background image

4

Algorytmy i struktury danych, wykład 3

Statyczna a dynamiczna struktura 

danych

Dynamiczną strukturę danych odróżnia sposób przydziału 

pamięci operacyjnej:

 ilość wymaganej pamięci przez struktury danych nie 

musi być znana przed uruchomieniem programu;

 przydział pamięci następuje dynamicznie w czasie 

realizacji odpowiedniej części programu; 

 po wykonaniu zadań struktury danych powinny być 

usunięte a przydzielona pamięć dynamicznie 

zwolniona;

 zaleta tego podejścia:

możliwość dynamicznego tworzenia struktur danych o 

różnych „kształtach”;

„brak” ograniczeń na wielkość struktury; 

wada: złożone operacje dodawania i usuwania 

elementów struktury;

background image

5

Algorytmy i struktury danych, wykład 3

Arytmetyka wskaźników – 

przypomnienie

Utworzenie struktury dynamicznej możliwe jest 
poprzez zastosowanie wskaźników, adresów, 
referencji;

Czy potrafimy odróżnić pojęcie i właściwości:

zmiennej,

wskaźnika,

adresu,

referencji? 

background image

6

Algorytmy i struktury danych, wykład 3

Arytmetyka wskaźników – 

przypomnienie

Deklaracja zmiennej ‘var’ o typie ‘type’:

type var;

Przykład: 

int x = 8;

Deklaracja zmiennej wskaźnikowej ‘name’ do typu ‘type’ :

type *name; 

Przykład: 

int *ip;

/*wskaźnik na typ integer*/

float *fp; 

/*wskaźnik na typ float */

Przypisanie adresu zmiennej x do wskaźnika ip;

ip = &x;  

& oznacza ‘adres’ i zwraca adres stojącej przy nim 
operandy;

ip teraz wskazuje na x; 

i
p
f
p

ip

8

X

background image

7

Algorytmy i struktury danych, wykład 3

Arytmetyka wskaźników – 

przypomnienie

Pobranie wartości wskazywanej przez wskaźnik :

int y; 

y = *ip; 

y teraz posiada wartość równą x; 

8

x

ip

Reprezentacja logiczna

600000

ip

8

x

500000

600000

Fizyczna reprezentacja w pamięci

background image

8

Algorytmy i struktury danych, wykład 3

Arytmetyka wskaźników – 

przypomnienie

Przeanalizuj i wyjaśnij poniższy fragment kodu:

  int x=1, y=2, z[10];
  int *ip, *iq;

ip = &x;

  

y = *ip;

  

*ip = 0;

  

*ip += 1;
y = *ip+2;
ip = &z[0];
iq = ip;

  

/* ip wskazuje na x        

*/

/* y = 1                 

*/

/* x przypisano 0         

*/

/* x zwiększone o 1  */
/* y = 3                 

*/

/* ip wskazuje na z[0] 

*/

/* iq wskazuje na z[0] 

*/

background image

9

Algorytmy i struktury danych, wykład 3

Arytmetyka wskaźników – 

przypomnienie

Przykład operacji dla typu prostego:

int *px; 

px += 2;

px = (adres px) + 2 * rozmiar obiektu wskazywanego 

przez px;

dla px równe jest 3000 i rozmiaru 4 dla int:

3000 + 2 * 4 = 3008;

Przykład dla tablicy:

int a[4];

int *pa;

pa = a; /* lub pa=&a[0]; */

pa ++; 

/*pa wskazuje na a[1] */

pa =+ 2; 

/*pa wskazuje na a[3] */

pa --; /*pa wskazuje na a[2] */ 

a[0] a[1] a[2] a[3]

3000 3004 3008 3012

pa

background image

10

Algorytmy i struktury danych, wykład 3

Dynamiczne zarządzanie pamięcią 

operacyjną

Dynamiczny przydział pamięci (alokacja):

malloc() /* z biblioteki stdlib.h */

Przykład:

void *  malloc(size_t size);

‘void’ pozwala na wskazanie danych dowolnego typu;

argumentem funkcji jest rozmiar przydzielanej pamięci;

pamięć przydzielana jest z obszaru zwanego kopcem;

sizeof() – operator do określenia wielkości pamięci:

sizeof(int) – zwróci rozmiar pamięci potrzebny dla 
przechowania danych typu integer;

sizeof(struct node) – zwróci rozmiar pamięci potrzebny dla 
przechowania danych typu zadeklarowanej struktury 
‘node’;

background image

11

Algorytmy i struktury danych, wykład 3

Dynamiczne zarządzanie pamięcią – 

polecenia

rekursywn

deklaracja 

struktury

Przykład użycia malloc() i sizeof():

(1) 

int x=1, y;

   

y = sizeof x;

       lub y = sizeof (int);

(2) 

struct node {

char data;
struct node *nextPtr };

struct node *newPtr;
newPtr = malloc(sizeof(struct node));

newPt
r

Dane

nextPtr

?

background image

12

Algorytmy i struktury danych, wykład 3

Dynamiczne zarządzanie pamięcią – 

polecenia

Dynamiczne zwolnienie pamięci (na kopiec):

free() 

/* z biblioteki stdlib.h */

 Przykład:

struct node {

char data;
struct node *nextPtr };

struct node *newPtr;
newPtr = malloc(sizeof(struct node));

/* operacje na danych*/

free (newPtr);

background image

13

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych

Definiowanie elementu listy; 

Dołączanie i usuwanie elementu listy; 

Wyszukiwanie elementu w liście; 

Przestawianie elementów w liście;

background image

14

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych

Model grafowy listy jednokierunkowej (dwukierunkowej)

e

d

1

d

2

d

3

d

n

e

d

1

d

2

d

3

d

n

background image

15

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Element listy zawiera:

Dane elementarne,

Odwzorowanie relacji następstwa – informacja o 
dowiązaniu do innych elementów;

dane

dowiązanie

start

NULL

ogon

głowa

background image

16

Algorytmy i struktury danych, wykład 3

dane 

elementar

ne

dowiązani

e do 

kolejnego 

elementu 

Dynamiczne realizacje struktur 

listowych 

Deklaracja elementu listy:

struct Node {

   char data;
   struct Node *next;
  };

typedef struct Node *NodePtr;

 

/* pomocniczy typ wskaźnikowy do struktury ‘Node’ 

*/

/* zmienna ‘start’ tego typu wskazywać będzie 

głowę listy */ 

background image

17

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm dołączania elementu do listy 
jednokierunkowej (1):

Cel:

Dodanie nowego elementu do listy; 

Dane wejściowe:

Dowiązanie głowy  listy ‘startPtr’;

Nowa dana elementarna;

background image

18

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm dołączania elementu do listy 
jednokierunkowej (2):

Utwórz element i ustal dane elementarne;

Znajdź miejsce wstawienia elementu w 
liście;

Wstaw element do listy:

Wstaw element jako pierwszy w liście;

(lub) Wstaw element we wskazane miejsce w 
liście; 

background image

19

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm dołączania elementu do listy 
jednokierunkowej (3):

Utwórz element i ustal dane elementarne
int insert (NodePtr *startPtr, char nazwa)
{

Node *newPtr, *currPtr, *prevPtr;
int retcode=1;
/* Utwórz element Node */

  

newPtr = (Node *)malloc(sizeof(Node));

background image

20

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych

Schemat algorytmu cz.3

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

background image

21

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm dołączania elementu do listy jednokierunkowej (4):

Utwórz element i ustal dane elementarne
int insert (NodePtr *startPtr, char nazwa)

{
Node *newPtr, *currPtr, *prevPtr;

int retcode = 1;
/* Utwórz element Node */

   newPtr = (Node *)malloc(sizeof(Node));

if (newPtr == NULL)  /* weryfikacja przydzielonej pamięci*/ 

    retcode = 0;
else 

{   /* Ustal dane elementarne w Node */

    newPtr -> data = nazwa;
    newPtr -> next = NULL;

    /* Inicjalizacja wskaźników pomocniczych */

    currPtr = *startPtr;   /* ustaw wskaźnik na głowę listy */ 

    prevPtr = NULL;

background image

22

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych

Schemat działania algorytmu cz.4

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

NULL

C

NUL
L

background image

23

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm dołączania elementu do listy jednokierunkowej 
(5):

Utwórz element i ustal dane elementarne

Znajdź miejsce wstawienia elementu w liście

Dopóki currPtr jest różny od NULL oraz dane elementu 
wstawianego są ‘większe’ od currPtr->data:

• Ustaw prevPtr na currPtr; 
• Przesuń currPtr na następny element listy;


/* Znajdź miejsce wstawienia */
while ((currPtr != NULL) && (nazwa > currPtr->data))
{
prevPtr = currPtr;
currPtr = currPtr -> next;
}

background image

24

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych

Schemat algorytmu cz.5

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

C

NUL
L

background image

25

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm dołączania elementu do listy jednokierunkowej 
(6):

Utwórz element i ustal dane elementarne

Znajdź miejsce wstawienia elementu w liście

Zainicjalizuj currPtr na start listy a prevPtr na NULL;

Dopóki currPtr jest różny od NULL i wartość wstawiana jest 
większa od currPtr->data:

• Ustaw prevPtr na currPtr; 
• Przesuń currPtr na następny element listy;

Wstaw element do listy:

Wstaw element jako pierwszy w liście:

• Ustaw pole next elementu wstawianego na pierwszy element listy;
• Ustaw wskaźnik do listy na element wstawiony;

(lub) Wstaw element we wskazane miejsce w liście:

• Ustaw pole next elementu prevPtr na element wstawiany;
• Ustaw pole next elementu wstawianego na element currPtr;

background image

26

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm dołączania elementu do listy 
jednokierunkowej (7):

/* Wstaw element */
if (prevPtr == NULL)
/* Wstaw element jako pierwszy w liście */
{

newPtr -> next = *startPtr;
*startPtr = newPtr;

}

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

NULL

C

NUL
L

startPtr

newPtr

prevPtr

D

currPtr

C

A

B

NULL

NUL
L

background image

27

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm dołączania elementu do listy 
jednokierunkowej (8):

/* Wstaw element */

/* Wstaw element w miejsce między prevPtr a currPtr 
*/
else 

    {

newPtr->next = currPtr;
prevPtr->next = newPtr;
}
retcode = 1;
}
return retcode;

}

background image

28

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych

Schemat algorytmu cz.8

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

NULL

C

NUL
L

startPtr

newPtr

currPtr

D

prevPtr

A

B

C

NUL
L

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

C

NUL
L

background image

29

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Uwagi do dołączania elementu do listy 
dwukierunkowej
:

każdy element posiada dodatkowe pole (dowiązanie) 
prev, które dla pierwszego elementu listy jest równe 
NULL;

lista może być przeglądana w obydwu kierunkach;

często pamięta się dowiązania do pierwszego i 
ostatniego elementu;

należy zawsze uaktualniać dowiązania w obydwu 
kierunkach (wartości czterech pól);

Czy potrafisz dostosować zaprezentowany 

algorytm do list dwukierunkowych?

 

background image

30

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Uwagi do dołączania elementu do listy cyklicznej:

brak dowiązań wskazujących na NULL;

w liście jednoelementowej dowiązania wskazują na 
ten sam element;

aby uniknąć pętli nieskończonej podczas 
przeglądania listy, należy zastosować ‘strażnika’ – 
dowiązanie do pierwszego elementu (umownego);

Czy potrafisz dostosować zaprezentowany 

algorytm do list cyklicznych?

 

background image

31

Algorytmy i struktury danych, wykład 3

Przykład dołączania 

elementu do listy

#include "lista.h"

void LISTA::dorzuc1(int x) // dolaczamy rekord na 

koniec listy

{                             // (ver.1 - bez "sortowania")

ELEMENT *q=new ELEMENT;

 q->wartosc=x;

 q->nastepny=NULL;

if (inf.glowa==NULL)       // lista pusta

   inf.glowa=inf.ogon=q;

 else                 // cos jest w liscie

 {

 (inf.ogon)->nastepny=q;

 inf.ogon=q;

 }}

background image

32

Algorytmy i struktury danych, wykład 3

Przykład dołączania 

elementu do listy

Jak działa zaprezentowany kod?

W przypadku listy pustej obydwa pola początkowe 
struktury lista są inicjowane wskaźnikiem na nowo 
powstały element

Jeśli lista nie jest pusta nowy element zostaje podpięty do 
końca listy stając się jej ogonem a element pierwszy 
zapewnia relację wejścia w listę

Oczywiście można pierwszy element ustawiać jako 
początek listy czyli głowa. Założeniem było ze przydział 
pamięci na wskaźnik nastąpi i będzie różny od zera

Zaprezentujemy realizacje połączenia dwóch zadanych 
list utworzonych wg pliku lista.h o kodzie napisanym w 
C++ z elementami programowania obiektowego. Na tych 
listach wykonanych będzie kilka operacji szukania, 
dopisywania, usuwania.

background image

33

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm szukania elementu w liście 
jednokierunkowej (1):

Cel:

Wyszukanie elementu w liście; 

Dane wejściowe:

Dowiązanie głowy  listy ‘startPtr’;

Kryterium poszukiwania, np. wartość danej 
elementarnej;

Uwagi:

W skrajnym przypadku należy przejrzeć wszystkie 
elementy (złożoność O(n));

background image

34

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm szukania elementu w liście 
jednokierunkowej (2):

Rozpocznij od pierwszego elementu listy;

Dopóki aktualny element listy jest różny od NULL oraz 
dane szukane są różne od danych aktualnego 
elementu, to przemieść się do następnego elementu 
listy;

Daj dowiązanie do aktualnego elementu;

background image

35

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm szukania elementu w liście 
jednokierunkowej (3):

Node *Find (NodePtr *startPtr, char nazwa)
{

NodePtr currPtr = *startPtr;      /* pierwszy element 
listy */
while ((currPtr != NULL) && (currPtr -> data != 
nazwa
))

 currPtr = currPtr -> next;

return currPtr;

background image

36

Algorytmy i struktury danych, wykład 3

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

NULL

C

NUL
L

startPtr

D

A

B

C

NUL
L

Dynamiczne realizacje struktur 

listowych 

Algorytm szukania elementu w liście 
jednokierunkowej (4):

Przykład:
Node *ele = Find (startPtr, ‘C’);

currPtr

Nazwa szukana: C

currPtr: startPtr

currPtr -> data: A

background image

37

Algorytmy i struktury danych, wykład 3

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

NULL

C

NUL
L

startPtr

D

A

B

C

NUL
L

Dynamiczne realizacje struktur 

listowych 

Algorytm szukania elementu w liście 
jednokierunkowej (5):

Przykład:
Node *ele = Find (startPtr, ‘C’);

currPtr

Nazwa szukana: C

currPtr: currPtr -> next

currPtr -> data: B

background image

38

Algorytmy i struktury danych, wykład 3

startPtr

currPtr

prevPtr

newPtr

A

B

D

NULL

NULL

C

NUL
L

startPtr

D

A

B

C

NUL
L

Dynamiczne realizacje struktur 

listowych 

Algorytm szukania elementu w liście 
jednokierunkowej (6):

Przykład:
Node *ele = Find (startPtr, ‘C’);

currPtr

Nazwa szukana: C

currPtr: currPtr -> next

currPtr -> data: C

background image

39

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm usuwania elementu z listy 
jednokierunkowej (1):

Cel:

Usunięcie elementu z listy; 

Dane wejściowe:

Dowiązanie głowy  listy ‘startPtr’;

Opis elementu, np. wartość danej elementarnej;

background image

40

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm usuwania elementu z listy 
jednokierunkowej (2):

Jeżeli dane są zgodne z danymi pierwszego elementu 
listy

Usuń pierwszy element listy;

W p.p. znajdź element do usunięcia w liście;

Jeżeli nie znaleziono elementu, generuj komunikat;

W p.p. usuń znaleziony element;

background image

41

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm usuwania elementu z listy jednokierunkowej (3):

Jeżeli dane są zgodne z danymi pierwszego elementu listy

Usuń pierwszy element listy;

int delete (NodePtr *startPtr, char nazwa)

{

NodePtr prevPtr, currPtr, tempPtr;

int retcode;
   if (*startPtr == NULL)   

          /* Lista pusta */

  retcode = 0;

      else   

   {

 

  if (nazwa == (*startPtr)->data)    /* Usuń pierwszy element 

listy */   
  {    
tempPtr = *startPtr;

*startPtr = (*startPtr)->next;

free (tempPtr);

retcode = 1;

   }

background image

42

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm usuwania elementu z listy jednokierunkowej 

(4):

Jeżeli dane są zgodne z danymi pierwszego elementu 

listy

Usuń pierwszy element listy;

W p.p. znajdź w liście element do usunięcia:


else

{ /* znajdź w liście element do usunięcia */ 

  prevPtr = *startPtr;    

   

/* początek listy */

  currPtr = (*startPtr)->next;  /* drugi element*/

    while (currPtr != NULL && currPtr -> data != nazwa)

  {

prevPtr = currPtr;

currPtr = currPtr -> next;

  }

background image

43

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm usuwania elementu z listy jednokierunkowej (5):

Jeżeli dane są zgodne z danymi pierwszego elementu listy

Usuń pierwszy element listy;

W p.p. znajdź element do usunięcia w liście:

Jeżeli nie znaleziono elementu, generuj komunikat;

W p.p. usuń znaleziony element;


if (currPtr == NULL)

retcode = 0;     /* node not found */

else
{  /* Usuń znaleziony element */

tempPtr = currPtr;

prevPtr->next = currPtr->next;

free (tempPtr);

retcode = 1;

}  }  }

return retcode;
}

background image

44

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

listowych 

Algorytm usuwania elementu z listy 
jednokierunkowej (6):

A

startPtr

B

C

Przed 
usunięciem:

NULL

A

startPtr

B

C

Po usunięciu:

NULL

background image

45

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Definiowanie elementu drzewa;

Dołączanie i usuwanie elementu drzewa;

Wyszukiwanie elementu w drzewie;

background image

46

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Drzewiastą strukturą danych nazywamy strukturę 
danych 

S=(D, R, e)

, w której relacja porządkująca 

N

 

opisuje kolejne, rekurencyjne powiązania pomiędzy 
danymi elementarnymi drzewa, tworzącymi kolejne 
„poddrzewa”.

Przykład struktury drzewiastej

Uniwersytet

Wydział

Wydział

Wydział

Wydział

Instytut

Instytut

Instytut

Instytut

Instytut

background image

47

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych

Istnieje wiele sytuacji w których przetwarzane 
informacje

mają strukturę hierarchiczna lub zagnieżdżoną, jak: 
drzewo

genealogiczne lub diagram struktury organizacyjnej.

Abstrakcje modelującą strukturę hierarchiczną 
nazywamy 

drzewem – jest to jeden z najbardziej podstawowych 

modeli

danych w informatyce.

background image

48

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych

Kiedy  mówimy  o  reprezentowaniu  drzew,  w  pierwszej 
kolejności mamy na myśli sposób reprezentowania węzłów. 

Różnica  miedzy  reprezentacjami  drzew  dotyczy  miejsca  w 
pamięci  komputera  gdzie  przechowywana    jest  struktura 
zawierająca węzły. 

W  języku  C  możemy  stworzyć  przestrzeń  dla  struktur 
reprezentujących wierzchołki za pomocą funkcji 

malloc

  ze 

standartowej  biblioteki 

stdhlib.h

,  co  powoduje, 

ż

e  do 

umieszczonych  w  pamięci  węzłów  mamy  dostęp  tylko  za 
pomocą  wskaźników.  Rozwiązaniem  alternatywnym  jest 
stworzenie  tablicy struktur i wykorzystanie jej elementów 
do  reprezentowania  węzłów.  Możemy  uzyskać  dostęp  do 
węzłów  nie  wykorzystując  ścieżek  w  drzewie.  Wadą  jest  z 
góry  określony  rozmiar  tablicy  (musi  istnieć  ograniczenie 
maksymalnego rozmiaru drzewa).

background image

49

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Drzewo binarne (dwójkowe):

Drzewo o stopniu 2 (każdy węzeł ma co najwyżej 
dwóch następników – potomków: lewego i 
prawego);

Ostatnimi potomkami są liście (elementy, które nie 
mają potomków);

e

d1

d2

d3

d4

d5

d6

poziom 1

poziom 2

poziom 3

Czy drzewo z jednego z poprzednich slajdów 

(Uniwersytet) jest drzewem binarnym?

 

background image

50

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Zupełne drzewo binarne (dwójkowe): 

Każdy węzeł, z wyjątkiem liści, ma dokładnie dwóch 

potomków;

Drzewo poszukiwań binarnych (BST):

Dla każdego węzła (nie liścia) wszystkie wartości 

przechowywane w lewym poddrzewie są mniejsze od 

jego wartości oraz przeciwnie dla drzewa prawego;

Drzewo AVL (1962 – Adelson-Velskii, Landis) 

Drzewo BST jest drzewem AVL wtedy, kiedy dla każdego 

wierzchołka wysokości dwóch jego poddrzew różnią się o 

co najwyżej 1 poziom;

Kopiec

Wartości przechowywane w potomkach każdego węzła są 

mniejsze od wartości węźle;

Drzewo jest szczelnie wypełniane od lewego poddrzewa;

Liście leżą na co najwyżej dwóch sąsiednich poziomach;

background image

51

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych

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 tablicy wskaźników 
do dzieci tego węzła. 

typedef struct NODE *pNODE

struct NODE{

int info;

pNODE children[BF];

};

Info

 reprezentuje 

etykietę węzła

. Stała 

bf

 jest 

rozmiarem 

tablicy

 

wskaźników

. Reprezentuje maksymalna  liczbę dzieci 

dowolnego węzła,  czyli 

czynnik rozgałęzienia

  (ang. 

branching 

factor

). i-ty element tablicy  reprezentującej węzeł  zawiera 

wskaźnik do i-tego dziecka tego węzła.  Brakujące połączenia 
możemy reprezentować za pomocą wskaźnika  pustego 

NULL

.

inf
o

p

0

        p

1

       ..........      p

bf-1

background image

52

Algorytmy i struktury danych, wykład 3

Zestawienie reprezentacji drzew

 

Reprezentacja oparta na tablicy wskaźników

 

umożliwia nam dostęp do  -tego dziecka dowolnego 
węzła w czasie O(1). Taka reprezentacja   wiąże się 
jednak ze znacznym marnotrawstwem przestrzeni 
pamięciowej,  jeśli tylko kilka węzłów ma wiele dzieci. 
W takim wypadku większość wskaźników w tablicy 

children

 będzie równa 

NULL

.

 

Reprezentacja skrajnie lewy potomek-prawy element 

siostrzany

  

wymaga  mniejszej przestrzeni 

pamięciowej.  Nie wymaga również istnienia   
maksymalnego czynnika rozgałęzienie węzłów. 
Możemy reprezentować   węzły z dowolna wartością 
tego czynnika, nie modyfikując  jednocześnie  
struktury danych. 

background image

53

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Element drzewa zawiera:

Dane elementarne,

Realizację relacji następstwa – dowiązania do 
następników;

Dane

Dowiązanie na 

prawego 

potomka

Dowiązanie na 

lewego potomka

Korzeń

Liść

Potomek

Przodek

background image

54

Algorytmy i struktury danych, wykład 3

dane 

elementar

ne

dowiązani

e do 

prawego 

potomka

dowiązani

e do 

lewego 

potomka 

Dynamiczne realizacje struktur 

drzewiastych 

Deklaracja elementu drzewa binarnego:

struct Node {
   int 

  data;

   struct Node *llink;
   struct Node *rlink; 
  };

typedef struct Node *NodePtr;

  /* pomocniczy typ wskaźnikowy do struktury ‘Node’ */

/* zmienna ‘start’ tego typu wskazywać będzie korzeń 
*/ 

background image

55

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Podstawowe operacje na drzewach binarnych:

szukanie elementu w drzewie, 

przeglądanie drzewa;

dołączanie elementu do drzewa, 

usuwanie elementu z drzewa, 

Uwaga:

Operacje te często są realizowane 
rekurencyjnie;

background image

56

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm szukania elementu w drzewie binarnym (1):

Cel:

uzyskanie dowiązania do węzła;

można je interpretować jako identyfikację węzła; 

Dane wejściowe:

Dowiązanie do korzenia drzewa ‘Root’;

Kryterium poszukiwania, np. wartość danej 
elementarnej;

Uwagi:

kolejność przeszukiwania dowolna – w skrajnym 
przypadku należy przejrzeć wszystkie węzły w drzewie 
(złożoność O(n));

stosowane rozwiązania: pętla lub rekurencja;

background image

57

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm szukania elementu w drzewie binarnym (2):

Ustaw aktualne dowiązanie na korzeń drzewa;

Dopóki aktualne dowiązanie jest różne od NULL:

Jeżeli wartość szukana jest mniejsza od danej 
aktualnego węzła, to szukaj w jego lewym poddrzewie;

Jeżeli wartość szukana jest większa od danej aktualnego 
węzła, to szukaj w jego prawym poddrzewie;

Jeżeli wartość szukana jest równa danej aktualnego 
węzła, to koniec – daj dowiązanie do węzła;

background image

58

Algorytmy i struktury danych, wykład 3

przejście 

do lewego 

poddrzew

a

przejście 

do 

prawego 

poddrzew

a

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm szukania elementu w drzewie binarnym (3):

Wersja procedury z pętlą:
NodePtr find (int inValue, NodePtr node) 
{

    

while (node) {

  if (inValue == node -> data)
    return node;
  else if (inValue < node -> data)
    node = node -> llink;
  else if (inValue > node -> data)
    node = node -> rlink;

 

  return NULL;

}

background image

59

Algorytmy i struktury danych, wykład 3

wywołanie 

procedury 

dla 

lewego 

poddrzew

a

wywołanie 

procedury 

dla 

prawego 

poddrzew

a

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm szukania elementu w drzewie binarnym (4):

Wersja procedury rekurencyjnej:
NodePtr find (int inValue, NodePtr node) 
{

    

if (node) {

  if (inValue == node -> data)
    return node;
  else if (inValue < node -> data)
    return find ( inValue, node > llink);
  else if (inValue > node -> data)
    return find ( inValue, node > rlink);

 

else return NULL;

}

background image

60

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego (1):

Cel:

jednokrotne „odwiedzenie” każdego elementu 
drzewa;

można je interpretować jako umieszczenie wszystkich 
węzłów w jednej linii – linearyzacja drzewa; 

Dane wejściowe:

Dowiązanie do korzenia drzewa ‘Root’;

Uwagi:

kolejność przejścia dowolna – liczba możliwych 
ścieżek w drzewie o n węzłach wynosi n! 
(permutacja?, prawda czy fałsz???);

najczęściej stosowane sposoby: wszerz i w głąb;

background image

61

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(2):

Wersja „inorder” – LVR (porządek symetryczny)

Przejście do lewego poddrzewa (L);

Odwiedzenie węzła (V);

Przejście do prawego poddrzewa (R);

Wersja „preorder” – VLR (porządek prosty)

Odwiedzenie węzła (V);

Przejście do lewego poddrzewa (L);

Przejście do prawego poddrzewa (R);

Wersja „postorder” – LRV (porządek odwrotny)

Przejście do lewego poddrzewa (L);

Przejście do prawego poddrzewa (R);

Odwiedzenie węzła (V);

background image

62

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb (3):

Wersja procedury „inorder” – LVR 

porządek symetryczny (lewe-korzeń-prawe)

void inorder (NodePtr node) 

     if (node) 

{
  inorder (node -> llink);
  visit (node);
  inorder (node -> rlink);
}
 }

background image

63

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb (4):

Wersja procedury „preorder” – VLR

porządek prosty (korzeń-lewe-prawe)

void preorder (NodePtr node) 

     if (node) 

{
  visit (node);
  preorder (node -> llink);
  preorder (node -> rlink);
}
 }

background image

64

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb (5):

Wersja procedury „postorder” – LRV

porządek odwrotny (lewe-prawe-korzeń)

void postorder (NodePtr node) 

     if (node) 

{
  postorder (node -> llink);
  postorder (node -> rlink);
  visit (node);
}
 }

background image

65

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(6):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik:

background image

66

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(7):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik:

background image

67

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(8):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik:

background image

68

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(9):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9

background image

69

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(10):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9

background image

70

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(11):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9

background image

71

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(12):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9, 11

background image

72

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(13):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9, 11

background image

73

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(14):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9, 11, 15

background image

74

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(15):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9, 11, 15

background image

75

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(16):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9, 11, 15

background image

76

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(17):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9, 11, 15, 
28

background image

77

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm przeglądanie drzewa binarnego w głąb 
(18):

Przykład dla procedury „inorder” – LVR

1
5

9

2
8

NULL

NULL

NULL

1
1

NULL

NULL

Root

inorder (node -> 
llink);
visit (node);
inorder (node -> 
rlink);

Wynik: 9, 11, 15, 
28

background image

78

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm dołączania elementu do drzewa 
binarnego (1):

Cel:

dodanie nowego elementu do drzewa;

Dane wejściowe:

Dowiązanie do korzenia drzewa ‘Root’;

Nowa dana elementarna;

background image

79

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm dołączania elementu do drzewa binarnego 
(2):

Utwórz element i ustal dane elementarne;

Znajdź miejsce wstawienia elementu w drzewie;

Wstaw element do drzewa:

Wstaw element jako pierwszy w drzewie;

(lub) Wstaw element we wskazane miejsce w drzewie; 

background image

80

Algorytmy i struktury danych, wykład 3

rekurenc

ja

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm dołączania elementu do drzewa binarnego (3):

void Insert (int inValue, NodePtr &next) {
    if  (next == NULL ) {
         next = (Node *)malloc(sizeof(Node));

  next -> llink = NULL;   

         next -> rlink = NULL;
         next -> data = inValue;
    }
    else if ( inValue  <   next -> data )
        Insert( inValue, next -> llink ) ;      
    else if ( inValue  >   next -> data )
        Insert( inValue, next -> rlink );
}

background image

81

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm dołączania elementu do drzewa binarnego 
(4):

Wstawienie do drzewa elementu z wartością ’11’;

Insert ( 11, Root);

1
5

9

2
8

Root

NULL

NULL

NULL

NULL

inValue = 11

background image

82

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm dołączania elementu do drzewa binarnego 
(5):

Dopóki (inValue < next -> data) 

Insert ( 11, next -> llink);

1
5

9

2
8

next

NULL

NULL

NULL

NULL

inValue = 11

background image

83

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm dołączania elementu do drzewa binarnego 
(6):

Dopóki (inValue > next -> data) 

Insert ( 11, next -> rlink);

1
5

9

2
8

next

NULL

NULL

NULL

NULL

inValue = 11

background image

84

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm dołączania elementu do drzewa binarnego 

(7):

if  (next == NULL ) {

  next = (Node *)malloc(sizeof(Node));

  next -> llink = NULL;   

  next -> rlink = NULL;

  next -> data = inValue;

}

1
5

9

2
8

next

NULL

NULL

NULL

NULL

inValue = 11

background image

85

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm dołączania elementu do drzewa binarnego 
(8):

Drzewo po wstawieniu elementu z wartością ’11’;

1
5

9

2
8

next

NULL

NULL

NULL

1
1

NULL

NULL

Root

inValue = 11

background image

86

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm usuwania elementu z drzewa 
binarnego (1):

Cel:

Usunięcie węzła z drzewa;

Dane wejściowe:

Dowiązanie do korzenia drzewa ‘Root’;

Opis elementu usuwanego, np. wartość danej 
elementarnej;

Uwagi:

Przypadek 1: węzeł jest liściem;

Przypadek 2: węzeł ma jednego potomka;

Przypadek 3: węzeł ma dwóch potomków;

background image

87

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm usuwania elementu z drzewa binarnego (2):

Przypadek 1: węzeł jest liściem:

Znajdź element w drzewie;

Usuń węzeł z drzewa;

1
5

9

2
8

NULL

1
5

2
8

NULL

7

9

NULL

11

11

25

25

background image

88

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm usuwania elementu z drzewa binarnego (3):

Przypadek 2: węzeł ma jednego potomka:

Znajdź element w drzewie;

Usuń węzeł z drzewa;

Zastąp węzeł usunięty jego potomkiem (zmiana 
dowiązania w przodku węzła usuwanego)

1
5

9

2
8

NULL

1
5

2
5

NULL

NULL

7

7

11

11

7

25

background image

89

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm usuwania elementu z drzewa binarnego (4):

Przypadek 3: węzeł ma dwóch potomków:

Znajdź element w drzewie;

Usuń węzeł z drzewa;

Zastąp węzeł usunięty: najmniejszym z prawego 
poddrzewa lub największym z lewego poddrzewa;

1
5

9

2
8

NULL

7

11

25

background image

90

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm usuwania elementu z drzewa binarnego (5):

Przypadek 3: węzeł ma dwóch potomków:

Wersja z przesunięciem najmniejszego elementu z 
prawego poddrzewa (skrajnie lewy wierzchołek tego 
poddrzewa);

1
5

9

2
8

NULL

7

2
5

9

7

11

25

11

28

NULL

NULL

background image

91

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm usuwania elementu z drzewa binarnego (6):

Przypadek 3: węzeł ma dwóch potomków:

Wersja z usunięciem największego elementu z lewego 
poddrzewa (skrajnie prawy wierzchołek);

1
5

9

2
8

NULL

7

1
1

9

7

11

25

28

NULL

25

NULL

background image

92

Algorytmy i struktury danych, wykład 3

Dynamiczne realizacje struktur 

drzewiastych 

Algorytm usuwania elementu z drzewa binarnego (7):

Jeżeli w „Przypadku 3” przesuwany:

skrajnie prawy węzeł (największy element) z lewego 
poddrzewa posiada potomka lewego;

skrajnie lewy węzeł (najmniejszy element) z prawego 
poddrzewa posiada potomka prawego;

to należy zastosować dla węzła przesuwanego 
dodatkowo algorytm usuwania z „Przypadku 2” 
(usuwanie węzła z jednym potomkiem); 

Inne rozwiązanie dla operacji usuwania zobaczymy na 
wykładzie dotyczącym działań na rodzajach drzew 
binarnych; 

background image

93

Algorytmy i struktury danych, wykład 3

Podsumowanie

Omówiliśmy podstawowe zagadnienia związane ze 
strukturami danych: listy i drzewa; 

Przestudiuj jeszcze raz poszczególne algorytmy (ze 
szczególną uwagą usuwanie elementów);

Spróbuj dokonać modyfikacji w kodzie prezentowanych 
procedur dla list i drzew; 

Zauważ, że podane algorytmy tworzą pewien zestaw 
standardu postępowania ze strukturami danych i 
szczegółowe postaci algorytmów zależą tylko od 
analizowanej struktury danych.

Dziękuję za uwagę


Document Outline