Algorytmy i Struktury Danych Struktury Danych

advertisement
Algorytmy i Struktury Danych
Struktury Danych
WYKŁAD 2
PROWADZĄCY: DR PAWEŁ DROZDA
Plan Wykładu
 Tablice
 Stosy
 Kolejki
 Listy
 Drzewa
dr Paweł Drozda
Struktury danych – po co?
 porządkowanie informacji na komputerach w formie




zrozumiałej dla człowieka
pomocne narzędzie przy rozwiązywaniu
skomplikowanych problemów algorytmicznych
listy – ułatwiają tworzenie elastycznych baz danych
drzewa binarne – ułatwiają analizę wyrażeń
arytmetycznych
grafy – duże zastosowanie w dziedzinie sztucznej
inteligencji
dr Paweł Drozda
Tablice (1)
 Najprostsza struktura danych
 Kontener zawierający N elementów typu T
 Dostęp do elementów przy pomocy indeksu (pozycji)
 Operacje
USTAW(τ, x, p) – w tablicy τ wstaw element x na pozycji p
 POBIERZ(τ, p) – z tablicy τ odczytaj element na pozycji p
 USUŃ(τ, p) – z tablicy τ usuń element na pozycji p
 Przykład: tablica liczb całkowitych

indeks
0
1
2
3
4
1
2
3
5
7
5
6
7
8
9
11 13 17 19 23
element tablicy o indeksie 2, zawierający
wartość 3
dr Paweł Drozda
Tablice (2)
 Tworzenie tablicy w C++
 T nazwa[const rozmiar];
int tab[100];
char znaki[] = {‘x’, ’y’, ’z’};
 Dostęp do elementów
 indeksy: 0,…,N-1
tab[0] = 1;
int x = tab[i];
 Rozmiar tablicy musi być znany a priori (tablica statyczna)
dr Paweł Drozda
Tablica – przykład
#include <iostream>
int main()
{
int tab[4];
tab[0] = 12;
tab[1] = 65;
tab[2] = 44;
tab[3] = 7;
int suma = 0;
for (int i=0; i<4; i++)
{
suma = suma + tab[i];
}
std::cout << suma;
return 0;
}
dr Paweł Drozda
void usun (int tab, int p)
{
for (i=p; i<length(tab); i++)
tab[i]=tab[i+1];
}
void wstaw(int tab, int p, int x)
{
tab[p]=x;
}
void wstaw1 (int tab, int p, int x)
{
for ()
tab[p]=x;
}
Tablice wielowymiarowe
 Deklaracja tablicy wielowymiarowej
T tab[N1] [N2]…[Nk]
 można zapisać N1 *N2*…*Nk
elementów w tablicy
 Przykład
int tab[2][2][2];
tab[][][]={{1,2,3},{1,4,3},{5,6,7},{7,6,5},{2,2,2}}
 Dostęp do elementów
 poprzez indeksy n1 n2…nk
 Przykład – tablica dwuwymiarowa
(macierz)
tab[0][0]=1
tab[1][2]=5

dr Paweł Drozda
#include <iostream>
int main()
{
int tab[10][10];
for (int i=0;i<9;i++)
{
for (int j=0;j<9;j++)
{
tab[i][j] = i*j;
tab[j][i] = i*j;
}
}
std::cout << tab[4][7];
return 0;
}
Stos
 dostęp tylko od wierzchołka
 zasada działania tzw. LIFO (Last In First Out)
 Dostępne dwie podstawowe funkcje:


Top
PUSH(S,X) – umieszczenie elementu na stosie
POP(S) – zdjęcie elementu ze stosu
 Każdy element składa się z dwóch pól:
 dane – dowolna zmienna
 wskaźnik - zawiera informacje o miejscu
przechowania kolejnego elementu na stosie
 Dodatkowy element:
 Top – przechowuje wskaźnik do szczytu stosu
 Dodatkowe funkcje stosu:
 przepełnienie - dla stosu o zadeklarowanej max
wielkości
 stos pusty – sprawdza czy stos nie jest pusty
dr Paweł Drozda
dane3
wskaźnik
dane2
wskaźnik
ogniwo
dane1
wskaźnik
…
Przykład – użycie stosu
push(S,1)
push(S,5)
push(S,3)
3
5
1
PUSTO
pop(S)
-> 3
top(S) -> 5
S
dr Paweł Drozda
pop(S)
->5
Implementacja stosu - wskaźniki
void push (int x)
{
ELEMENT *q = new ELEMENT;
if (top==NULL)
{
q->wartosc=x;
top=q;
}
else{
q-> wartosc =x;
q-> next=top;
top=q;
}
dr Paweł Drozda
Stos jako tablica
1
2
3
4
12
4
5
6
5
6
7
7
START,
Wielkość stosu 6
top[S]=4
1
2
3
4
5
6
12
4
5
6
4
5
PUSH(S,4), PUSH(S,5)
PUSH(S,7) – przepełnienie!!
top[S]=6
1
2
3
12
4
5
top[S]=3
dr Paweł Drozda
4
5
6
7
POP(S), POP(S), POP(S)
Stos jako tablica - implementacja
int Pusty(S){
if (top(S)==0) return true;
else return false;
}
void Push(S,x){
top(S)=top(S)+1;
S[top(S)]=x;
}
Pop(S){
If Pusty(S) error „nie ma co zdjac”;
else { top(S)--;
return S[top(S)+1];}
}
dr Paweł Drozda
Kolejka
 Zasada działania – FIFO (First In First Out)
 Podstawowe funkcje:
 ENQUEUE(Q,x) – dodanie elementu x do kolejki
 DEQUEUE(Q) – zdjęcie elementu z kolejki
 Struktura elementu:
 wartość elementu
 wskaźnik do elementu następnego w kolejce
 Elementy dodatkowe
 Head – przechowuje wskaźnik do początku kolejki
 Tail – przechowuje wskaźnik do końca kolejki
head
tail
dane1
wskaźnik
dr Paweł Drozda
dane2
wskaźnik
dane3
wskaźnik
Przykład – użycie kolejki
Enqueue(Q,2)
Enqueue(Q,5)
Enqueue(Q,3)
DEQUEUE(Q)
HEAD(Q) -> 5
Dequeue(Q)
2
dr Paweł Drozda
5
3
Implementacja kolejki
void dequeue(Q){
if (head!=NULL)
head=head->next;
else error „nic nie ma w kolejce”;
}
void enqueue(Q, x){
ELEMENT *q= new ELEMENT;
q->wartosc=x;
tail->next=q;
tail=q;
}
dr Paweł Drozda
Kolejka za pomocą tablicy
1
2
3
4
5
6
7
12
4
5
6
START
Head(Q)=4, Tail(Q)=7
1
2
14
1
3
4
5
6
7
12
4
5
6
6
7
5
6
ENQUEUE(Q,4),
ENQUEUE(Q,1)
Tail(Q)=2, Head(Q)=4
1
2
14
1
3
4
5
Tail(Q)=2, Head(Q)=6
dr Paweł Drozda
DEQUEUE(Q),
DEQUEUE(Q)
Kolejka – implementacja tablicy
void dequeue(Q){
x = Q[head(Q)];
If (head(Q)= length(Q)) head(Q)=1;
else head(Q)++;
return x;
}
void enqueue(Q,x){
if (tail(Q))==lenght(Q)) tail(Q)=1;
else tail(Q)++;
Q[tail(Q)]=x;
}
dr Paweł Drozda
Problem
 Jak za pomocą dwóch kolejek stworzyć stos?
Kolejka 2
Kolejka 1
2
5
2
5
 Jak za pomocą dwóch stosów stworzyć kolejkę?
dr Paweł Drozda
3
Listy (1)
 Struktura danych z elementami ułożonymi w
liniowym porządku – porządek ustalony przez
wskaźniki
 Element złożony:


lista jednokierunkowa: wartość i wskaźnik
lista dwukierunkowa wartość,
dwa wskaźniki
head
tail
Lista
jednokierunkowa
dr Paweł Drozda
wartość
wartość
wartość
następny
następny
NULL
Listy (2)
 Podstawowe funkcje
 Search(L, x) – znajduje wskaźnik do elementu o kluczu x, bądź
NULL gdy nie ma elementu z kluczem x
 Insert (L, x, w) – wstawia element o kluczu x w miejscu
wskazywanym przez w
 Delete (L,w) – usuwa element wskazywany przez w
 Min(L) – zwraca element o najmniejszym kluczu
 Max(L) – zwraca element o największym kluczu
head
tail
wartość
wartość
wartość
prev | next
prev | next
prev | next
dr Paweł Drozda
Lista
dwukierunkowa
Tworzenie listy
Head(L)
Tail(L)
/
3
Insert(L,3,Head)
Insert(L,5,Tail)
Insert(L,6,Tail)
Insert(L,3,Tail)
Search(L,5)
dr Paweł Drozda
5
6
Delete(L,Tail)
Tail(L)
7
/
Lista jednokierunkowa
 Dodanie elementu pomiędzy dwa istniejące
wartość
wartość
wartość
następny
następny
NULL
wartość
następny
dr Paweł Drozda
Listy - implementacja
Search (L,x){
temp=head(L);
while ((temp->next!=null) &&(temp->wartosc!=x))
temp=temp->next;
return temp;
}
Insert(L,x){ // na koniec listy
ELEMENT q = new ELEMENT;
tail->next=q;
tail=q;
q->wartosc=x;
}
dr Paweł Drozda
Listy - własności
 Liniowe uporządkowanie elementów
 Elastyczność
 wstawianie / usuwanie na dowolnej pozycji
 dynamiczna długość
 Brak bezpośredniego dostępu do i-go elementu (O(n))
 Dodatkowy koszt pamięciowy (wskaźniki)
Drzewa binarne (1)
 Węzeł reprezentowany za pomocą rekordów
 klucz węzła
parent
 wskaźnik do ojca
klucz
left right
 wskaźnik do lewego syna
 wskaźnik do prawego syna
parent
klucz
left
parent
klucz
left
dr Paweł Drozda
right
parent
klucz
left
right
right
parent
parent
klucz
parent
klucz
klucz
left
right
left
right
left
right
Drzewo binarne (2)
 Oznaczenia
 root(T) – wierzchołek korzenia – gdy wskaźnik parent
wskazuje na NULL
 leaf(T) – wierzchołek liścia – gdy wskaźniki left i right
wskazują na NULL
dr Paweł Drozda
Download