Algorytmy i struktury danych/Algorytmy tekstowe I: Różnice pomiędzy wersjami
Linia 53: | Linia 53: | ||
== Minimalne słowo pokrywające == | == Minimalne słowo pokrywające == | ||
Pokażemy pewne proste zastosowanie tablice prefikso-sufisków. | Pokażemy pewne proste zastosowanie tablice prefikso-sufisków. | ||
Słowem pokrywającym tekst x taki tekst y, którego wystąpienia w x | |||
pokrywają cały tekst x. Na przykład aba pokrywa ababaaba, natomiast nie pokrywa tekstu abaaababa. | |||
Obliczyć długość najkrótszego słowa pkrywającego dany tekst x. | |||
Niech <math>S[i]</math> | |||
będzie rozmiarem minimalnego pokrywajćego słowa dla prefiksu <math>x[1..i]</math>. Następujący algorytm liczy długość minimalnego słowa | |||
pokrywającego tekstu x. Liczymy wartości <math>S[i]</math> najmniejszej długości minimalnego słowa pokrywającego <math>x[1 | |||
\ldots i]</math> dla każdego <math>1 \le i \le n</math>. | |||
W <math>i</math>-tej | |||
iteracji algorytm pamięta jaki jest ``znany zakres'' każdego minimalnego słowa pokrywającego. | |||
<center> [[Grafika:Minpokslowo.jpg]]<br> | |||
Rysunek 3: <math>i</math>-ta iteracja algorytmu, dla <math>i=15</math>, oraz słowa <math>x\ =\ abaabababaababa\ldots</math>. Tuż przed | |||
rozpoczęciem tej iteracji mamy <math>P[i]=8</math>, <math>q=S[8]=3</math>, <math>Zakres[3]=13</math>. Po zakończeniu <math>i</math>-tej iteracji | |||
mamy <math>S[15]=3,Zakres[3]=15</math>, ponieważ <math>i-Zakres[3] \le q</math>. </center> | |||
{{algorytm | Rozmiar-Minimalnego-Pokrycia|algorym_rozm_min_pokr| | |||
'''for ''' <math>i:=2</math> '''to''' <math>n</math> '''do'''<br> | |||
<math>Zakres[i]=i, S[i]=i</math><br> | |||
'''for ''' <math>i:=2</math> '''to''' <math>n</math> '''do'''<br> | |||
'''if''' <math>P[i]>0</math> oraz <math>i-Zakres[S[P[i]] \le S[P[i]]</math> '''then'''<br> | |||
<math>S[i] := S[P[i]]</math>; <math>Zakres[S[P[i]] := i</math>;<br> | |||
'''return''' <math>S[n]</math>; | |||
}} | |||
==Tablica Silnych Prefikso-Sufiksów== | ==Tablica Silnych Prefikso-Sufiksów== |
Wersja z 10:30, 24 sie 2006
Algorytmy tekstowe I
Tekst jest ciągiem symboli, przyjmujemy że jest on zadany tablicą x[1..n] elementami której są symbole ze zbioru A (zwanego alfabetem). Liczba jest długością (rozmiarem)tekstu. W większości naszych algorytmów jedyne operacje dopuszczalne na symbolach wejściowych to porównania dwóch symboli.
Algorytmy na tekstach wyróżniają się tym, że wykorzystują specyficzne kombinatorycznewłasności tekstów. Okresem tekstu jest każda liczba naturalna niezerowa taka, że, dla każdego i dla którego obie strony są zdefiniowane. Przez per(x) oznaczmyminimalny okres x. Okresowość spełnia następującą ciekawą własność kombinatoryczną. Niech oznaczanajmnieszy wspólny dzielnik p,q.
Lemat [Lemat o okresowości]
Jeśli x ma okresy p, q oraz to jest również okresem x.
Lemat ten wynika z poprawności algorytm Euklidesa z odejmowaniem, który liczy nwd(p,q). Zauważmy, żejeśli są okresami to p-q też jest okresem. Dokładny dowód zostawiamy jako ćwiczenie.
Lemat ten można wzmocnić osłabiając założenia. Dowód pozostawiamy jako ćwiczenie.
Lemat [Silny lemat o okresowości]
Jeśli x ma okresy p, q oraz to jest również okresem x.
Pojęciem dualnym do okresu jestprefikso-sufiks tekstu, jest to najdłuższy własciwy (nie będący całym x) prefiks tekstu x będącyjednocześnie sufiksem x. Oczywistym jest, że jest długością prefikso-sufiksu x.Jeśli to prefikso-sufiksem x jest słowo puste o długości zerowej.
Oznaczmy przez rozmiar prefikso-sufiksu , zatem , gdzie .
Przykład
Dla mamy:
Wartość jest warością sztuczną (przyjmiemy potem ).
Liczenie tablicy Prefikso-Sufiksów
Przedstawimy jeden z możliwych algorytmów liniowych oblicznaia tablicy P, jest to iteracyjna wersja algorytmu rekurencyjnego, który moglibyśmy otrzymac korzystając z faktu:
W algorytmie do liczenia korzystamy z wartości dla .
Algorytm Prefikso-Sufiksy
; ;
for to do
while and do
; ;
Złożoność liniowa wynika stąd, że w każdej iteracji zwiększamy wartość t co najwyżejo jeden, a wykonanie każdej operacji zmniejsza wartość t co najmniej o jeden. Proste zastosowanie zasady magazynu (lub potencjału) implikuje, że operacji wykonujemy conajwyżej n. Dowód poprawności pozostawiamy jako ćwiczenie.
Minimalne słowo pokrywające
Pokażemy pewne proste zastosowanie tablice prefikso-sufisków.
Słowem pokrywającym tekst x taki tekst y, którego wystąpienia w x pokrywają cały tekst x. Na przykład aba pokrywa ababaaba, natomiast nie pokrywa tekstu abaaababa. Obliczyć długość najkrótszego słowa pkrywającego dany tekst x.
Niech będzie rozmiarem minimalnego pokrywajćego słowa dla prefiksu . Następujący algorytm liczy długość minimalnego słowa pokrywającego tekstu x. Liczymy wartości najmniejszej długości minimalnego słowa pokrywającego dla każdego . W -tej iteracji algorytm pamięta jaki jest ``znany zakres każdego minimalnego słowa pokrywającego.

Rysunek 3: -ta iteracja algorytmu, dla , oraz słowa . Tuż przed rozpoczęciem tej iteracji mamy , , . Po zakończeniu -tej iteracji
mamy , ponieważ .Algorytm Rozmiar-Minimalnego-Pokrycia
for to do
for to do
if oraz then
; ;
return ;
Tablica Silnych Prefikso-Sufiksów
Wprowadzimy silną tablicę prefikso-sufisów dla wzorca :
jeśli to , gdzie jest maksymalnym rozmiarm słowa będącego prefiksem i sufiksem najdłuższego własciwegoi spełniającego dodatkowy warunek dla .
Jeśli takiego k nie ma toprzyjmujemy . Przyjmujemy ponadto, że .
Wartości tablicy P' mogą być znacznie mniejsze niż wartości tablicy P.
Przykład
Dla mamy:
Algorytm bazuje na następującej relacji między P i P':
Nie musimy liczyć tablicy P, potrzebna jest jedynie ostatnia wartość , którą liczymy on-line.
Algorytm Silne-Prefikso-Sufiksy
; 1;
for 1 to do //
while and do
;
;
if or
then else ;
Gdyweżmiemy to , , ,oraz , dla . To jest pesymistyczny przypadek dla algorytmu Silne-Prefikso-Sufiksy, algorytm wykonuje porównań symboli.
String-matching: algorytm Knutha-Morrisa-Pratta
Przedstawimy klasyczny algorytm Knutha-Morrisa-Pratta (w skrócie KMP) dla problemu string-matchingu: obliczyć w w tekście wszystkie (lub pierwsze) wystąpienia danego tekstu , zwanego wzorcem (ang. pattern).
Oznaczmy , gdzie .
Operacją dominującą w algorytmie jest porównanie dwóch symboli.
Zaczniemy od obliczania jedynie pierwszego wystąpienia. Algorytm KMP przegląda tekst y od lewej do prawej, sprawdzając, czy jest zgodność na pozycji we wzorcu x, oraz na pozycji w tekście y. Jeśli jest niezgodność to przesuwamy potencjalny początek (pozycja i) wystąpienia x w y.Zakładamy, że algorytm zwraca wartość false gdy nie zwróci wcześniej true. Pozostawiamy dowód poprawności(określenie niezmienników) jako ćwiczenie.
Algorytm Algorithm KMP
; ;
while do
while and do ;
if then return(true);
;
Operacją dominującą w algorytmie jest operacja: .
Udowodnimy, że algorytm KMP wykonuje co najwyżej 2n-m porównań symboli. Zauważmy, że dla danejpozycji w tekście y jest ona co najwyżej raz porównana z pewną pozycją we wzorcu w porównaniupozytywnym (gdy symbole są równe). Jednocześnie każde negatywne porównanie powoduje przesunięciepozycji co najmniej o jdeden, maksymalna wartość i wynosi n-m, zatem mamy takich porównań conajwyżej n-m, w sumie co najwyżej 2n-m porównań w algorytmi KMP.
Algorytm dla , wykonuje 2n-2porównania, zatem 2n-m jest dolną i jednocześnie górną granicą na liczbę porównań w algorytmie.
Obserwacja. Tablicę P' możemy w algorytmie KMP zamienić na P bez zmiany złożoności pesymistycznej.
W wersji on-line algorytmu okaże się, że jest zdecydowana różnica między użyciem P' i P,to właśnie jest motywem wprowadzenia silnych prefikso-sufiksów.

Wersja on-line algorytmu KMP
Przedstawimy teraz wersję on-line algorytmu KMP. Wczytujemy kolejne symbole i wypisujemy on-line (nabieżąco) odpowiedż:
- 0 - gdy dotychczas wczytany tekst nie zawiera x jako sufiks,
- 1 - jeśli zawiera
Algorytm On-Line-KMP
repeat forever
read();
while and do ;
;
if then
write(1); ;
else write(0);
Oznaczmy przez delay(m) maksymalną liczbę kroków algorytmu On-Line-KMP między wczytaniem symbolui daniem odpowiedzi. Przez delay'(m) oznaczmy podobną wielkość, w sytuacji gdy zamiast tablicy P' użyjemy P.
Przykład
Jeśli oraz Parser nie mógł rozpoznać (błąd składni): {\displaystyle y=a^{m-1b} , to , .
Z lematu o okresowości wynika, że zachodzi następujący fakt:
Uzasadnienie pozostawiamy jako ćwiczenie.
Wersja real-time algorytmu KMP
Pokażemy teraz wersje algorytmu on-line która działa real-time, tzn. czas reakcji między wczytaniem symbolui daniem odpowiedzi jest O(1) niezalżnie od rozmiaru alfabetu.
Algorytm zachowuje się podobnie jak algorytm On-Line-KMP, podstawowa różnica polega na tym, że algorytm wkłada do kolejki wczytane symbole, które jeszcze nie są przetworzone w sensie algorytmu KMP. Algorytm zachowuje siępodobnie jak algorytm on-line, ale wczytuje kolejne symbole z kolejki, a nie bezpośrednio z wejścia. Rysunekpokazuje relacje tego algorytmu do algorytmu KMP. Symbole z wejścia najpierw wędrują do kolejki.

Rysunek 2: Typowa konfiguracja w algorytmie real-time-KMP.
Algorytm Real-Time-KMP
inicjalizacja: ; Kolejka ;
repeat forever
read(symbol);
insert(symbol,Kolejka);
write(OUTPUT(Kolejka, j));
W celu skrócenia zapisów pojedyńczych algorytmów rozbijamy algorytm na dwie części. Zasadniczaczęść jest zapisana jako osobna funkcja OUTPUT(Kolejka,\ j). Funkcja taliczy 0 lub 1, w zależności od tego czy ostatnio wczytany symbol kończy wystąpieniewzorca x. Zmienne Kolejka, j są globalne.
Oczywistym jest że opóżnienie (czas reakcji) tego algorytmu jest O(1).
Pozostawiamy jako ćwiczenie uzasadnienie tego, że algorytm Real-Time-KMP jest poprawny.
Algorytm Real-Time-KMP: funkcja OUTPUT(Kolejka, j)
output 0;
repeat 2 times
if Kolejka niepusta then
if then
j 0; delete(Kolejka);
else if then ;
else
; delete(Kolejka);
if
output 1; j ;
return(output);
Wersja algorytmu KMP z 3/2.n porównaniami
Algorytm KMP wykonuje co najmniej 2n-m porównań symboli. Załóżmy, że są to operacje dominujące ispróbujmy zmniejszyć stały wspó:lczynnik 2 do . Na początku załóżmy, że .Następujący algorytm znajduje wszystkie wystąpienia wzorca ab w tekście y.
Algorytm Szukanie-ab
wzorcem jest
;
while do
while do;
if then
wypisz-wystąpienie;ii+2
Algorytm KMP dla wzorca ab wykonywał 2n-2 porównań symboli, nowy algorytm jest lepszy. Zachodzi fakt: algorytm Szukanie-ab wykonuje co najwyżej n porównań w tym przypadku.
Uzasadnienie pozostawimay jako ćwiczenie.
Uogólnimy algorytm na dowolne wzorce. Niech x zawiera co najmniej dwa różne symbole, , gdzie .Oznaczmy skrócony wzorzec
Przykład
, wtedy , .
Podamy nieformalny zarys działania oszczędniejszej wersji algorytmu KMP, w której osobno szukamy x' i osobno części .
Niech będzie taką wersją algorytmu KMP w której jedynie szukamy wzorca , ale tablica jest policzona względem wzorca .Jeśli i to wykonujemy przesunięcie potencjalnego początku i wzorca w y o k+1, gdzie . Inaczej mówiąc, nie szukamy wszystkich wystąpień x', ale jedynie takich, które mają sens pod względem potencjalnego znalezienia na lewo ciągu .
Tak zmodyfikowany algorytm KMP zastosujemy jako część algorytmu Oszczędny-KMP. Graficzna ilustracja działania algorytmu Oszczędny-KMP jest pokazana na rysunku.
Algorytm Oszczędny-KMP
Znajdujemy wystąpienia x' w tekście algorytmem KMP';
dla każdego wystąpienia x' sprawdzamy czy na lewo jest wystąpienie ;
nie sprawdzamy tych pozycji w y, których zgodność z pewną pozycją w x jest znana;
Rysunek 3:Typowa konfiguracja w algorytmie Oszczędny-KMP.
Pozostawiamy jako ćwiczenie dokładny zapis algorytmu w pseudokodzie oraz dowód tego, że algorytm Oszczędny-KMP wykonuje co najwyżej porównan.
Ogólna idea jest przedstawiona na rysunku.

Rysunek 4: Ilustracja tego, że liczba operacji dodatkowych jest ograniczona przez .
Niech zasadniczymi operacjami będą operacje sprawdzania pierwszego b na danej pozycji tekstu y,oraz te sprawdzania symboli ktore sa z wynikiem pozytywnym. Takich operacji jest co najwyżej n. Pozostałe operacje to
(1) sprawdzanie w części z wynikiem negatywnym, wtedy przesuwamy wzorzec co najmniej o k,
(2) sprawdzanie części na lewo od pozytywnego (w kwadraciku na rysunku), na pozycjach gdzie wcześniej było sprawdzanie negatywnego b. Wtedy odległość między pozytywnymi kolejnymi b jest co najmniej 2w, gdzie liczba sprawdzanych na lewo symboli a.Zatem lokalnie przesunięcie jest co najmniej dwukrotnie większe niż liczba dodatkowych operacji.
Suma przesunięć wzorca na tekście wynosi co najwyżej n, tak więc sumaryczna liczba dodatkowych operacji jest co najwyżej , a liczb wszstkich nie przekracza .
Równoważność cykliczna słów
Pokażemy problem, który prawdopodobie najlepiej pokazuje użyteczność porządku liniowego na alfabecie. Rotacją słowa jest kaz'rde słowo postaci . (w szczególności . Niech będą słowami długości , mówimy, że są one cyklicznie równoważne gdy dla pewnych .
Naturalnym algorytmem sprawdzania cyklicznej równoważności jest szukanie słowa w słowie , ale podamy algorytm znacznie prostszy bazujący na porządku leksykograficznym , który będzie działal w czasie liniowym i w miejscu (dodatkowa pamięć jest stała).
W algorytmie roszerzamy tablice na ale robimy to jedynie dla uproszczenia, w rzeczywistości możemy poruszać się cyklicznie po i po , pozostawiamy modyfikację jako ćwiczenie.
Algorytm Równoważność-Cykliczna
; ;
; ;
while and do
;
while do ;
if then return true;
if then else ;
return false;
Problem poprawności pozostawiamy jako ćwiczenie.
Liczba porównań jest oczywiście liniowa. Pozostawiamy jako ćwiczenie policzenie dokładnego wzoru na maksymalną liczbę porównań symboli dla tekstów długości .