You are on page 1of 19

IDZ DO

PRZYKADOWY ROZDZIA
SPIS TRECI

KATALOG KSIEK
KATALOG ONLINE
ZAMW DRUKOWANY KATALOG

TWJ KOSZYK
DODAJ DO KOSZYKA

CENNIK I INFORMACJE
ZAMW INFORMACJE
O NOWOCIACH
ZAMW CENNIK

CZYTELNIA
FRAGMENTY KSIEK ONLINE

Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl

Algorytmy, struktury danych


i techniki programowania.
Wydanie III
Autor: Piotr Wrblewski
ISBN: 83-7361-101-0
Format: B5, stron: 360
Algorytmika stanowi ga wiedzy, ktra w cigu ostatnich kilkudziesiciu lat
dostarczya wielu efektywnych narzdzi wspomagajcych rozwizywanie rnorodnych
problemw za pomoc komputera. Teoria algorytmw i struktur danych jest jednym
z podstawowych przedmiotw wykadanych na studiach informatycznych i pokrewnych.
Ksika, ktrej trzecie i poprawione wydanie trzymasz w rku, od wielu lat stanowi
podstawowy podrcznik z dziedziny algorytmiki. Rni si od klasycznych
podrcznikw akademickich: skierowana jest nie tylko do adeptw informatyki.
Dziki naciskowi na praktyczn stron prezentowanych zagadnie powinna
zainteresowa take osoby programujce hobbystycznie, jak rwnie tych wszystkich,
dla ktrych programowanie jest dziaalnoci wan, lecz nie podstawow w pracy
zawodowej. Jest to nowoczesny podrcznik dla wszystkich, ktrzy w codziennej pracy
programistycznej odczuwaj potrzeb szybkiego odszukania pewnych informacji
z dziedziny algorytmiki w celu zastosowania ich w swoich programach.
W ksice opisano m.in.:
Techniki rekurencyjne: co to jest rekurencja i jak j stosowa w praktyce?
Sortowanie danych: najpopularniejsze procedury sortujce.
Struktury danych: listy, kolejki, zbiory i drzewa w ujciu praktycznym.
Derekursywacja: jak zmieni program rekurencyjny (czasami bardzo
czasochonny) na wersj iteracyjn?
Algorytmy przeszukiwania: przeszukiwanie liniowe, binarne i transformacja
liniowa (ang. hashing).
Przeszukiwanie tekstw: opis najbardziej znanych metod przeszukiwania tekstw
(Boyera i Moore'a, Rabina i Karpa, brute-force, K-M-P).
Zaawansowane techniki programowania: dziel i rzd, programowanie
dynamiczne, algorytmy aroczne (ang. greedy).
Algorytmika grafw: opis jednej z najciekawszych struktur danych
wystpujcych w informatyce.
Sztuczna inteligencja: czy komputery mog myle?
Kodowanie i kompresja danych: opis najpopularniejszych metod kodowania
i kompresji danych systemu kryptograficznego z kluczem publicznym
i metody Huffmana
W ksice znajdziesz rwnie liczne przykady i zadania, ktre pomog Ci sprawdzi
swoj wiedz. Kod rdowy znajdziesz na doczonej dyskietce.

Spis treci
Przedmowa...................................................................................... 11
Rozdzia 1. Zanim wystartujemy ........................................................................ 19
1.1. Jak to wczeniej bywao, czyli wyjtki z historii maszyn algorytmicznych..............21
1.2. Jak to si niedawno odbyo, czyli o tym, kto wymyli
metodologi programowania .....................................................................................23
1.3. Proces koncepcji programw .....................................................................................24
1.4. Poziomy abstrakcji opisu i wybr jzyka...................................................................25
1.5. Poprawno algorytmw ............................................................................................27

Rozdzia 2. Rekurencja ...................................................................................... 29


2.1. Definicja rekurencji....................................................................................................29
2.2. Ilustracja pojcia rekurencji .......................................................................................31
2.3. Jak wykonuj si programy rekurencyjne?...................................................................32
2.4. Niebezpieczestwa rekurencji....................................................................................34
2.4.1. Cig Fibonacciego ............................................................................................34
2.4.2. Stack overflow!.................................................................................................36
2.5. Puapek cig dalszy ....................................................................................................37
2.5.1. Std do wiecznoci............................................................................................37
2.5.2. Definicja poprawna, ale... .................................................................................38
2.6. Typy programw rekurencyjnych ..............................................................................39
2.7. Mylenie rekurencyjne ...............................................................................................41
2.7.1. Przykad 1.: Spirala...........................................................................................42
2.7.2. Przykad 2.: Kwadraty parzyste.....................................................................44
2.8. Uwagi praktyczne na temat technik rekurencyjnych .................................................45
2.9. Zadania .......................................................................................................................46
2.9.1. Zadanie 2.1........................................................................................................46
2.9.2. Zadanie 2.2........................................................................................................46
2.9.3. Zadanie 2.3........................................................................................................48
2.9.4. Zadanie 2.4........................................................................................................48
2.9.5. Zadanie 2.5........................................................................................................49
2.10. Rozwizania i wskazwki do zada.........................................................................49
2.10.1. Zadanie 2.1......................................................................................................49
2.10.2. Zadanie 2.2......................................................................................................50
2.10.3. Zadanie 2.3......................................................................................................50
2.10.4. Zadanie 2.4......................................................................................................51
2.10.5. Zadanie 2.5......................................................................................................52

Algorytmy, struktury danych i techniki programowania

Rozdzia 3. Analiza sprawnoci algorytmw ........................................................ 53


3.1. Dobre samopoczucie uytkownika programu ............................................................54
3.2. Przykad 1: Jeszcze raz funkcja silnia... .....................................................................56
3.3. Przykad 2: Zerowanie fragmentu tablicy ..................................................................60
3.4. Przykad 3: Wpadamy w puapk...............................................................................62
3.5. Przykad 4: Rne typy zoonoci obliczeniowej.....................................................63
3.6. Nowe zadanie: uproci obliczenia! ............................................................................66
3.7. Analiza programw rekurencyjnych ...........................................................................66
3.7.1. Terminologia.....................................................................................................67
3.7.2. Ilustracja metody na przykadzie ......................................................................68
3.7.3. Rozkad logarytmiczny .....................................................................................70
3.7.4. Zamiana dziedziny rwnania rekurencyjnego ..................................................71
3.7.5. Funkcja Ackermanna, czyli co dla smakoszy .................................................72
3.8. Zadania .......................................................................................................................73
3.8.1. Zadanie 3.1........................................................................................................73
3.8.2. Zadanie 3.2........................................................................................................74
3.8.3. Zadanie 3.3........................................................................................................74
3.8.4. Zadanie 3.4........................................................................................................74
3.9. Rozwizania i wskazwki do zada...........................................................................75
3.9.1 Zadanie 3.2.........................................................................................................75
3.9.2. Zadanie 3.4........................................................................................................76

Rozdzia 4. Algorytmy sortowania ...................................................................... 77

4.1. Sortowanie przez wstawianie, algorytm klasy O(N2) ................................................78


4.2. Sortowanie bbelkowe, algorytm klasy O(N2)...........................................................80
4.3. Quicksort, algorytm klasy O(N log N).......................................................................82
4.4. Heap Sort sortowanie przez kopcowanie ..............................................................85
4.5. Sortowanie przez scalanie ..........................................................................................88
4.6. Uwagi praktyczne.......................................................................................................90

Rozdzia 5. Struktury danych ............................................................................. 93


5.1. Listy jednokierunkowe...............................................................................................94
5.1.1. Realizacja struktur danych listy jednokierunkowej ..........................................96
5.1.2. Tworzenie listy jednokierunkowej....................................................................97
5.1.3. Listy jednokierunkowe teoria i rzeczywisto................................................106
5.2. Tablicowa implementacja list...................................................................................119
5.2.1. Klasyczna reprezentacja tablicowa .................................................................119
5.2.2. Metoda tablic rwnolegych ...........................................................................121
5.2.3. Listy innych typw .........................................................................................123
5.3. Stos ...........................................................................................................................125
5.3.1. Zasada dziaania stosu.....................................................................................125
5.4. Kolejki FIFO ............................................................................................................129
5.5. Sterty i kolejki priorytetowe.....................................................................................132
5.6. Drzewa i ich reprezentacje .......................................................................................139
5.6.1. Drzewa binarne i wyraenia arytmetyczne .....................................................142
5.7. Uniwersalna struktura sownikowa ..........................................................................147
5.8. Zbiory .......................................................................................................................152
5.9. Zadania .....................................................................................................................155
5.9.1. Zadanie 5.1......................................................................................................155
5.9.2. Zadanie 5.2......................................................................................................155
5.9.3. Zadanie 5.3......................................................................................................155
5.10. Rozwizania zada.................................................................................................155
5.10.1. Zadanie 5.1....................................................................................................155
5.10.2. Zadanie 5.3....................................................................................................156

Spis treci

Rozdzia 6. Derekursywacja i optymalizacja algorytmw ................................... 157


6.1. Jak pracuje kompilator? ...........................................................................................158
6.2. Odrobina formalizmu nie zaszkodzi!..........................................................................160
6.3. Kilka przykadw derekursywacji algorytmw ...........................................................162
6.4. Derekursywacja z wykorzystaniem stosu ................................................................165
6.4.1. Eliminacja zmiennych lokalnych....................................................................166
6.5. Metoda funkcji przeciwnych....................................................................................168
6.6. Klasyczne schematy derekursywacji........................................................................170
6.6.1. Schemat typu while.........................................................................................171
6.6.2. Schemat typu if-else........................................................................................173
6.6.3. Schemat z podwjnym wywoaniem rekurencyjnym .....................................175
6.7. Podsumowanie .........................................................................................................177

Rozdzia 7. Algorytmy przeszukiwania .............................................................. 179


7.1. Przeszukiwanie liniowe............................................................................................179
7.2. Przeszukiwanie binarne............................................................................................180
7.3. Transformacja kluczowa (hashing) ..........................................................................181
7.3.1. W poszukiwaniu funkcji H .............................................................................183
7.3.2. Najbardziej znane funkcje H...........................................................................184
7.3.3. Obsuga konfliktw dostpu ...........................................................................187
7.3.4. Powrt do rde .............................................................................................187
7.3.5. Jeszcze raz tablice!..........................................................................................188
7.3.6. Prbkowanie liniowe ......................................................................................189
7.3.7. Podwjne kluczowanie ...................................................................................191
7.3.8. Zastosowania transformacji kluczowej...........................................................193
7.3.9. Podsumowanie metod transformacji kluczowej ...............................................193

Rozdzia 8. Przeszukiwanie tekstw ................................................................. 195


8.1. Algorytm typu brute-force .......................................................................................195
8.2. Nowe algorytmy poszukiwa...................................................................................197
8.2.1. Algorytm K-M-P.............................................................................................198
8.2.2.Algorytm Boyera i Moorea.............................................................................203
8.2.3. Algorytm Rabina i Karpa................................................................................205

Rozdzia 9. Zaawansowane techniki programowania......................................... 209


9.1. Programowanie typu dziel i zwyciaj .................................................................210
9.1.1. Odszukiwanie minimum i maksimum w tablicy liczb....................................211
9.1.2. Mnoenie macierzy o rozmiarze NN............................................................214
9.1.3. Mnoenie liczb cakowitych ...........................................................................217
9.1.4. Inne znane algorytmy dziel i zwyciaj ......................................................218
9.2. Algorytmy aroczne, czyli przeksi co nadszed ju czas... ............................219
9.2.1. Problem plecakowy, czyli nieatwe jest ycie turysty-piechura ...........................220
9.3. Programowanie dynamiczne ....................................................................................223
9.4. Uwagi bibliograficzne ..............................................................................................227

Rozdzia 10. Elementy algorytmiki grafw .......................................................... 229


10.1. Definicje i pojcia podstawowe .............................................................................230
10.2. Sposoby reprezentacji grafw ................................................................................232
10.3. Podstawowe operacje na grafach ...........................................................................234
10.3.1. Suma grafw .................................................................................................234
10.3.2. Kompozycja grafw......................................................................................234
10.3.3. Potga grafu ..................................................................................................235
10.4. Algorytm Roy-Warshalla .......................................................................................236
10.5. Algorytm Floyda-Warshalla...................................................................................239
10.6. Algorytm Dijkstry ..................................................................................................243

Algorytmy, struktury danych i techniki programowania


10.7. Drzewo rozpinajce minimalne..............................................................................244
10.8. Przeszukiwanie grafw ..........................................................................................245
10.8.1. Strategia w gb .........................................................................................246
10.8.2. Strategia wszerz.........................................................................................247
10.9. Problem waciwego doboru ..................................................................................249
10.10. Podsumowanie .....................................................................................................254

Rozdzia 11.Algorytmy numeryczne.................................................................... 255


11.1. Poszukiwanie miejsc zerowych funkcji .................................................................255
11.2. Iteracyjne obliczanie wartoci funkcji....................................................................257
11.3. Interpolacja funkcji metod Lagrangea ................................................................258
11.4. Rniczkowanie funkcji.........................................................................................260
11.5. Cakowanie funkcji metod Simpsona...................................................................262
11.6. Rozwizywanie ukadw rwna liniowych metod Gaussa ................................263
11.7. Uwagi kocowe......................................................................................................266

Rozdzia 12. Czy komputery mog myle? ........................................................ 267


12.1. Przegld obszarw zainteresowa Sztucznej Inteligencji......................................268
12.1.1. Systemy eksperckie.......................................................................................269
12.1.2. Sieci neuronowe............................................................................................271
12.2. Reprezentacja problemw ......................................................................................272
12.2.1. wiczenie 12.1..............................................................................................274
12.3. Gry dwuosobowe i drzewa gier..............................................................................274
12.4. Algorytm mini-max................................................................................................276

Rozdzia 13. Kodowanie i kompresja danych ...................................................... 281


13.1. Kodowanie danych i arytmetyka duych liczb...........................................................283
13.1.1. Kodowanie symetryczne...............................................................................284
13.1.2. Kodowanie asymetryczne .............................................................................285
13.1.3. Metody prymitywne......................................................................................292
13.1.4. amanie szyfrw...........................................................................................293
13.2. Techniki kompresji danych ....................................................................................294
13.2.1. Kompresja poprzez modelowanie matematyczne.........................................296
13.2.2. Kompresja metod RLE................................................................................297
13.2.3. Kompresja danych metod Huffmana ..........................................................298
13.2.4. Kodowanie LZW ..........................................................................................304
13.2.5. Idea kodowania sownikowego na przykadach ...........................................304
13.2.6. Opis formatu GIF..........................................................................................307

Rozdzia 14. Zadania rne................................................................................ 311


14.1. Teksty zada...........................................................................................................311
14.1.1. Zadanie 14.1..................................................................................................311
14.1.2. Zadanie 14.2..................................................................................................312
14.1.3. Zadanie 14.3..................................................................................................312
14.1.4. Zadanie 14.4..................................................................................................312
14.1.5. Zadanie 14.5..................................................................................................312
14.1.6. Zadanie 14.6..................................................................................................312
14.1.7. Zadanie 14.7..................................................................................................312
14.1.8. Zadanie 14.8..................................................................................................313
14.1.9. Zadanie 14.9..................................................................................................313
14.1.10. Zadanie 14.10..............................................................................................313
14.1.11. Zadanie 14.11..............................................................................................313
14.1.12. Zadanie 14.12..............................................................................................313

Spis treci

9
14.2. Rozwizania ...........................................................................................................313
14.2.1. Zadanie 14.1..................................................................................................313
14.2.2. Zadanie 14.3..................................................................................................314
14.2.3. Zadanie 14.4..................................................................................................315
14.2.4. Zadanie 14.10................................................................................................315
14.2.5. Zadanie 14.12................................................................................................316

Dodatek A Poznaj C++ w pi minut! .............................................................. 319


Dodatek B Systemy obliczeniowe w piguce..................................................... 337
Literatura ...................................................................................... 343
Spis ilustracji ................................................................................ 345
Spis tablic ..................................................................................... 349
Skorowidz...................................................................................... 351

Rozdzia 8.

Przeszukiwanie tekstw
Zanim na dobre zanurzymy si w lektur nowego rozdziau, naley wyjani pewne nieporozumienie, ktre moe towarzyszy jego tytuowi. Ot za tekst bdziemy uwaali
cig znakw w sensie informatycznym. Nie zawsze bdzie to miao cokolwiek wsplnego
z ludzk pisanin! Tekstem bdzie na przykad rwnie cig bitw1, ktry tylko przez
umowno moe by podzielony na rwnej wielkoci porcje, ktrym przyporzdkowano
pewien kod liczbowy2.
Okazuje si wszelako, e przyjcie konwencji dotyczcych interpretacji informacji uatwia
wiele operacji na niej. Dlatego te pozostamy przy oglnikowym stwierdzeniu tekst
wiedzc, e za tym okreleniem moe si kry do sporo znacze.

8.1. Algorytm typu brute-force


Zadaniem, ktre bdziemy usiowali wsplnie rozwiza, jest poszukiwanie wzorca3 w
o dugoci M znakw w tekcie t o dugoci N. Z atwoci moemy zaproponowa
do oczywisty algorytm rozwizujcy to zadanie, bazujc na pomysach symbolicznie przedstawionych na rysunku 8.1.
Rysunek 8.1.
Algorytm typu brute-force przeszukiwania
tekstu

Fragmenty (jeszcze) zgodne

M-1
wzorzec w

1
2
3

Reprezentujcy np. pami ekranu.


Np. ASCII lub dowolny inny.
Ang. pattern matching.

K
0

Z
N-1

i
Badany tekst t

196

Algorytmy, struktury danych i techniki programowania

Zarezerwujmy indeksy  i  do poruszania si odpowiednio we wzorcu i tekcie podczas operacji porwnywania znak po znaku zgodnoci wzorca z tekstem. Zamy, e
w trakcie poszukiwa obszary objte szarym kolorem na rysunku okazay si zgodne.
Po stwierdzeniu tego faktu przesuwamy si zarwno we wzorcu, jak i w tekcie o jedn
pozycj do przodu (;).
C si jednak powinno sta z indeksami  oraz  podczas stwierdzenia niezgodnoci
znakw? W takiej sytuacji cae poszukiwanie koczy si porak, co zmusza nas do
anulowania szarej strefy zgodnoci. Czynimy to poprzez cofnicie si w tekcie o to,
co byo zgodne, czyli o  znakw, wyzerowujc przy okazji . Omwmy jeszcze moment stwierdzenia cakowitej zgodnoci wzorca z tekstem. Kiedy to nastpi? Ot
nietrudno zauway, e podczas stwierdzenia zgodnoci ostatniego znaku  powinno
zrwna si z . Moemy wwczas atwo odtworzy pozycj, od ktrej wzorzec startuje
w badanym tekcie: bdzie to oczywicie .
Tumaczc powysze sytuacje na C++, moemy atwo doj do nastpujcej procedury:
txt-1.cpp



   
 

 
    

!""!

  #$%
#$

&&'
&'
(
))))
(
 

 &


 &'
(

Sposb korzystania z funkcji 


 jest przedstawiony na przykadzie nastpujcej
funkcji :


 *+**+ ++
  !! * !!
 ,
(

Jako wynik funkcji zwracana jest pozycja w tekcie, od ktrej zaczyna si wzorzec, lub 
w przypadku, gdy poszukiwany tekst nie zosta odnaleziony jest to znana nam ju
doskonale konwencja. Przypatrzmy si dokadniej przykadowi poszukiwania wzorca
 w pewnym tekcie binarnym (patrz rysunek 8.2).

Rozdzia 8. Przeszukiwanie tekstw


Rysunek 8.2.
Faszywe starty
podczas poszukiwania

197

`0

Rysunek jest nieco uproszczony: w istocie poziome przesuwanie si wzorca oznacza instrukcje zaznaczone na listingu jako (*), natomiast caa szara strefa o dugoci k oznacza
k-krotne wykonanie (**).
Na podstawie zobrazowanego przykadu moemy sprbowa wymyli taki najgorszy
tekst i wzorzec, dla ktrych proces poszukiwania bdzie trwa moliwie najduej. Chodzi oczywicie o zarwno tekst, jak i wzorzec zoone z samych zer i zakoczone jedynk4.
Sprbujmy obliczy klas tego algorytmu dla opisanego przed chwil ekstremalnego najgorszego przypadku. Obliczenie nie naley do skomplikowanych czynnoci: zakadajc, e restart algorytmu bdzie konieczny  razy, i wiedzc, e podczas kadego cyklu jest konieczne wykonanie  porwna, otrzymujemy natychmiast
, czyli okoo5 .
Zaprezentowany w tym paragrafie algorytm wykorzystuje komputer jako bezmylne,
ale sprawne liczydo6. Jego zoono obliczeniowa eliminuje go w praktyce z przeszukiwania tekstw binarnych, w ktrych moe wystpi wiele niekorzystnych konfiguracji danych. Jedyn zalet algorytmu jest jego prostota, co i tak nie czyni go na tyle atrakcyjnym, by da si zamczy jego powolnym dziaaniem.

8.2. Nowe algorytmy poszukiwa


Algorytm, o ktrym bdzie mowa w tym rozdziale, posiada ciekaw histori, ktr
w formie anegdoty warto przytoczy. Ot w 1970 roku S. A. Cook udowodni teoretyczny rezultat dotyczcy pewnej abstrakcyjnej maszyny. Wynikao z niego, e istnia
4
5
6

Zera i jedynki symbolizuj tu dwa rne od siebie znaki.


Zwykle  bdzie znacznie mniejsze ni .
Termin brute-force jeden z moich znajomych licznie przetumaczy jako metod mastodonta.

198

Algorytmy, struktury danych i techniki programowania

algorytm poszukiwania wzorca w tekcie, ktry dziaa w czasie proporcjonalnym do


 w najgorszym przypadku. Rezultat pracy Cooka wcale nie by przewidziany do praktycznych celw, niemniej D. E. Knuth i V. R. Pratt otrzymali na jego podstawie algorytm, ktry by atwo implementowalny praktycznie ukazujc przy okazji, i pomidzy praktycznymi realizacjami a rozwaaniami teoretycznymi nie istnieje wcale a tak
ogromna przepa, jakby si to mogo wydawa. W tym samym czasie J. H. Morris odkry dokadnie ten sam algorytm jako rozwizanie problemu, ktry napotka podczas
praktycznej implementacji edytora tekstu. Algorytm K-M-P bo tak bdziemy go dalej
zwali jest jednym z przykadw do czstych w nauce odkry rwnolegych: z jakich niewiadomych powodw nagle kilku pracujcych osobno ludzi dochodzi do tego
samego dobrego rezultatu. Prawda, e jest w tym co niesamowitego i a si prosi o jakie metafizyczne hipotezy?
Knuth, Morris i Pratt opublikowali swj algorytm dopiero w 1976 roku. W midzyczasie
pojawi si kolejny cudowny algorytm, tym razem autorstwa R. S. Boyera i J. S.
Moorea, ktry okaza si w pewnych zastosowaniach znacznie szybszy od algorytmu
K-M-P. Zosta on rwnie rwnolegle wynaleziony (odkryty?) przez R. W. Gospera.
Oba te algorytmy s jednak do trudne do zrozumienia bez pogbionej analizy, co
utrudnio ich rozpropagowanie.
W roku 1980 R. M. Karp i M. O. Rabin doszli do wniosku, e przeszukiwanie tekstw
nie jest a tak dalekie od standardowych metod przeszukiwania i wynaleli algorytm,
ktry dziaajc cigle w czasie proporcjonalnym do  jest ideowo zbliony do
poznanego ju przez nas algorytmu typu brute-force. Na dodatek, jest to algorytm, ktry
mona wzgldnie atwo uoglni na przypadek poszukiwania w tablicach 2-wymiarowych, co czyni go potencjalnie uytecznym w obrbce obrazw.
W nastpnych trzech sekcjach szczegowo omwimy sobie wspomniane w tym przegldzie historycznym algorytmy.

8.2.1. Algorytm K-M-P


Wad algorytmu brute-force jest jego czuo na konfiguracj danych: faszywe restarty
s tu bardzo kosztowne; w analizie tekstu cofamy si o ca dugo wzorca, zapominajc po drodze wszystko, co przetestowalimy do tej pory. Narzuca si tu niejako
ch skorzystania z informacji, ktre ju w pewien sposb posiadamy przecie
w nastpnym etapie bd wykonywane czciowo te same porwnania, co poprzednio!
W pewnych szczeglnych przypadkach przy znajomoci struktury analizowanego tekstu moliwe jest ulepszenie algorytmu. Przykadowo: jeli wiemy na pewno, i w poszukiwanym wzorcu jego pierwszy znak nie pojawia si ju w nim w ogle7, to
w razie restartu nie musimy cofa wskanika  o  pozycji, jak to byo poprzednio
(patrz listing txt-1.cpp). W tym przypadku moemy po prostu zinkrementowa  wiedzc,
e ewentualne powtrzenie poszukiwa na pewno nic by ju nie dao. Owszem, mona si atwo zgodzi z twierdzeniem, i tak wyspecjalizowane teksty zdarzaj si relatywnie rzadko, jednak powyszy przykad ukazuje, i ewentualne manipulacje algo7

Przykad: ABBBBBBB znak A wystpi tylko jeden raz.

Rozdzia 8. Przeszukiwanie tekstw

199

rytmami poszukiwa s cigle moliwe wystarczy si tylko rozejrze. Idea algorytmu


K-M-P. polega na wstpnym zbadaniu wzorca w celu obliczenia iloci pozycji, o ktre
naley cofn wskanik  w przypadku stwierdzenia niezgodnoci badanego tekstu ze
wzorcem. Oczywicie, mona rwnie rozumowa w kategoriach przesuwania wzorca
do przodu rezultat bdzie ten sam. To wanie t drug konwencj bdziemy stosowa
dalej. Wiemy ju, e powinnimy przesuwa si po badanym tekcie nieco inteligentniej
ni w poprzednim algorytmie. W przypadku zauwaenia niezgodnoci na pewnej pozycji  wzorca8 naley zmodyfikowa ten indeks, wykorzystujc informacj zawart w ju
zbadanej szarej strefie zgodnoci.
Brzmi to wszystko (zapewne) niesychanie tajemniczo, pora wic jak najszybciej wyjani
t spraw, aby unikn moliwych nieporozumie. Popatrzmy w tym celu na rysunek 8.3.
Rysunek 8.3.
Wyszukiwanie optymalnego
przesunicia w algorytmie
K-M-P

Moment niezgodnoci zosta zaznaczony poprzez narysowanie przerywanej pionowej


kreski. Ot wyobramy sobie, e przesuwamy teraz wzorzec bardzo wolno w prawo,
patrzc jednoczenie na ju zbadany tekst tak, aby obserwowa ewentualne pokrycie
si tej czci wzorca, ktra znajduje si po lewej stronie przerywanej kreski, z tekstem,
ktry umieszczony jest powyej wzorca. W pewnym momencie moe okaza si, e nastpuje pokrycie obu tych czci. Zatrzymujemy wwczas przesuwanie i kontynuujemy
testowanie (znak po znaku) zgodnoci obu czci znajdujcych si za kresk pionow.
Od czego zaley ewentualne pokrycie si ogldanych fragmentw tekstu i wzorca? Ot,
do paradoksalnie badany tekst nie ma tu nic do powiedzenia jeli mona to tak
okreli. Informacja o tym, jaki on by, jest ukryta w stwierdzeniu  znakw byo
zgodnych w tym sensie mona zupenie o badanym tekcie zapomnie i analizujc
wycznie sam wzorzec, odkry poszukiwane optymalne przesunicie. Na tym wanie
spostrzeeniu opiera si idea algorytmu K-M-P. Okazuje si, e badajc sam struktur
wzorca, mona obliczy, jak powinnimy zmodyfikowa indeks  w razie stwierdzenia
niezgodnoci tekstu ze wzorcem na j-tej pozycji.
Zanim zagbimy si w wyjanienia na temat obliczania owych przesuni, popatrzmy
na efekt ich dziaania na kilku kolejnych przykadach. Na rysunku 8.4 moemy dostrzec, i na sidmej pozycji wzorca9 (ktrym jest do abstrakcyjny cig ) zostaa stwierdzona niezgodno.
Jeli zostawimy indeks  w spokoju, to modyfikujc wycznie  moemy bez
problemu kontynuowa przeszukiwanie. Jakie jest optymalne przesunicie wzorca? lizgajc go wolno w prawo (patrz rysunek 8.4) doprowadzamy w pewnym momencie
do naoenia si cigw  przed kresk caa strefa niezgodnoci zostaa wyprowadzona na prawo i ewentualne dalsze testowanie moe by kontynuowane!
8
9

Lub i w przypadku badanego tekstu.


Liczc indeksy tablicy tradycyjnie od zera.

200

Algorytmy, struktury danych i techniki programowania


i=const

Rysunek 8.4.
Przesuwanie si wzorca
w algorytmie K-M-P (1)

i=const
1

j=3

j=7

Analogiczny przykad znajduje si na rysunku 8.5.


Rysunek 8.5.
Przesuwanie si wzorca
w algorytmie K-M-P (2)

i=const
1

i=const
1

j=3

j=1

Tym razem niezgodno wystpia na pozycji . Dokonujc podobnie jak poprzednio przesuwania wzorca w prawo, zauwaamy, i jedyne moliwe naoenie si
znakw wystpi po przesuniciu o dwie pozycje w prawo czyli dla . Dodatkowo okazuje si, e znaki za kresk te si pokryy, ale o tym algorytm dowie si dopiero
podczas kolejnego testu zgodnoci na pozycji .
Dla potrzeb algorytmu K-M-P konieczne okazuje si wprowadzenie tablicy przesuni
. Sposb jej zastosowania bdzie nastpujcy: jeli na pozycji  wystpia
niezgodno znakw, to kolejn wartoci  bdzie . Nie wnikajc chwilowo
w sposb inicjalizacji tej tablicy (odmiennej oczywicie dla kadego wzorca), moemy natychmiast poda algorytm K-M-P, ktry w konstrukcji jest niemal dokadn kopi
algorytmu typu brute-force:
kmp.cpp
-.


    
 !""!)) ))

/ "" #$%
#$
01 #$
 

 &


 &'
(

Szczeglnym przypadkiem jest wystpienie niezgodnoci na pozycji zerowej: z zaoenia niemoliwe jest tu przesuwanie wzorca w celu uzyskania naoenia si znakw.
Z tego powodu chcemy, aby indeks  pozosta niezmieniony przy jednoczesnej progresji indeksu . Jest to moliwe do uzyskania, jeli umwimy si, e  zostanie
zainicjowany wartoci . Wwczas podczas kolejnej iteracji ptli  nastpi inkrementacja  oraz , co wyzeruje nam .

Rozdzia 8. Przeszukiwanie tekstw

201

Pozostaje do omwienia sposb konstrukcji tablicy . Jej obliczenie powinno


nastpi przed wywoaniem funkcji , co sugeruje, i w przypadku wielokrotnego poszukiwania tego samego wzorca nie musimy ju powtarza inicjacji tej tablicy. Funkcja inicjujca tablic jest przewrotna jest ona praktycznie identyczna z  z t tylko
rnic, i algorytm sprawdza zgodno wzorca... z nim samym!
01 #$
 201 


 
01 #$&'
 &'!&')) )) 01 #$

/ ""
#$%
#$ 
01 #$
(

Sens tego algorytmu jest nastpujcy: tu po inkrementacji  i  wiemy, e pierwsze 


znakw wzorca jest zgodne ze znakami na pozycjach:   (ostatnie 
pozycji w pierwszych  znakach wzorca). Poniewa jest to najwiksze  speniajce powyszy warunek, zatem, aby nie omin potencjalnego miejsca wykrycia wzorca w tekcie, naley ustawi  na .
Popatrzmy, jaki bdzie efekt zadziaania funkcji ! na sowie ananas (patrz
rysunek 8.6). Zacieniowane litery oznaczaj miejsca, w ktrych wystpia niezgodno
wzorca z tekstem. W kadym przypadku graficznie przedstawiono efekt przesunicia
wzorca wida wyranie, ktre strefy pokrywaj si przed stref zacieniowan (porwnaj rysunek 8.5).
Rysunek 8.6.
Optymalne przesunicia
wzorca ananas

a)
a

b)
n

a
s

c)
a

d)
n

a
a

e)
a

Przypomnijmy jeszcze, e tablica  zawiera now warto dla indeksu , ktry
przemieszcza si po wzorcu.
Algorytm K-M-P mona zoptymalizowa, jeli znamy z gry wzorce, ktrych bdziemy
poszukiwa. Przykadowo: jeli bardzo czsto zdarza nam si szuka w tekstach sowa ananas, to w funkcj  mona wbudowa tablic przesuni:

202

Algorytmy, struktury danych i techniki programowania

ananas.cpp
-.2

&'
  3
))
 3  #$%44   
))
 '3  #$%44  
))
 ,3  #$%44  
))
 53  #$%44  '
))
  #$%44  ,
))
  #$%44  5
))

 &6
(

W celu waciwego odtworzenia etykiet naley oczywicie co najmniej raz wykona


funkcj ! lub obliczy samemu odpowiednie wartoci. W kadym razie gra
jest warta wieczki: powysza funkcja charakteryzuje si bardzo zwizym kodem
wynikowym asemblerowym, jest zatem bardzo szybka. Posiadacze kompilatorw,
ktre umoliwiaj generacj kodu wynikowego jako tzw. assembly output10, mog
z atwoci sprawdzi rnice pomidzy wersjami  i !   ! Dla przykadu
mog poda, e w przypadku wspomnianego kompilatora GNU klasyczna wersja procedury  (wraz z !) miaa objto okoo 170 linii kodu asemblerowego,
natomiast !    zmiecia si w ok. 100 liniach. (Patrz: pliki z rozszerzeniem s na
dyskietce dla kompilatora GNU lub asm dla kompilatora Borland C++ 5.5).
Algorytm K-M-P dziaa w czasie proporcjonalnym do  w najgorszym przypadku.
Najwikszy zauwaalny zysk zwizany z jego uyciem dotyczy przypadku tekstw
o wysokim stopniu samopowtarzalnoci do rzadko wystpujcych w praktyce.
Dla typowych tekstw zysk zwizany z wyborem metody K-M-P bdzie zatem sabo zauwaalny.
Uycie tego algorytmu jest jednak niezbdne w tych aplikacjach, w ktrych nastpuje
liniowe przegldanie tekstu bez buforowania. Jak atwo zauway, wskanik  w funkcji  nigdy nie jest dekrementowany, co oznacza, e plik mona przeglda od pocztku do koca bez cofania si w nim. W niektrych systemach moe to mie istotne
znaczenie praktyczne przykadowo: mamy zamiar analizowa bardzo dugi plik
tekstowy i charakter wykonywanych operacji nie pozwala na cofnicie si w tej czynnoci (i w odczytywanym na bieco pliku).
10

W przypadku kompilatorw popularnej serii Borland C++ naley skompilowa program rcznie poprzez
polecenie bcc32 -S -Ixxx plik.cpp, gdzie xxx oznacza katalog z plikami typu H; identyczna opcja istnieje
w kompilatorze GNU C++, naley wystuka: c++ -S plik.cpp.

Rozdzia 8. Przeszukiwanie tekstw

203

8.2.2.Algorytm Boyera i Moorea


Kolejny algorytm, ktry bdziemy omawiali, jest ideowo znacznie prostszy do zrozumienia ni algorytm K-M-P. W przeciwiestwie do metody K-M-P porwnywaniu
ulega ostatni znak wzorca. To niekonwencjonalne podejcie niesie ze sob kilka istotnych zalet:
 jeli podczas porwnywania okae si, e rozpatrywany aktualnie znak nie

wchodzi w ogle w skad wzorca, wwczas moemy skoczy w analizie


tekstu o ca dugo wzorca do przodu! Ciar algorytmu przesun si wic
z analizy ewentualnych zgodnoci na badanie niezgodnoci a te ostatnie s
statystycznie znacznie czciej spotykane;
 skoki wzorca s zazwyczaj znacznie wiksze od  porwnaj z metod K-M-P!

Zanim przejdziemy do szczegowej prezentacji kodu, omwimy sobie na przykadzie jego dziaanie. Spjrzmy w tym celu na rysunek 8.7, gdzie przedstawione jest poszukiwanie cigu znakw lek w tekcie Z pamitnika modej lekarki11.
Rysunek 8.7.
Przeszukiwanie tekstu
metod Boyera
i Moore'a

k
l

Pierwsze pi porwna trafia na litery: , , , i ", ktre we wzorcu nie wystpuj!


Za kadym razem moemy zatem przeskoczy w tekcie o trzy znaki do przodu (dugo wzorca). Porwnanie szste trafia jednak na liter #, ktra w sowie lek wystpuje. Algorytm wwczas przesuwa wzorzec o tyle pozycji do przodu, aby litery #
naoyy si na siebie, i porwnywanie jest kontynuowane.
Nastpnie okazuje si, e litera  nie wystpuje we wzorcu mamy zatem prawo przesun si o kolejne 3 znaki do przodu. W tym momencie trafiamy ju na poszukiwane
sowo, co nastpuje po jednokrotnym przesuniciu wzorca, tak aby pokryy si litery .
Algorytm jest jak wida klarowny, prosty i szybki. Jego realizacja take nie jest zbyt
skomplikowana. Podobnie jak w przypadku metody poprzedniej, take i tu musimy wykona pewn prekompilacj w celu stworzenia tablicy przesuni. Tym razem jednak
tablica ta bdzie miaa tyle pozycji, ile jest znakw w alfabecie wszystkie znaki,
ktre mog wystpi w tekcie plus spacja. Bdziemy rwnie potrzebowali prostej
11

Tytu znakomitego cyklu autorstwa Ewy Szumaskiej.

204

Algorytmy, struktury danych i techniki programowania

funkcji $# , ktra zwraca w przypadku spacji liczb zero w pozostaych przypadkach numer litery w alfabecie. Poniszy przykad uwzgldnia jedynie kilka polskich
liter Czytelnik uzupeni go z atwoci o brakujce znaki. Numer litery jest oczywicie zupenie arbitralny i zaley od programisty. Wane jest tylko, aby nie pomin w tablicy adnej litery, ktra moe wystpi w tekcie. Jedna z moliwych wersji funkcji
$#  jest przedstawiona poniej:
 7,6 ,), ,)'89:;;). <). 
01 #7$





443
 . 

4=43
 >5

4?43
 >@. <

443
 >>

4A43
 >6 B. < 0

 3. 0 
 
 C D -E EF

  &44)'



  &484),G
(
(

Funkcja $#  ma jedynie charakter usugowy. Suy ona m.in. do waciwej inicjalizacji tablicy przesuni. Majc za sob analiz przykadu z rysunku 8.7, Czytelnik nie
powinien by zbytnio zdziwiony sposobem inicjalizacji:
 201 


  

!7))
01 #$
!))
01 #
#$ $&&'
(

Przejdmy wreszcie do prezentacji samego listingu algorytmu, z przykadem wywoania:


*-


 201 

     

&' &'/&& &&

 #$%
#$

H01 # #$ $
 &/H
)&


)H
 /

 &'
&'
(

Rozdzia 8. Przeszukiwanie tekstw

205


 
(
-

 +I.-= -+
 !!+J<.
K+!!*-++ !!
(

Algorytm Boyera i Moorea, podobnie jak i K-M-P, jest klasy  jednak jest on
o tyle od niego lepszy, i w przypadku krtkich wzorcw i dugiego alfabetu koczy
si po okoo M/N porwnaniach. W celu obliczenia optymalnych przesuni12 autorzy algorytmu proponuj skombinowanie powyszego algorytmu z tym zaproponowanym
przez Knutha, Morrisa i Pratta. Celowo tego zabiegu wydaje si jednak wtpliwa,
gdy, optymalizujc sam algorytm, mona w bardzo atwy sposb uczyni zbyt czasochonnym sam proces prekompilacji wzorca.

8.2.3. Algorytm Rabina i Karpa


Ostatni algorytm do przeszukiwania tekstw, ktry bdziemy analizowali, wymaga znajomoci rozdziau 7. i terminologii, ktra zostaa w nim przedstawiona. Algorytm Rabina
i Karpa polega bowiem na do przewrotnej idei:
 wzorzec %(do odszukania) jest kluczem (patrz terminologia transformacji
kluczowej w rozdziale 7.) o dugoci  znakw, charakteryzujcym si pewn
wartoci wybranej przez nas funkcji &. Moemy zatem obliczy jednokrotnie
&&% i korzysta z tego wyliczenia w sposb cigy.
 tekst wejciowy  (do przeszukania) moe by w taki sposb odczytywany,
aby na bieco zna  ostatnich znakw13. Z tych  znakw wyliczamy
na bieco &&.

Gdy zaoymy jednoznaczno wybranej funkcji &, sprawdzenie zgodnoci wzorca


z aktualnie badanym fragmentem tekstu sprowadza si do odpowiedzi na pytanie: czy &
jest rwne &? Spostrzegawczy Czytelnik ma jednak prawo pokrci w tym miejscu
z powtpiewaniem gow: przecie to nie ma prawa dziaa szybko! Istotnie, pomys
wyliczenia dodatkowo funkcji & dla kadego sowa wejciowego o dugoci  wydaje
si tak samo kosztowny jak nie bardziej! jak zwyke sprawdzanie tekstu znak po
znaku (patrz algorytm brute-force, 8.1). Tym bardziej e jak do tej pory nie powiedzielimy ani sowa na temat funkcji &! Z poprzedniego rozdziau pamitamy zapewne,
i jej wybr wcale nie by taki oczywisty.
Omawiany algorytm jednak istnieje i na dodatek dziaa szybko! Zatem, aby to wszystko, co poprzednio zostao napisane, logicznie si ze sob czyo, potrzebny nam bdzie
zapewne jaki trik. Sztuka polega na waciwym wyborze funkcji &. Robin i Karp wybrali
12
13

Rozwa np. wielokrotne wystpowanie takich samych liter we wzorcu.


Na samym pocztku bdzie to oczywicie  pierwszych znakw tekstu.

206

Algorytmy, struktury danych i techniki programowania

tak funkcj, ktra dziki swym szczeglnym waciwociom umoliwia dynamiczne


wykorzystywanie wynikw oblicze dokonanych krok wczeniej, co znaczco potrafi
uproci obliczenia wykonywane w kroku biecym.
Zamy, e cig M znakw bdziemy interpretowa jako pewn liczb cakowit.
Przyjmujc za b jako podstaw systemu ilo wszystkich moliwych znakw,
otrzymamy:
x = t[i]b M-1 + t[i + 1]b M-2 +K t[i + M -1].

Przesumy si teraz w tekcie o jedn pozycj do przodu i zobaczmy, jak zmieni si


warto x:
x'= t[i + 1]b M-1 + t[i + 2]b M-2 +... t[i + M].

Jeli dobrze przyjrzymy si x i x', to okae si, e warto x' jest w duej czci zbudowana z elementw tworzcych x pomnoonych przez b z uwagi na przesunicie.
Nietrudno jest wwczas wywnioskowa, e:
x'= ( x - t[i]b M-1 ) + t[i + M].

Jako funkcji & uyjemy dobrze nam znanej z poprzedniego rozdziau &'' (, gdzie
 jest du liczb pierwsz. Zamy, e dla danej pozycji  warto &' jest nam
znana. Po przesuniciu si w tekcie o jedn pozycj w prawo pojawia si konieczno
wyliczenia wartoci funkcji &')dla tego nowego sowa. Czy istotnie zachodzi potrzeba powtarzania caego wyliczenia? By moe istnieje pewne uatwienie bazujce na
zalenoci, jaka istnieje pomidzy ' i ')?
Na pomoc przychodzi nam tu wasno funkcji $
* uytej w wyraeniu arytmetycznym. Mona oczywicie obliczy $
* z wyniku kocowego, lecz to bywa czasami
niewygodne z uwagi na przykad wielko liczby, z ktr mamy do czynienia a poza tym, gdzie tu byby zysk szybkoci?! Jednak identyczny wynik otrzymuje si, aplikujc funkcj $
* po kadej operacji czstkowej i przenoszc otrzyman warto do
nastpnego wyraenia czstkowego! Dla przykadu wemy obliczenie:
(5*100 + 6 *10 + 8)%7 = 568%7 = 1.

Wynik ten jest oczywicie prawdziwy, co mona atwo sprawdzi z kalkulatorem. Identyczny rezultat da nam jednak nastpujca sekwencja oblicze:

5*100%7 = 3

(3 + 6 *10)%7 = 0

(0 + 8)%7 = 1

co jest te atwe do weryfikacji.


Implementacja algorytmu jest prosta, lecz zawiera kilka instrukcji wartych omwienia.
Popatrzmy na listing:

Rozdzia 8. Przeszukiwanie tekstw

207

rk.cpp

#$  #$

 
  *2'' L
 L   
 
  
!))

L
L
*)
#$ M.  1 L
 
L L *) #$ M.  1 L  
(
'!)) *2'* *2' M.
L
%L )) .
=
  

L L )* .& #$ *2' M.
L L *) #)$ M.
 /&

 &'.N.
K
(

 
(

Na pierwszym etapie nastpuje wyliczenie pocztkowych wartoci & i &. Poniewa


cigi znakw trzeba interpretowa jako liczby, konieczne bdzie zastosowanie znanej
ju nam doskonale funkcji $#  (patrz strona 204.). Warto & jest niezmienna i nie
wymaga uaktualniania. Nie dotyczy to jednak aktualnie badanego fragmentu tekstu
tutaj warto & ulega zmianie podczas kadej inkrementacji zmiennej . Do obliczenia
&') moemy wykorzysta omwion wczeniej wasno funkcji $
* co jest dokonywane w trzeciej ptli . Dodatkowego wyjanienia wymaga by moe linia oznaczona (*). Ot dodawanie wartoci +, do & pozwala nam unikn przypadkowego
wskoczenia w liczby ujemne. Gdyby istotnie tak si stao, przeniesiona do nastpnego
wyraenia arytmetycznego warto $
* byaby nieprawidowa i sfaszowaaby kocowy wynik!
Kolejne uwagi nale si parametrom  i +. Zaleca si, aby  byo du liczb pierwsz14, jednake nie mona tu przesadza z uwagi na moliwe przekroczenie zakresu
pojemnoci uytych zmiennych. W przypadku wyboru duego  zmniejszamy prawdopodobiestwo wystpienia kolizji spowodowanej niejednoznacznoci funkcji &. Ta
moliwo mimo i mao prawdopodobna cigle istnieje i ostrony programista
powinien wykona dodatkowy test zgodnoci % i    po zwrceniu
przez funkcj  pewnego indeksu .
Co za si tyczy wyboru podstawy systemu (oznaczonej w programie jako b), to warto
jest wybra liczb nawet nieco za du, zawsze jednak bdc potg liczby 2. Moliwe jest wwczas zaimplementowanie operacji mnoenia przez b jako przesunicia
bitowego wykonywanego przez komputer znacznie szybciej ni zwyke mnoenie.
Przykadowo: dla b=64 moemy zapisa mnoenie +, jako --..
Gwoli formalnoci jeszcze mona doda, e gdy nie wystpuje kolizja (typowy przypadek!), algorytm Robina i Karpa wykonuje si w czasie proporcjonalnym do .
14

W naszym przypadku jest to liczba 33554393.

You might also like