PPT - Kustra Piotr

Download Report

Transcript PPT - Kustra Piotr

AiSD_W4
Dynamiczne struktury danych
dr inż. Kustra Piotr
Opracowanie: Anna Adrian oraz Kustra Piotr
Tablice dynamiczne
program DynamicVec;
var
t1 : array of integer;
t2 : array [1..10] of integer;
nElem: integer;
BEGIN
read(nElem);
write('Ile elementów? ', nElem);
setlength(t1, nElem);
for i:=1 to nElem do
begin
t1[i]:=0;
end;
end.
t2
t1
…
nElem
2
Macierz dynamiczna
program DynamicMatrix;
var
sizeX, sizeY, i, j:integer;
m:array of array of integer;
begin
size:=15;
SetLength(m, sizeX, sizeY);
for i:=0 to sizeX-1 do
begin
for j:=0 to sizeY-1 do
begin
m[i,j]:=1;
end;
end;
readln();
end.
sizeY
sizeX
3
Zbiory dynamiczne
Zbiory
– w matematyce pojęcie fundamentalne, niezmienne;
- w informatyce zbiory mogą być zmieniane w wyniku
działania algorytmów (powiększać, zmniejszać, albo
zmieniać w czasie) – stąd ich nazwa zbiory dynamiczne.
Zbiór dynamiczny do którego można dodawać (wstawiać)
elementy, usuwać elementy ze zbioru i sprawdzać czy
element należy do zbioru nazywane są słownikami.
Metoda realizacji zbiorów dynamicznych zależy od operacji,
które na konkretnym zbiorze mogą być wykonane.
4
Elementy zbioru dynamicznego
• Każdy element zbioru dynamicznego jest reprezentowany przez
obiekt, którego pola można odczytać lub modyfikować, jeśli mamy
wskaźnik tego obiektu.
• W pewnych rodzajach zbiorów dynamicznych wyróżnione jest jedno
z pól każdego elementu i nazywane kluczem (key) obiektu.
• Jeśli każdy element zbioru dynamicznego ma własny unikalny
(niepowtarzalny) klucz, wtedy zwykle taki zbiór traktujemy jako zbiór
kluczy.
• W niektórych implementacjach zbiorów dynamicznych zakłada się,
że zbiór kluczy jest liniowo uporządkowany
• Obiekt może zawierać też inne dane (dodatkowe dane) zawarte
w innych polach, jednak one nie wpływają na realizację zbioru
• Istnieje możliwość występowania w obiekcie pól zawierających
wartości zmieniające się przez operacje na zbiorze (np. wskaźniki5
do innych obiektów w zbiorze)
Operacje na zbiorach dynamicznych
Wyróżnia się dwie grupy operacji na zbiorach dynamicznych,
są to:
• Zapytania– pozwalające uzyskać pewne informacje na
temat zbioru: SEARCH, MINIMUM, MAXIMUM,
SUCCESSOR(następca), PREDECESSOR(poprzednik)
• Operacje modyfikujące– umożliwiające wprowadzanie
zmian w zbiorze dynamicznym : INSERT i DELETE.
Wymienione operacje uznawane są jako typowe.
W konkretnych implementacjach zbiorów dynamicznych
zwykle znajdują zastosowanie tylko niektóre z nich.
6
Operacje na zbiorach dynamicznych
Zapytania
SEARCH(S,k) - dla danego zbioru S i klucza k zwraca wskaźnik
x do takiego obiektu w zbiorze S, dla którego key[x]=k albo
NIL- gdy w zbiorze S nie znaleziono żadnego obiektu
spełniającego podany warunek.
MINIMUM(S) – zwraca w wyniku element zbioru S o najmniej szym kluczu; dotyczy zbiorów liniowo uporządkowanych.
MAXIMUM(S) wskazuje element zbioru S o największym
kluczu; dotyczy zbiorów liniowo uporządkowanych.
7
Operacje na zbiorach dynamicznych
Zapytania
SUCCESSOR (S,x) - dla danego elementu x o kluczu
należącym do uporządkowanego zbioru S daje w wyniku
następnik elementu x w S, tj najmniejszy element ze zbioru
S który jest większy od x.
Jeśli x jest największym elementem w zbiorze S
wynikiem jest stała NIL
PREDECESSOR (S,x) dla danego elementu x o kluczu
należącym do uporządkowanego zbioru S daje w wyniku
poprzednik elementu x w S, tj największy element ze zbioru
S który jest mniejszy od x.
Jeśli x jest najmniejszym elementem w zbiorze S
wynikiem jest stała NIL
8
Operacje na zbiorach dynamicznych
Operacje modyfikujące
INSERT(S,x) – dodaje do zbioru S wskazany element x.
Przy tej operacji zakłada się zwykle, że wcześniej zostały
zainicjowane wartości wszystkich pól obiektu wskazanego
przez x istotne dla realizacji zbioru S
DELETE(S,x)- dla danego wskaźnika x do obiektu zawartego
w zbiorze S usuwa ten element ze zbioru S.
Warto zauważyć, że argumentem tej operacji jest
wskaźnik do elementu x a nie wartość jego klucza.
Czas wymagany do realizacji operacji na zbiorze wyrażany
jest zwykle jako funkcja rozmiaru zbioru.
9
Elementarne dynamiczne struktury danych
Zbiory dynamiczne mogą być realizowane przez różne
struktury danych.
W dalszym ciągu wykładu przedstawiono podstawy
realizacji elementarnych struktur danych, takich jak:
•
•
•
•
Stosy
Kolejki
Listy
Drzewa
10
Stosy i kolejki
Stosy i kolejki są realizacją zbiorów dynamicznych
w których element usuwany jest określony jednoznacznie:
 stos: strategia LIFO (last in first out) –najpóźniej dodany
usuwany jest jako pierwszy
 kolejka: strategia FIFO (first in first out) _ najwcześniej
usuwany jest element najstarszy
Stosy i kolejki mogą być efektywnie implementowane
na wiele sposobów
11
Stos
Stos zawierający nie więcej niż n elementów można zaimplementować
w n elementowej tablicy S[1..n]
Atrybut top [S] oznacza numer ostatnio wstawionego elementu do stosu.
Stos składa się z elementów: S[1..top[S]], gdzie
 S[1] jest elementem na dnie stosu
 S[top[S]] jest elementem na wierzchu stosu
S
1
2
3
4
15
6
2
9
top [S] = 4
5
6
7
12
Podstawowe operacje na stosie
Sprawdzam czy stos jest pusty:
Stack-Empty(S)
if top (S) =0
then return TRUE
else return FALSE
•Jeśli top[S] =0 to stos jest pusty.
 Na próbę zdjęcia elementu ze stosu pustego powinien
pojawić się komunikat o wystąpieniu błędu niedomiaru.
 Błąd przepełnienia występuje wtedy gdy top[S] > n
13
Podstawowe operacje na stosie
Insert – PUSH
PUSH (S,x)
top [S]  top [S] +1
S[ top [S]]  x
--------------------------------------------------------------------------PUSH (S,17)
PUSH (S,3)
S
1
2
3
4
5
6
15
6
2
9
17
3
7
top [S] = 6
14
Podstawowe operacje na stosie
Delete - POP
POP (S)
If STACK-EMPTY (S)
then error „niedomiar”
else top [S]  top [S] -1
return S[ top [S] +1]
---------------------------------------------------------------------------
S
1
2
3
4
5
6
15
6
2
9
17
3
7
top [S] = 5
15
Kolejki
Kolejkę zawierającą nie więcej niż n elementów można
zaimplementować w n elementowej tablicy Q[1..n]
Atrybut head [Q] wskazuje głowę (początek) kolejki
Atrybut tail[Q] wyznacza następną wolną pozycję na którą można
wstawić do kolejki nowy element.
Jeśli head [Q] = tail[Q] to kolejka jest pusta.
Początkowo head [Q] = tail[Q] =1
Jeśli kolejka jest pusta i próbujemy usunąć z niej element występuje
wtedy błąd niedomiaru
Jeśli head [Q] = tail[Q] +1, to kolejka jest pełna i przy próbie
wstawienia kolejnego elementu występuje błąd przepełnienia
16
Kolejki
1
2
3
4
Q
head [Q]=7
5
6
7
8
9
10
11
15
6
9
8
4
12
tail [Q] = 12
Kolejka zawiera 5 elementów na pozycjach Q [7..11]
Elementy kolejki zajmują pozycje
head [Q], head [Q]+1,……………, tail[Q]-1
Zakładamy, że Tablica Q jest cykliczna, tzn pozycja 1 jest
bezpośrednim następnikiem pozycji n .
17
Podstawowe operacje na kolejkach
ENQUEUE (Q,x)
ENQUEUE (Q,x)
Q [tail [Q]]  x
if tail [Q]=length [Q]
then tail [Q] 1
else tail [Q]  tail [Q] +1
-----------------------------------------------------------------------------------------------ENQUEUE (Q,17); ENQUEUE (Q,3); ENQUEUE (Q,5)
Q
1
2
3
5
3
4
5
6
7
8
9
10
11
12
15
6
9
8
4
17
18
tail [Q] = 3
head [Q]=7
Podstawowe operacje na kolejkach
DEQUEUE (Q)
DEQUEUE (Q,x)
x Q [head[Q]]
if head [Q]=length [Q]
then head[Q] 1
else head[Q]  head [Q] +1
return x
-----------------------------------------------------------------------------------------------DEQUEUE (Q);
Q
1
2
3
5
tail [Q] = 3
3
4
5
6
7
8
9
10
11
12
15
6
9
8
4
17
head [Q]=8
19
Kolejka dwustronna
• W stosach wstawianie i usuwanie elementów jest realizowane
tylko na jednym końcu, na górze stosu.
• W kolejce dodajemy elementy na jednym końcu a usuwamy
z drugiego końca.
• Kolejka dwustronna (dwukierunkowa) jest strukturą danych
pozwalającą na wstawianie i usuwanie elementów na obu
końcach kolejki.
• Napisać procedury służące do wstawiania elementów na obu
końcach i do usuwania z obu końców kolejki zaimplementowanej
w tablicy
20
Listy
• Lista z dowiązaniami jest prostą i elastyczną strukturą
danych, służącą do reprezentowania zbiorów
dynamicznych, umożliwiającą wykonanie wszystkich
typowych operacji na zbiorach.
• Elementy listy ułożone są w porządku liniowym.
• Porządek określają wskaźniki związane z każdym
elementem listy, a nie jak w tablicach, gdzie porządek
jest wyznaczony przez indeksy.
21
Atrybuty listy
Każdy element listy dwukierunkowej (doubly linked list) jest rekordem
składającym się z trzech pól :
key[x] –zawierającego klucz elementu x,
prev[x]- wskazującego na poprzednika elementu x, Jeśli prev[x]=NIL to
element x nie ma poprzednika, x jest pierwszym elementem listy,
mówimy, że x jest wtedy głową (head) listy.
Jeśli head[L] = NIL to lista jest pusta
next[x] – wskazującego na następnika x na liście
Jeśli next [x]=NIL to element x nie ma następnika , czyli x jest ostatnim
elementem listy, nazywanym ogonem listy
22
Rodzaje list
Lista jest jednokierunkowa (singly linked list) gdy pomijany
jest wskaźnik prev
Lista jest posortowana gdy kolejność elementów na liście jest
zgodna z porządkiem na ich kluczach;
- element o najmniejszym kluczu znajduje się w głowie,
- element o największym kluczu w ogonie listy.
W liście nieposortowanej kolejność elementów jest dowolna.
W liście cyklicznej, elementy tworzą pierścień.
Pole prev elementu w głowie wskazuje na ogon, a pole next w
ogonie na głowę listy cyklicznej.
23
Operacje na listach - wyszukiwanie
Założenie: listy są dwukierunkowe, nieposortowane.
Procedura LIST-SEARCH (L,k) wyznacza pierwszy element o kluczu k na
liście L za pomocą prostego sortowania. Czas jej działania wynosi (n)
LIST-SEARCH (L,k)
x head[L]
while x NIL i key[x]  k
do x next[x]
return x
Po wywołaniu procedury LIST-SEARCH (L,4) na liście otrzymamy wskaźnik
do jej trzeciego elementu, a po wywołaniu LIST-SEARCH (L,7)
otrzymamy NIL
24
Operacje na listach
– wstawianie nowych elementów
Procedura LIST-INSERT(L,x) przyłącza element x, którego pole key zostało wcześniej
zainicjowane, na początek listy.
Czas działania procedury na liście o n elementach wynosi O(1)
LIST-INSERT(L,x)
next[x] head[L]
if head[L]  NIL
then prev[head[L] ] x
head[L] x
prev[x]  NIL
-----------------------------------------------------------------------------------------------------------------Po wykonaniu procedury LIST-INSERT(L,x), gdzie key[x]=25 w głowie listy znajdzie
się nowy rekord z kluczem 25 pole next zawiera wskaźnik do poprzedniej głowy z
kluczem 9
25
Operacje na listach –usuwanie elementów
z list z dowiązaniami
• Wywołanie procedury LIST-DELETE (L,x) powoduje usunięcie
elementu x z listy L.
•
• Wycinanie elementu z listy polega na modyfikacji odpowiednich
wskaźników.
• Czas działania procedury na liście o n elementach wynosi O(1) ale
pesymistyczny czas usuwania elementu o zadanym kluczu wynosi
(n)
• ponieważ
• Najpierw musi zostać wywołana procedura LIST-SEARCH, aby
wyznaczyć wskaźnik elementu x
26
Operacje na listach –usuwanie elementów
z list z dowiązaniami
LIST-DELETE (L,x)
if prev[x]  NIL
then next[ prev[x]] next[x]
else head[L] next[x]
if next[x]  NIL
then prev [next [x]] prev[x]
-----------------------------------------------------------------------------Wynik wykonania operacji LIST-DELETE (L,x), gdzie x wskazuje na
element o kluczu 4 z poprzedniej listy
27
Tablicowe reprezentacje struktur
wskaźnikowych
Reprezentacja wielotablicowa
Dana jest lista:
Przedstawmy reprezentację tej listy za pomocą trzech tablic:
Tablica key zawiera wartości kluczy znajdujących się na liście
Tablice next i prev zawierają wskaźniki
Wartości key[x], prev[x] i next[x] określają jeden element listy
o indeksie x.
Indeksy odgrywają rolę wskaźnika w tablicach key, next i prev
28
Tablicowa reprezentacja listy (danej)
W zmiennej L pamiętany jest numer pozycji (7) na której znajduje się
głowa listy.
Na liście klucz 4 znajduje się bezpośrednio za elementem o kluczu 16
29
Lista jednostronnie wiązana –
implementacja wskaźnikowa
Definicja elementu listy
info
*next
type stos = ^node;
node=record
val: integer;
next: stos;
end;
val: integer
next: stos
H
10
H
NIL
-6
12
NIL
30
Dodawanie do stosu
procedure PUSH (x:integer);
var
pom:^node;
begin
new(pom);
pom^.val:=x;
pom^.next:=head;
head:=pom;
end;
H
pom
NIL
x
31
Dodawanie do stosu
procedure PUSH (x:integer);
var
pom:^node;
begin
new(pom);
pom^.val:=x;
pom^.next:=head;
head:=pom;
end;
x1
H
pom
NIL
x2
32
Usuwanie ze stosu
procedure POP;
var
H
pom:^node;
begin
if head <>NIL then
begin
pom:=head;
head:= pom^.next;
dispose(pom);
end;
end;
10
-6
12
NIL
pom
33
Przeglądanie listy jednostronnie
wiązanej
procedure ShowList;
var
H
pom:^node;
begin
pom:=head;
write('HEAD --> ');
while (pom<>NIL) do
begin
write(pom^.val, '--> ');
pom:=pom^.next;
end;
writeln ('NIL');
end;
10
-6
12
NIL
pom
HEAD--> 10-->
34
Przeglądanie listy jednostronnie
wiązanej
procedure ShowList;
var
H
pom:^node;
begin
pom:=head;
write('HEAD --> ');
while (pom<>NIL) do
begin
write(pom^.val, '--> ');
pom:=pom^.next;
end;
writeln ('NIL');
end;
10
-6
12
NIL
pom
HEAD--> 10-->-6->12-->
35
Przeglądanie listy jednostronnie
wiązanej
procedure ShowList;
var
H
pom:^node;
begin
pom:=head;
write('HEAD --> ');
while (pom<>NIL) do
begin
write(pom^.val, '--> ');
pom:=pom^.next;
end;
writeln ('NIL');
end;
10
-6
12
NIL
pom
HEAD--> 10-->-6->12--> NIL
36