• Nie Znaleziono Wyników

Algorytmy i struktury danych - laboratoria

N/A
N/A
Protected

Academic year: 2021

Share "Algorytmy i struktury danych - laboratoria"

Copied!
38
0
0

Pełen tekst

(1)

Wydział Matematyki i Nauk Informacyjnych Politechnika Warszawska

Algorytmy

i struktury danych - laboratoria

Anna Maria Radzikowska

(2)

Spis treści

1 Stosy i kolejki 7

1.1 Stosy . . . . 7

1.2 Kolejki . . . . 8

1.3 Zadania . . . . 8

2 Sortowanie 11 2.1 Sortowanie przez scalanie MergeSort . . . . 11

2.2 Sortowanie szybkie . . . . 12

2.3 Zadania . . . . 13

3 Selekcja 15 3.1 Algorytm Hadiana–Sobela . . . . 15

3.2 Algorytm Hoare’a . . . . 17

3.3 Zadania . . . . 18

4 Kopce i kolejki priorytetowe 19 4.1 Kopce . . . . 19

4.2 Kolejki priorytetowe . . . . 21

4.3 Zadania . . . . 22

5 Słowniki 23 5.1 Reprezentacje listowe . . . . 23

5.2 Drzewa poszukiwań binarnych BST . . . . 24

5.3 Zadania . . . . 26

6 Haszowanie 29 6.1 Haszowanie łańcuchowe . . . . 29

6.2 Haszowanie rozproszone . . . . 30

6.3 Haszowanie otwarte . . . . 30

6.4 Zadania . . . . 31 3

(3)

4 SPIS TREŚCI

7 Algorytmy grafowe 33

7.1 Metody przeszukiwania grafów . . . . 33

7.2 Najkrótsze ścieżki w grafie . . . . 34

7.3 Znajdowanie cykli Hamiltona . . . . 35

7.4 Zadania . . . . 35

8 Podsumowanie 37 8.1 Zadania . . . . 37

(4)

Wstęp

Niniejsze opracowanie stanowi materiał omawiany na zajęciach laboratoryj- nych z przedmiotu Algorytmy i Struktury Danych prowadzonych przez au- torkę dla studentów drugiego roku kierunku Matematyki na Wydziale Ma- tematyki i Nauk Informacyjnych Politechniki Warszawskiej. Zajęcia labora- toryjne, w wymiarze 15 godzin w semestrze, odbywają się co 2 tygodnie po 2 godziny na każde zajęcia. Ostatnie, ósme zajęcia, poświęcone są podsumo- waniu materiału, zaliczeniu zajęć i ewentualnym poprawkom. Przedmiotem zajęć jest implementacja w języku C++ lub C# algorytmów omawianych w trakcie wykładów i ćwiczeń. Celem tych zajęć jest zdobycie praktycznych umiejętności wykorzystania wiedzy zdobytej na wykładach i ćwiczeniach.

Każda z 8 części niniejszego opracowania odpowiada kolejnym zajęciom la- boratoryjnym. W części wstępnej przypomniano podstawowy materiał oma- wiany na wykładzie lub ćwiczeniach, niezbędny w trakcie zajęć. Następnie przedstawiono przykładowe zadania implementacyjne będące przedmiotem zajęć.

Celem niniejszego opracowania jest ułatwienie studentom przygotowań do zajęć laboratoryjnych oraz stworzenie możliwości głębszego zrozumienia i przyswojenia materiału z zakresu kursu z Algorytmów i Struktur Danych oraz nabycie umiejętności praktyczego wykorzystania nabytej wiedzy.

5

(5)

6 SPIS TREŚCI

(6)

Laboratorium nr 1

Stosy i kolejki

Niniejsze zajęcia poświęcone są implementacji struktur stosowych i kolejko- wych zarówno w realizacji tablicowej, jak i listowej.

1.1 Stosy

Stosem nazywamy skończony ciąg elementów tego samego typu zorganizo- wany według zasady LIFO (ang. Last In First Out ).

Standardowymi operacjami stosowymi są:

• InitStack (s) : inicjalizacja pustego stosu

• Push(s, x) : dodanie elementu x do stosu s; adres tego elementu jest nowym wierzchołkiem stosu

• Pop(x) : zdjęcie wierzchołka stosu s; jest to funkcja, która zwraca zdej- mowany element, a nowym wierzchołkiem stosu jest adres poprzednio wstawionego elementu

• Top(s) : odczyt wierzchołka stosu; jest to funkcja, która zwraca ten element i nie zmienia struktury stosu

• Empty(s) : sprawdzenie, czy stos s jest pusty; jest to funkcja logiczna, która zwraca True, jeśli stos s jest pusty, False w.p.p. Funkcja nie zmienia struktury stosu.

Najpopularniejsze reprezentacje stosów:

• tablicowa : stos reprezentujemy parą (table, topElem), gdzie table jest N –elementową tablicą jednowymiarową, zaś topElem jest liczbą cał- kowitą (wskaźnikiem wierzchołka stosu). Procedura push wstawia ele- ment na pozycję topElem+1, natomiast procedura pop usuwa ostatni zapełniony element tablicy (zmniejsza o 1 wartość zmiennej topElem).

7

(7)

8 LABORATORIUM NR 1. STOSY I KOLEJKI

• listowa : stos reprezentujemy listą s (wskaźnik początku listy). Proce- dura push wstawia element na początek listy, zaś pop usuwa pierwszy jej element. Adres pierwszego elementu listy jest odpowiednio modyfi- kowany.

1.2 Kolejki

Kolejka jest skończonym ciągiem elementów tego samego typu zorganizo- wanym według zasady FIFO (ang. First In First Out ). Jest to struktura dynamiczna, z której usuwany może być tylko najwcześniej wstawiony ele- ment. W kolejce mamy zazwyczaj dostęp do dwóch jej elementów: pierwszego (najwcześniej wstawionego) i ostatniego (najpóźniej wstawionego).

Standardowe operacje kolejkowe:

• InitQueue(Q) : inicjalizacja pustej kolejki

• EnQueue(Q, x) : wstawienie elementu x do kolejki Q

• DeQueue(Q) : usuwanie pierwszego elementu z kolejki; jest to funkcja, która zwraca usuwany element

• Empty(Q) : sprawdzanie, czy kolejka Q jest pusta; jest to funkcja lo- giczna, która zwraca True, jeśli kolejka jest pusta i False w przeciw- nym przypadku

• Front (Q) : odczyt pierwszego elementu kolejki Q; jest to funkcja, która zwraca ten element jednocześnie nie zmieniając struktury kolejki.

Najpopularniejsze reprezentacje kolejki to

• reprezentacja tablicowa: kolejka realizowana jest jednowymiarową ta- blicą K[1..N ] wraz z dwoma indeksami, first i last, odpowiadającymi początkowemu i końcowemu elementowi kolejki.

• listowa: kolejka realizowana jest listą jednokierunkową wraz z dwoma wskaźnikami, first i last (są to wskaźniki na pierwszy i ostatni element listy).

1.3 Zadania

1. Zaimplementować stos liczb całkowitych przy realizacji listowej. Opra- cować algorytm, który w oparciu o podstawowe operacje stosowe od- wróci porządek elementów na stosie.

(8)

1.3. ZADANIA 9 2. Zaimplementować stos liczb całkowitych przy realizacji tablicowej. Opra-

cować algorytm scalający dwa uporządkowane rosnąco ciągi A i B liczb całkowitych umieszczone odpowiednio na stosach stosA i stosB. Ciąg wynikowy umieścić na stosie stosC.

3. Zaimplementować kolejkę liczb rzeczywistych przy realizacji tablicowej.

4. Zaimpementować kolejkę napisów (ciągi cyfr, dużych i małych liter) przy realizacji listowej. Opracować algorytm, który nie zmieniając struk- tury kolejki wyszukuje w tej kolejce zadany element.

(9)

10 LABORATORIUM NR 1. STOSY I KOLEJKI

(10)

Laboratorium nr 2

Sortowanie

Przedmiotem zajęć jest implemetacja wybranych algorytmów sortowania.

Rozważane będą ciągi (Ai)ni=1o elementach typu U , gdzie (U, ), zaś  jest porządkiem liniowym.

2.1 Sortowanie przez scalanie MergeSort

Ciąg wejściowy zapisany jest w n–elementowej tablicy jednowymiarowej A.

W algorytmie wykorzystywana jest procedura Merge scalająca dwa już upo- rządkowane podciągi Al, . . . , As i As+1, . . . , Arw jeden ciąg uporządkowany zawierający elementu obu scalanych ciągów. W tej procedurze wykorzysta- na jest pomocnicza tablica B, w której zapisywane są kolejne elementy już scalonego ciągu. Po scaleniu obu podciągów kolejne elementy tablicy B są kopiowane do tablicy A.

Algorytm 2.1: Merge 1 MergeSort (l, s, r : int);

2 var i, j : int;

3 begin

3 j := s + 1; i := k := l;

4 while (i6 s) ∧ (j 6 r) do 5 if A[i]  A[j]

6 then B[k] := Ai; i := i+1 7 else B[k] := Aj; j := j+1; fi;

8 k := k+1;

9 od;

11

(11)

12 LABORATORIUM NR 2. SORTOWANIE 10 while i6 s do B[k] := Ai; i := i+1; k := k+1 od;

11 while j6 r do B[k] := A[j]; j := j+1; k := k+1 od;

12 for i := l to r do A[i] := B[i] od;

13 end Merge;

Algorytm 2.1: MergeSort 1 MergeSort (l, r : int);

2 begin

3 if l = r then exit fi;

4 s:=l+r2 ;

5 MergeSort (l, s);

6 MergeSort (s+1, r);

7 Merge(l, s, r);

8 end MergeSort ;

2.2 Sortowanie szybkie

Elementy n– elementowe ciągu wejściowego zapisane są w tablicy A o n+1 elementach. Przyjmujemy A[n+1] = +∞ (tzw. “wartownik”, element nie mniejszy niż każdy element ciągu).

W algorytmie QuickSort wykorzystywana jest procedura Partition, podzia- łu n–elementowego ciągu wejściowego A na dwa podciągi A0l, . . . , A0j−1 oraz A00j+1, . . . , A00r w ten sposób, że każdy element podciągu A0 jest nie większy od elementu dzielącego x (w wersji oryginalnej x = A1), zaś każdy element podciągu A00 jest nie mniejszy od x Po wyznaczeniu takich podciągów ele- menty A1 i Aj są zamienione miejscami. Teraz element x zajmuje pozycję wyznaczoną przez porządek. Procedura Partition zwraca indeks j.

Algorytm 2.2: QuickSort 1 QuickSort (l, r : int);

2 var i : int;

3 begin 4 x := Al;

5 j:=Partition(A, l, r);

6 if j−1>1 then QuickSort (l, j−1) fi;

7 if r−j>1 then QuickSort (j+1, r) fi;

8 end QuickSort ;

(12)

2.3. ZADANIA 13

2.3 Zadania

1. Zaimplementuj algorytm sortowania przez scalanie MergeSort. Dany- mi algorytmu są ciągi par liczb całkowitych (x, y). Kluczem sortowania jest pierwsza współrzędna pary, a w przypadku dwóch par o tej samej pierwszej współrzędnej, kluczem jest druga współrzędna. Ciągi par mo- gą być

(a) podawane z klawiatury

(b) wczytywane z pliku tekstowego (c) generowane losowo.

2. Zaimplementuj wariant algorytm sortowania szybkiego QuickSort z po- jedyńczą rekursją. Algorytm ma sortować elementy w porządku male- jącym Danymi algorytmu są ciągi par napisów (imię, nazwisko). Klu- czem sortowania jest pole nazwisko, zaś w przypadku par o tej samej wartości tego pola, kluczem jest pole imię.

3. Zaimplementować wariant algorytm sortowania szybkiego QuickSort, w którym podciągi o długości k<10 są porządkowane algorytmem sor- towania przez wstawianie. Danymi algorytmu są łańcuchy znaków ze zbioru liter (małych i dużych) oraz cyfr.

4. Dany jest zbiór studentów pewnego kierunku. Dane studenta stanowią pakiet informacji:

• numer indeksu

• wyniki z 15 zajęć laboratoryjnych AiSD (na każdych zajęciach student otrzymuje 0..5 punktów).

Ocena z zajęć wystawiana jest zgodnie z sumaryczną ilościa zdoby- tych punktów. Zaimplementować algorytm, który w sposób efektywny pozwoli ustalić, które miejsce na liście rankingowej zajmuje student o podanym numerze indeksu. Dane do algorytmu wprowadzane są opcjo- nalnie: albo z klawiatury albo z pliku tekstowego.

(13)

14 LABORATORIUM NR 2. SORTOWANIE

(14)

Laboratorium nr 3

Selekcja

Przedmiotem niniejszych zajęć jest implementacja wybranych algorytmów selekcji omawianych na wykładach i ćwiczeniach.

3.1 Algorytm Hadiana–Sobela

W algorytmie Hadiana–Sobela wykorzystywana jest struktura drzewa tur- niejowego. Przypomnijmy, że drzewem turniejowym jest drzewo binarne o własności:

• elementy uniwersum są zapiane tylko w liściach

• liście są na 2 ostatnich poziomach

• w węzłach wewnętrznych zapisane są adresy liści przegrywających, tj.

adres liścia zawierającego mniejszy klucz spośród maksymalnych klu- czy odpowiednio w lewym i prawym poddrzewie.

Reprezentacja drzewa turniejowego

Drzewo turniejowe reprezentowane jest przy pomocy dwch tablic jednowy- miarowych A[1..n] i B[0..n−1], przy elementy tablicy A odpowiadają roz- ważanemu zbiorowi (elementy uniwersum), w tablicy B zapiane są klucze węzłów wewnętrznych (adresy liści przegrywajcych, indeksy tablicy A), przy czym B[0] jest wartownikiem (B[0] = 0) W strukturze połaczonej B[0], B[1], . . . , B[n−1], A[1], . . . , [n] węzeł B[i] jest ojcem

• B2i] i B[2i+1], jeśli 2i+1 6 n−1

• B[n−1] i A[1], jeśli 2i+1 = n

• A[2i−n+1] i A[2i−n+2], jeśli n+1 6 2i+1 6 2n−1.

Liście i węzły wewnętrzne numerowane są jak w kopcu.

15

(15)

16 LABORATORIUM NR 3. SELEKCJA Poprawianie struktury drzewa turniejowego

Algorytm 3.1: PlayOff 1 PlayOff (n : int; var j, w : int);

2 var j : int;

3 begin 4 j = bj2c;

5 while Bj > 0 do 6 if ABj>Aw 7 then w :=: Bj fi;

7 j := bj2c

8 od

9 end PlayOff ; Budowa turnieju

Algorytm 3.2: Tournament 1 Tournament (n : int) : int;

2 var i, j, w : int;

3 begin

4 for i := 0 to n−1 do 5 Bi := 0

6 od;

7 for i := 1 to n do

8 w := i;

9 j := w+n−1;

10 PlayOff (n, j, w);

11 if j>0 then Bj := w fi

12 od;

13 return(w) 14 end Tournament ; Algorytm selekcji Hadaiana–Sobela

Algorytm 3.3: Algorytm Hadiana–Sobela 1 HS_Selection(n, k : int) : U ;

2 var i, j : int;

3 begin

4 w :=Tournament (n−k+2);

(16)

3.2. ALGORYTM HOARE’A 17 5 for i := n−k+2 to n do

6 Aw := Ai; 7 j := w+n−k+1;

8 PlayOff (n−k+2, j, w);

9 od;

10 j := bnk+1+w

2 c;

11 w :=: Bj;

12 PlayOff (n−k+2, j, w);

13 return(Aw);

14 end HS_Selection;

3.2 Algorytm Hoare’a

Algorytm Hoare’a wykorzystuje ideę podziału ciągu (operacja Partition) względem elementu dzielącego x = A1 zastosowaną w algorytmie sortowa- nia szybkiego: dzielimy ciąg A1, . . . , An na dwa podciągi A01, . . . , A0j−1 i A0j+1, . . . , A0n takie, że

• dla każdego i = 1, . . . , j−1, A0x6 x,

• dla każego k = j+1, . . . , n, x 6 A0k.

Po dokonaniu podziału następuje zamiana A1:=: Aj– teraz element dzielący zajmuje pozycję zgodną z porządkiem.

Algorytm 3.4 : Algorytm Hoare’a 1 HoareSelection(A:Ciąg; n, k : int) : U ; 2 var l, r, j : int;

3 begin

4 l := 1; r := n;

5 while l < r do 6 j :=Partition(l, r);

7 if j = r−k+1 then return(Aj) fi;

8 if j < r−k+1 9 then l:=j+1

10 else k:=k−(r−j+1); r := j − 1 fi;

11 od;

12 return(Al);

13 end HoareSelection;

(17)

18 LABORATORIUM NR 3. SELEKCJA

3.3 Zadania

1. Zaimplementować algorytm Hadiana–Sobela wyszukania k–tego co do wielkości elementu w n–elementowym zbiorze liczb całkowitych repre- zentowanym 1–wymiarową tablicą nieuporządkowaną.

2. Zaimplementować algorytm Hoare’a wyszukania mediany w n–elementowym zbiorze S, którego elementy stanowią pakiety informacji o wynikach ostatniej sesji studentów Twojej grupy:

• numer indeksu studenta

• ocena z analizy matematycznej (AM), algebry (AL), matematyki dyskretnej (MD) i programowania (PR).

Wybór dokonywany jest według średniej z ocen.

3. Zaimplementować algorytm wyszukiwania drugiego co do wielkości ele- mentu ze zbioru n–elementowego A punktów na płaszczyźnie (x1, x2) ∈ R2. Relacja porządku liniowego w R2 określona jest następująco:

(x1, x2) v (y1, y2) ⇔ (x16 y1) ∨ (x1= y1∧ y16 y2).

4. Zaimplementować algorytm wyszukiwania mediany w n–elementowym zbiorze łańcuchów znakowych, opartym na idei algorytmu Hadiana–

Sobela, w którym strukturę drzewa turniejowego zastąpiono strukturą kopca. Dane wejściowe wprowadzane są opcjonalnie albo z klawiatury, albo z pliku tekstowego.

(18)

Laboratorium nr 4

Kopce i kolejki priorytetowe

Zajęcia poświęcone są implementacji kopców i kolejek priorytetowych oraz wybranych algorytmów opartych na tych strukturach.

4.1 Kopce

Kopcem nazywamy drzewo binarne o własności: dla każdego węzła v

• jeśli v↑.left 6= NULL, to v↑.left↑.key<v↑.key

• jeśli v↑.right 6= NULL, to v↑.right↑.key<v↑.key Reprezentacja:

Tablica jednowymiarowa K[1..n] o własności:

• K[1] jest korzeniem kopca

• jeśli 2i 6 n, to K[2i] jest lewym następnikiem K[i]

• jeśli 2i+1 6 n, to K[2i+1] jest prawym następnikiem K[i].

Poprawianie struktury kopca

Warunek Kopiec(i, j):

(2i 6 j =⇒ K[2i] ≤ K[i]) ∧ (2i+1 6 j =⇒ K[2i + 1] ≤ K[i]).

Nagłówek: Heapify (l, r)

Dane: K[1..n] spełnia warunek Kopiec(i, r) dla i = l+1, l+2, . . . , r.

Wynik: K[1..n] spełnia warunek Kopiec(i, r) dla i = l, l+1, . . . , r.

19

(19)

20 LABORATORIUM NR 4. KOPCE I KOLEJKI PRIORYTETOWE Algorytm 3.1: Heapify

1 Heapify (l, r : int);

2 var i, j : int;

3 begin

4 j := l; k := 2j; x := Aj; 5 while k6 r do;

6 if k+16 r then

7 if K[k] < K[k + 1] then k := k+1 fi fi;

8 if x < Ak

9 then K[j] := K[k]; j := k; k := 2j 10 else k := r+1 fi;

11 od;

12 K[j] := x 13 end Heapify ;

Budowa kopca

Dane: Tablica K[1..n] elementów typu U . Wynik: Tablica K[1..m] reprezentująca kopiec.

Algorytm 3.2:BuildHeap 1 BuildHeap(n : int);

2 var i : int;

3 begin

4 for i := bn2c downto 1 do 5 Heapify (i, n);

6 od

7 end BuildHeap;

Wstawianie do kopca

Dane: Kopiec K o n > 0 elementach oraz x ∈ U . Wynik: Kopiec K o n+1 elementach z elementem x.

(20)

4.2. KOLEJKI PRIORYTETOWE 21 Algorytm 3.3: InsertHeap

1 InsertHeap(n : int; x : U );

2 begin

3 K[n + 1] := x;

4 i := n+1; j := b2ic;

5 while j>0 do

6 if K[j]> x then j := 0 fi;

7 K[i] := K[j];

8 i := j; j := b2jc;

9 od;

10 K[i] := x 5 end InsertHeap;

Usuwanie elementu maksymalnego Dane: tablica K[1..n] reprezentująca kopiec.

Wynik: tablica K0[1..n−1] reprezentująca kopiec po usunięciu elementu ko- rzenia kopca wejściowego.

Algorytm 3.4: DeleteMax 1 DeleteMax (n : int);

2 begin

3 K[1] := K[n]; n := n−1;

4 Heapify (1, n) 5 end DeleteMax ;

4.2 Kolejki priorytetowe

Kolejką priorytetową nazywamy strukturę danych zbioru A ⊆ U , gdzie (U,6 ), umożliwiającą wykonanie następujących operacji podstawowych:

• wstawienie elementu do kolejki

• dostęp do elementu o najwyższym priorytecie

• usunięcie elementu o najwyższym priorytecie.

Typowe realizacje:

• kopiec

• lista jednokierunkowa

• tablica cykliczna.

(21)

22 LABORATORIUM NR 4. KOPCE I KOLEJKI PRIORYTETOWE

4.3 Zadania

1. Zaimplementować strukturę kopca liczb rzeczywistych reprezentowane- go 1–wymiarową tablicą K wraz z operacją Change(i, x) ::= K[i] := x.

2. Zaimplementować algorytm wyznaczenia k–tego co do wielkości ele- mentu ze zbioru n–elementowego liczb całkowitych przy wykorzystaniu struktury kopca.

3. Zaimplementować kolejkę priorytetową realizowaną przy pomocy listy jednokierunkowej. Elementami kolejki są pakiety danych o wynikach studentów uzyskanych na laboratorium z AiSD postaci:

• numer indeksy studenta

• wyniki z 7 laboratoriów.

Zakładamy, że na poszczególnych zajęciach każdy student uzyskuje o, 1, 2 albo 3 punkty. Priorytetem jest suma punktów uzyskanych w trak- cie wszystkich 7 zajęć.

4. Zaimplementować kolejkę priorytetową realizowaną przy pomocy kop- ca zupełnego reprezentowanego 1–wymiarową tablicą. Elementami ko- lejki są wektory w R2: pary punktów ((x1, y1), (x2, y2)), gdzie (x1, y1) jest początkiem wektora, (x2, y2) jego końcem. Priorytetem jest dłu- gość wektora.

5. Zaimplementować strukturę kopca zupełnego rozszerzonego w taki spo- sób, aby w czasie Θ(lg n) możliwe było wykonanie operacji CountMin ::= podaj aktualną liczbę elementów minimalnych w kopcu.

Wskazówka: Dla każdego elementu kopca dodaj dodatkowy atrybut count – liczba elementów w podkopcu równych elementowi w węźle. W trakcie modyfikacji struktury kopca należy stosownie modyfikować ten atrybut.

(22)

Laboratorium nr 5

Słowniki

Słownikiem nazywany strukturę danych umożliwiającą wykonanie następu- jących operacji na n–elementowym zbiorze A ⊆ U , gdzie (U,6), zaś 6 jest porządkiem liniowym:

• Construct (A) : A := ∅

• Insert (A, x) : A := A ∪ {x}

• Delete(A, x) : A := A \ {x}

• Access(A, x) : wyznacz adres elementu x w strukturze A (jeśli x ∈ A, wpp funkcja zwraca NULL)

• Member (A, x) : czy x jest w strukturze A?

Reprezentacje:

• listy

• drzewa.

5.1 Reprezentacje listowe

Lista jest strukturą dynamiczną reprezentującą skończone ciągi elementów tego samego typu. Typowymi elementami listy są pary (elem,next ), gdzie elem to element listy (z pewnej rozważanej dziedziny), zaś next to adres następnego elementu listy. Listy zazwyczaj implementuje się przy pomocy zmiennych wskaźnikowych (choć możliwe są też reprezentacje tablicowe).

Warianty rozwiązań listowych

Wyróżniamy 4 podstawowe warianty rozwiązań listowych:

• podstawowy B : wstawiany element jest dołączony na koniec listy, a wyszukiwanie elementu nie zmienia jej struktury

23

(23)

24 LABORATORIUM NR 5. SŁOWNIKI

• przenieś w przód MoveToFront : wstawiany element jest zawsze umiesz- czany na początku listy, podobnie element wyszukiwany

• przesuń w przód Transpose : element wstawiany jest umieszczany na przedostatniej pozycji w liście, element wyszukiwany jest przesuwany o 1 pozycję do przodu listy

• licznik częstości FrequencyCounter : z każdym elementem list zwią- zany jest tzw. licznik częstości dostępu (ilość dostępów do elementu), lista jest posortowana względem tych liczników.

5.2 Drzewa poszukiwań binarnych BST

Drzewem poszukiwań binarnych nazywamy drzewo binarne t o własności: dla każdego węzła v tego drzewa zachodzi warunek:

• jeśli istnieje lewy następnik v, to jego klucz jest nie większy od klucza węzła v

• jeśli istnieje prawy następnik v, to jego klucz jest nie mniejszy od klucza węzła v

Podstawowe operacje:

• inicjalizacja drzewa

• wstawienie węzła do drzewa

• usunięcie węzła z drzewa

• wyszukanie klucza w drzewie.

Reprezentacja:

struct tree=↑node node=record

key : Data;

left : tree;

right : tree;

end;

Podstawowe operacje

Algorytm 4.1 ustala adres klucza x w drzewie t, a jeśli brak tego klucza w drzewie, zwraca NULL. Dodatkowo algorytm ustala adres ojca węzła o kluczu x (parametr prev ), o ile x występuje w drzewie i nie jest korzeniem, w przeciwnym przypadku wynikową wartością parametru prev jest NULL.

(24)

5.2. DRZEWA POSZUKIWAŃ BINARNYCH BST 25 Algorytm 4.1: Wyszukanie adresu klucza w drzewie BST

1 Access(t : tree; var prev : tree; x : Data) : tree;

2 begin

3 prev :=NULL;

4 while t 6= NULL do

5 if t↑.key = x then return(t) fi;

6 prev := t;

7 if t↑.key < x then t := t↑.right else t := t↑.left fi

8 od;

9 return(NULL) 10 end Access;

Algorytm 4.2: Wstawienie elementu do drzewa BST 1 Insert (var t : tree, x : Data);

2 var v, prev : tree; cont : Bool;

3 begin

4 v :=Access(t, prev, x);

5 if v 6= NULL then exit fi;

6 new(v);

7 ↑.left := v↑.it right :=NULL; v↑.key := x;

8 if prev =NULL then t := v else

9 if prev ↑.key<x then prev ↑.right := v else prev ↑.right := v fi

10 fi

11 end Insert ;

W algorytmie 4.3 usuwania klucza z drzewa BST rozważane są w istocie 3 następujące przypadki:

(P1) klucz znajduje się w liściu – następuje “obcięcie” tego liścia

(P2) klucz znajduje się w węźle v, który ma tylko 1 następnik (lewy bądź prawy) – następuje przełączenie wskaźnika w ojcu tego węzła do tego następnika

(P3) klucz znajduje się w węźle v, który ma dokładnie 2 następniki – wyszu- kujemy maksymalny klucz w jego lewym poddrzewie (lub minimalny klucz w jego prawym poddrzewie), przenosimy ów klucz do węzła v, oraz usuwamy węzeł, z którego przenieśliśmy klucz

Algorytm AccessMax jest pomocny w przypadku (P3). Funkcja ta zwraca adres węzła o maksymalnym kluczu w drzewie v, a dodatkowo nadaje para- metrowi prev watość adresu ojca tego węzła.

(25)

26 LABORATORIUM NR 5. SŁOWNIKI Algorytm 4.3: Usuwanie elementu z drzewa BST

1 Delete(var t : tree, x : Data);

2 var v, prev : tree; cont : Bool;

3 begin

3 v :=Access(t, prev, x);

4 if v=NULL then exit fi;

5 if v↑.left=NULL

6 then do prev dowiąż prawy następnik v else 7 if v↑.left=NULL

8 then do prev dowiąż lewy następnik v else 9 w :=AccessMaxMin(v↑.left, prev);

10 v↑.key := w↑.key;

11 prev↑.right := w↑.left;

12 v := w;

13 fi

14 fi;

15 kill (v);

16 end Delete;

5.3 Zadania

1. Zaimplementować strukturę słownikową przy pomocy drzewa poszuki- wań binarnych. Kluczami węzłów drzewa są liczby całkowite. Struktura winna gwarantować efektywne wykonanie następujących operacji:

(a) wstawienie elementu x do zbioru A (b) usunięcie elementu x ze zbioru A (c) wyszukanie elementu x w zbiorze A

(d) określenie, którym co do wielkości elementem w zbiorze A jest x (o ile x ∈ A)

(e) wyznaczenie k–tego co wielkości elementu zbioru A, k6 n.

2. Zaimplementować strukturę słownikową przy pomocy drzewa poszu- kiwań binarnych. Kluczami węzłów drzewa są napisy (ciągi znaków).

Struktura winna gwarantować efektywne wykonanie następujących operacji:

(a) wstawienie elementu x do zbioru A (b) usunięcie elementu x ze zbioru A

(26)

5.3. ZADANIA 27 (c) wyszukanie elementu x w zbiorze A

(d) wyznaczanie sumy elementów w liściach drzewa (e) wyznaczanie głębokości węzła z kluczem x.

3. Zaimplementować strukturę słownikową przy pomocy drzewa poszuki- wań binarnych. Kluczami węzłów drzewa są liczby całkowite. Struktura winna gwarantować efektywne wykonanie następujących operacji:

(a) wstawienie elementu x do zbioru A (b) usunięcie elementu x ze zbioru A

(c) wyszukanie elementu x w zbiorze A

(d) wyznaczenie wszystkich elementów podzbioru {x ∈ A : a6 x 6 b}, gdzie A jest zbiorem reprezentowanym rozważaną strukturą, zaś a, b ∈ Z są parametrami operacji.

4. Zaimplementować strukturę drzewa BST o kluczach całkowitych tak, by każdy wstawiany węzeł był umieszczany w korzeniu. Zastosować odpowiednie rotacje LL lub RR.

5. Dany jest zbiór Dictionary haseł (rzeczowników) w języku angielskim oraz zbiór Słownik haseł w języku polskim. Hasłem jest łańcuch liter

’a’,....’z’. Każde hasło w języku polskim może mieć kilka tłumaczeń na język angielski i odwrotnie: każde hasło w języku angielskim może od- powiadać kilku tłumaczeniom na język polski. Wykorzystując struktu- ry listowe oraz drzewa BST zaimplementować słownik angielsko–polski i polsko–angielski. Hasła (wraz z ich tłumaczeniami) są wczytywane z pliku tekstowego.

(27)

28 LABORATORIUM NR 5. SŁOWNIKI

(28)

Laboratorium nr 6

Haszowanie

Niniejsze zajęcia poświęcone są implementacji wybranych metod haszowania.

Dane jest uniwersum U , w którym nie określono porządku liniowego. Za- daniem jest reprezentacja zbiorów A ⊆ U wraz z operacją Search(A, x) – wyszukania x w zbiorze A. Jeśli x ∈ A, to otrzymujemy odpowiedź True, w przeciwnym przypadku False i dodatkowo element jest wstawiany do zbioru A.

Zakładamy, że dana jest liczba M ∈ N oraz funkcja haszująca h : U → {0, . . . , M −1}. Elementy zbioru A reprezentować będziemy tablicy H[0..M −1].

Dla x, y ∈ U , jeśli h(x) = h(y), to mamy do czynienia z kolizją.

6.1 Haszowanie łańcuchowe

Elementami tablicy H są głowy list elementów kolidujących. Można repre- zentować zbiory o liczności większej niż M .

Algorytm 4.1: ChainSearch 1 ChainSearch(x : U ) : Bool;

2 var i : int; p,t : list;

3 begin 4 i := h(x);

5 t := H[i]; p := NULL;

6 while t 6= NULL do

7 if t↑.elem = x then return(true) fi;

8 p := t; t := t↑.next;

9 od;

29

(29)

30 LABORATORIUM NR 6. HASZOWANIE 10 new(t); t↑.elem := x; t↑.next := NULL;

11 if p = NULL then Hi := t else p↑.next := t fi;

12 return(F alse) 13 end ChainSearch;

6.2 Haszowanie rozproszone

Elementy zbioru A wraz z listą elementów kolidujących są wstawiane do tablicy H. Ściślej: H[i] jest parą (el,idx ), gdzie wartością pola el są elementy zbiory A, zaś idx jest indeksem w tablicy H gdzie umieszczono następny element z listy kolizji.

Algorytm 4.1: ScatteringSearch 1 ScatteringSearch(x : U ) : Bool;

2 var i : int;

3 begin 4 i := h(x);

5 while H[i].elem 6= 0 do 6 while i 6= M do

7 if H[i].elem = x then return(T rue) fi;

8 i := H[i].next;

9 od;

10 while Hlast.elem 6= 0 do 11 last := last − 1;

12 if last = −1 then ERROR fi;

13 od;

14 H[i].next := last ; i := last ;

15 od;

16 H[i].elem := x; H[i].next := M ; return(F alse) 17 end ScatteringSearch;

6.3 Haszowanie otwarte

Elementami tablicy H są jedynie elementy zbiory A, jeśli występuje koli- zja, element wstawiany jest w pierwsze “od dołu” (w kierunku malejących indeksów) wolne pole tablicy H.

(30)

6.4. ZADANIA 31 Algorytm 4.1: OpenSearch

1 OpenSearch(x : U ) : Bool;

2 var i : int;

3 begin 4 i := h(x);

5 while H[i] 6= 0 do

6 if H[i] = x then return(T rue) fi;

7 i := i−1;

8 if i<0 then i := M −1 fi;

9 od;

10 if n = M −1 then ERROR fi;

11 n := b+1; H[i] := x; return(F alse) 12 end OpenSearch;

6.4 Zadania

1. Zaimplementować metodę adresowania łańcuchowego dla zbiorów liczb całkowitych. Jako funkcje haszujące przyjąć funkcje postaci h(x) = x mod M , gdzie M jest rozmiarem tablicy haszującej.

2. Zaimplementować metodę podwójnego adresowania otwartego dla zbio- rów liczb całkowitych. Jako funkcje haszujące przyjąć funkcje postaci h(x) = bM · frac(α · x)c, gdzie M jest rozmiarem tablicy haszującej, α =

5−1

2 , zaś frac(y) jest funkcją zwracającą część ułamkową argu- mentu y.

3. Zaimplementować metodę adresowania rozproszonego dla zbiorów liczb całkowitych. Jako funkcje haszujące przyjąć funkcje postaci h(x) = (ax mod b) mod M , gdzie a =

5−1

2 gdzie M jest rozmiarem tablicy haszującej, zaś a i b liczbami pierwszymi.

(31)

32 LABORATORIUM NR 6. HASZOWANIE

(32)

Laboratorium nr 7

Algorytmy grafowe

Niniejsze zajęcia poświęcone są implementacji grafu, podstawowym meto- dom jego obchodzenia oraz implementacji wybranych algorytmów grafowych.

Przypomnijmy parę faktów omówionych na wykładzie.

Grafem nazywamy parę (V, E), gdzie E jest zbiorem wierzchołków, zaś E jest zbiorem krawędzi.

Reprezentacja grafu:

1. macierz sąsiedztwa: zerojedynkowa tablica dwywymiarowa G[1..n, 1..n],

|V | = n, gdzie G[i, j] = 1 jeśli (i, j) ∈ E, wpp G[i, j] = 0

2. listy incydencji: tablica o n elementach, |V | = n, której elementami są listy wierzchołków incydentnych, tzn. G[i] jest listą wierzchołków, do których prowadzi krawędź z wierzchołka i.

7.1 Metody przeszukiwania grafów

Algorytm 7.1: Przeszukiwania grafu w głąb 1 DFS (v : int; G : Graph);

2 begin

3 Visited (v):=true;

4 InVertex (v);

5 for all w ∈ Neighbours(v) do

6 if ¬Visited (w) then DFS (w,G) fi;

7 od;

8 end DFS ;

33

(33)

34 LABORATORIUM NR 7. ALGORYTMY GRAFOWE Algorytm 7.1: Przeszukiwania grafu wszerz

1 BFS (v : int; G : Graph);

2 begin

3 InitQueue;

4 EnQueue(v);

5 Visited (v):=true;

6 while Nonempty do 7 v := DeQueue;

8 InVertex (v);

9 for all w ∈ Neighbours(w) do 10 if ¬Visited (w)

11 then EnQueue(w); Visited (w):=true; fi;

12 od;

13 od;

14 end BFS ;

7.2 Najkrótsze ścieżki w grafie

Dany jest graf skierowany (G = (V, E) oraz funkcja l : E → [0, +∞] przypi- sująca każdej jego krawędzi jej nieujemną wagę. Niech s będzie wyróżnionym węzłem grafu zwanym źródłem

Problem: dla każdego wierzchołka v ∈ V wyznacz najkrótsze ścieżki ze źró- dła s.

Idea metody:

• Zbiór wierzchołków V dzielimy na zbiór wierzchołków już odwiedzonych S i jeszcze nieodwiedzonych N S. Początkowo S = {s}.

• Algorytm przebiega w n − 1 fazach, |V | = n. W każdej fazie wyzna- czany jest taki wierzchołek w ∈ N S, którego odległość od s, spośród wszystkich wierzchołków z N S, jest minimalna. Taka najkrótsza ścież- ka od s do w prowadzi jedynie przez wierzchołki ze zbioru S (ścieżka specjalna). Wierzchołek w jest następnie dołączony do zbioru S.

Algorytm Dijkstry 1 begin

2 for all v ∈ V do Dv := l(s, v) od;

3 S := {s};

(34)

7.3. ZNAJDOWANIE CYKLI HAMILTONA 35 4 while S 6= V do

5 dist := +∞;

6 for all w ∈ V \ S do

7 if Dw < dist then v := w; dist := Dw fi;

8 od;

9 S := S ∪ {v};

10 for all w ∈ V \ S do

11 Dw := min(Dw, Dv+ l(v, w));

12 od;

13 od;

14 end;

7.3 Znajdowanie cykli Hamiltona

Algorytm Robertsa–Floresa 1 HamiltonCycle(v : int) : Bool;

2 begin

3 Visited (v) := true;

4 used := used +1;

5 for each w ∈ Neighbours(v) do 6 if w = start then

7 if used = |V | then H[used ] := v; return(True) fi fi;

8 if ¬Visited (w) then

9 if HamiltonCycle(w) then 10 H[used ] := v; return(true); fi;

11 fi;

12 od;

13 Visited (v) := false;

14 used := used −1;

15 return(False) 16 end HamiltonCycle;

7.4 Zadania

1. Zaimplementować algorytm wyznaczania spójnych składowych grafu.

Dane wprowadzane są opcjonalnie

• z pliku tekstowego

• z klawiatury.

(35)

36 LABORATORIUM NR 7. ALGORYTMY GRAFOWE 2. Rozważmy sieć połączej kolejowych w pewnym województwie. Węzła- mi sieci są nazwy miast, krawędziami – połączenia kolejowe pociągami Intercity, zaś wagi tych krawędzi to czas przejazdu pociągiem Interci- ty pomiędzy dwoma odpowiednimi miastami. Wykorzystując algorytm Dijkstry zaimplementować algorytm wyznaczania najszybszych połą- czeń między miastem wojewódzkim a poszczególnymi miejscowościami w tym województwie. Dane wprowadzane są opcjonalnie

• z pliku tekstowego

• z klawiatury.

3. Dla podanego grafu G zaimplementować algorytm wyznaczający cykl Hamiltona w grafie (o ile istnieje). Graf wprowadzany jest

• z klawiatury

• z pliku tekstowego.

4. Zaimplementuj algorytm, który obchodzi wszerz dane drzewo binarne.

(36)

Laboratorium nr 8

Podsumowanie

8.1 Zadania

1. Zaimplementować algorytm, który w czasie Θ(n lg n) wyznacza me- dianę dwóch uporządkowanych rosnąco ciągów (Ai)ni=1 i (Bi)ni=1 o 2n różnych elementach. Ciągi wprowadzane są opcjonalnie z klawiatury lub z pliku tekstowego.

2. Zaimplementować iteracyjną wersję algorytmu rozwiązującego problem n wież Hanoi. Wykorzystać strukturę stosu.

3. Zaimplementuj strukturę słownika opartą na drzewach Patricia. Klu- czami węzłów są liczby całkowite.

4. Dane są dwa n–elementowe zbiory liczb całkowitych A i B reprezemto- wane drzewami BST. Zaimplementuj algorytm, który wyznacza prze- cięcie tych zbiorów.

37

(37)

38 LABORATORIUM NR 8. PODSUMOWANIE

(38)

Literatura

[1] A. V. Aho, J. E. Hopcroft, J. D. Ullman. Projektowanie i analiza algo- rytmów, Wydawnictwo Helion, Gliwice, 2003.

[2] A. V. Aho, J. E. Hopcroft, J, D. Ullman. Algorytmy i struktury danych, Wydawnictwo Helion, Gliwice, 2003.

[3] L. Banachowski, A, Kreczmar. Elementy analizy algorytmów, Wydaw- nictwo Naukowo–Techniczne, Warszawa, 1982

[4] L. Banachowski, A. Kreczmar, W. Rytter. Analiza algorytmów i struktur danych, Wydawnictwo Naukowo–Techniczne, Warszawa, 1987.

[5] A. Dańko, T. L. Le, G. Mirkowska, P. Rembelski, A. Smyk, M. Sy- dow. Algorytmy i struktury Danych – Zadania, Wydawnictwo PJWSTK, Warszawa, 2006.

[6] L. Banachowski, K. Diks, W. Rytter. (1996). Algorytmy i struktury da- nych, Wydawnictwo Naukowo–Techniczne, Warszawa, 1996.

[7] T. H. Cormen, Ch. E. Leiserson, R. L. Rivest. Wprowadzenie do algoryt- mów i struktur danych, Wydawnictwo Naukowo–Techniczne, Warszawa, 1996.

[8] D. Harel. Rzecz o istocie informatyki, Algorytmika, Wydawnictwo Naukowo–Techniczne, Warszawa, 1992.

[9] D. Knuth. Sztuka programowania. Wydawnictwo Naukowo–Techniczne, Warszawa, 2002.

[10] R. Sedgewick. Algorytmy w C++, Oficyna Wydawnicza READ ME, Warszawa, 1999.

[11] P. Wróblewski. Algorytmy, struktury danych i techniki programowania, Wydawnictwo Helion, Gliwice, 2003

39

Cytaty

Powiązane dokumenty

WYKŁAD 08 Drzewa binarnych poszukiwań Grażyna Mirkowska.. PJWSTK, semestr

Zadanie Do zbioru reprezentowanego przez drzewo D dołączyć element e, o ile nie należy on jeszcze do etykiet drzewa D.... Zastosowanie: wyszukiwanie

(3) Jeżeli tak otrzymane drzewo nie jest częściowo uporządkowane, to przechodząc wzdłuż drogi od liścia x do korzenia, poprawić etykiety zamieniając etykietę ojca z

Jeśli element e należy do kolejki q, to po skończonej liczbie usunięć kolejnych elementów minimalnych.. dotrę do tego

takie drzewo &lt;V, T&gt; rozpinające grafu G, że suma kosztów jego krawędzi  eT c (e) jest najmniejsza.. Mirkowska, ASD_12 Algorytmy na

Niech będzie tekst 100000 znakowy, w którym występują tylko litery a,b,c,d,e,f i a-45tys razy, b-13tys., c-12tys.,.. d-16tys., e -

Powiemy, że problem jest rozstrzygalny, jeśli istnieje algorytm, który dla dowolnych danych x po skończonej liczbie kroków daje rozwiązanie problemu. W przeciwnym

Dowód przez indukcję ze względu na liczbę wywołań rekurencyjnych funkcji min_max.. Dla jednego tylko wywołania