Professional Documents
Culture Documents
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
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
Spis treci
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
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.
M-1
wzorzec w
1
2
3
K
0
Z
N-1
i
Badany tekst t
196
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
!""!
#$%
#$
&&'
&'
(
))))
(
&
&'
(
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).
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.
198
199
200
Rysunek 8.4.
Przesuwanie si wzorca
w algorytmie K-M-P (1)
i=const
1
j=3
j=7
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 .
201
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
ananas.cpp
-.2
&'
3
))
3#$%44
))
'3#$%44
))
,3#$%44
))
53#$%44
'
))
#$%44
,
))
#$%44
5
))
&6
(
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.
203
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
204
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
>6B.< 0
3. 0
C D-EEF
&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#
#$
$&&'
(
)H
/
&'
&'
(
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.
206
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
207
rk.cpp
#$#$
*2''L
L
!))
L
L
*)
#$
M. 1 L
LL *)#$
M. 1 L
(
'!))
*2'* *2'
M.
L
%L))
.
=
LL)* .&#$
*2'
M.
LL *)#)$
M.
/&
&'.N.
K
(
(