Algorytmy i struktury danych/Algorytmy tekstowe I: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Tprybick (dyskusja | edycje)
Tprybick (dyskusja | edycje)
Linia 191: Linia 191:


==Wersja algorytmu KMP z <math>\frac{3}{2}n</math> porównaniami==
==Wersja algorytmu KMP z <math>\frac{3}{2}n</math> 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 <math>\frac{3}{2}</math>. Na początku załóżmy, że <math>x=ab</math>.Następujący algorytm znajduje wszystkie wystąpienia wzorca ab w tekście y.\myskip<!--%--><!--%------------------------------------------------------------------->\begin{center}\fbox{\begin{minipage}{12cm}\vskip0.3cm\hspace*{0.6cm}\textbf{Algorithm} Szukanie-ab; \\wzorcem jest <math>ab</math> %\{ algorithm of Morris and Pratt \}\\\hspace*{1.2cm}<math>i:=0</math>; ;\\\hspace*{1.2cm}\textbf{while} <math>i\leq n-m</math> \textbf{do }\\\hspace*{1.8cm}\textbf{while} <math>y[i+2]\ne b</math> {do} \<math>i=i+1</math>;\\\hspace*{1.8cm}\textbf{if} <math>y[i+1]= a</math> \textbf{then }\\\hspace*{2.4cm} wypisz-wystąpienie; i:=i+2;\\\vskip0.4cm\end{minipage}}\end{center}<!--%------------------------------------------------------------------->\myskipAlgorytm KMP dla wzorca ab wykonywał 2n-2 porównań symboli, nowy algorytm jest lepszy. Zachodzi fakt:
algorytm Szukanie-abwykonuje co najwyżej n porównań w tym przypadku. \myskip\noindent Uzasadnienie pozostawimay jako ćwiczenie.\myskipUogólnimy algorytm na dowolne wzorce. Niech x zawiera co najmniej dwa różne symbole, \ <math>x=a^kb\alpha</math>, gdzie <math>a\ne b</math>.Oznaczmy <math>x'=b\alpha</math> ({\em skrócony wzorzec}).\myskip'''Przykład.'''\ <math>x\ =\ aaaabaaaababa</math>, wtedy <math>x'\ =\ baaaababa</math>, <math>\alpha\ =\ aaaababa</math>.\myskipPodamy nieformalny zarys działania oszczędniejszej wersji algorytmu KMP, w której osobno szukamy x' i osobno części <math>a^k</math>. \myskip
Niech <math>KMP'</math> będzie taką wersją algorytmu KMP w której jedynie szukamy wzorca <math>x'</math>, ale tablica <math>P'</math> jest policzona względem wzorca <math>x</math>.Jeśli <math>j>0</math> i <math>shift\le k</math> to wykonujemy przesunięcie potencjalnego początku i wzorca w y o k+1, gdzie <math>shift=j-P'[j]</math>. 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 <math>a^k</math>.\myskipTak zmodyfikowany algorytm KMP zastosujemy jako część algorytmu Oszczędny-KMP.
\noindent Graficzna ilustracja działania algorytmu Oszczędny-KMP jest pokazana na rysunku.\myskip '''Algorytm''' Oszczędny-KMP;\begin{description}\item\hspace*{0.7cm}Znajdujemy wystąpienia x' w tekście <math>y[k+1..m]</math> algorytmem KMP';\\dla każdego wystąpienia x' sprawdzamy czy na lewo jest wystąpienie <math>a^k</math>;\\nie sprawdzamy tych pozycji w  y, których zgodność z pewną pozycją w x jest znana; \end{description}


\begin{figure}[hbt]\begin{center}\includegraphics[width=5.9in]{teksty_fig5.eps}\caption{Typowa konfiguracja w algorytmie Oszczędny-KMP.<span id="real-time-KMP" \> \end{center}\end{figure}
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 <math>\frac{3}{2}</math>. Na początku załóżmy, że <math>x=ab</math>.Następujący algorytm znajduje wszystkie wystąpienia wzorca ab w tekście y.
<!--%********************-->\noindent Pozostawiamy jako ćwiczenie dokładny zapis algorytmu w pseudokodzie oraz dowód tego, że algorytm Oszczędny-KMP wykonuje co najwyżej <math>\frac{3}{2}n</math> porównan. \myskipOgólna idea jest przedsatwiona na rysunku.  


\begin{figure}[hbt]                                                                                                                    \begin{center}                                                                                                                          \includegraphics[width=5.9in]{teksty_fig6.eps}                                                                                          \caption{Ilustracja tego, że liczba operacji dodatkowych jest ograniczona przez <math>\frac{1}{2}n</math>.}  <span id="real-time-KMP" \>  
{{algorytm|Szukanie-ab|algorytm_szukanie_ab|
\end{center}                                                                                                                                                                
wzorcem jest <math>ab</math> <br>
\end{figure}                                                                                                                                                                                                                                                                                                                                               %********************
<math>i:=0</math>; <br>
'''while''' <math>i\leq n-m</math> '''do'''<br>
&nbsp;&nbsp;&nbsp;'''while''' <math>y[i+2]\ne b</math> '''do'''<math>i=i+1</math>;<br>
&nbsp;&nbsp;&nbsp;'''if''' <math>y[i+1]= a</math> '''then''' <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wypisz-wystąpienie;i<math>:=</math>i+2
}}


Algorytm KMP dla wzorca ab wykonywał 2n-2 porównań symboli, nowy algorytm jest lepszy. Zachodzi fakt:
&nbsp;&nbsp;&nbsp;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,  <math>x=a^kb\alpha</math>, gdzie <math>a\ne b</math>.Oznaczmy <math>x'=b\alpha</math> ''skrócony wzorzec''
{{przyklad|||
<math>x\ =\ aaaabaaaababa</math>, wtedy <math>x'\ =\ baaaababa</math>, <math>\alpha\ =\ aaaababa</math>.
}}
Podamy nieformalny zarys działania oszczędniejszej wersji algorytmu KMP, w której osobno szukamy x' i osobno części <math>a^k</math>.
Niech <math>KMP'</math> będzie taką wersją algorytmu KMP w której jedynie szukamy wzorca <math>x'</math>, ale tablica <math>P'</math> jest policzona względem wzorca <math>x</math>.Jeśli <math>j>0</math> i <math>shift\le k</math> to wykonujemy przesunięcie potencjalnego początku i wzorca w y o k+1, gdzie <math>shift=j-P'[j]</math>. 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 <math>a^k</math>.
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|algorytm_okmp|
Znajdujemy wystąpienia x' w tekście <math>y[k+1..m]</math> algorytmem KMP';<br>
dla każdego wystąpienia x' sprawdzamy czy na lewo jest wystąpienie <math>a^k</math>;<br>
nie sprawdzamy tych pozycji w  y, których zgodność z pewną pozycją w x jest znana; <br>
[[Grafika:Okmp.png]]<br>
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 <math>\frac{3}{2}n</math> porównan.
Ogólna idea jest przedstawiona na rysunku.
<center>[[Grafika:Okmp2.png]]<br>Rysunek 4: Ilustracja tego, że liczba operacji dodatkowych jest ograniczona przez <math>\frac{1}{2}n</math>.</center>


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  
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 <math>\alpha</math> z wynikiem negatywnym, wtedy przesuwamy wzorzec co najmniej o k,
(1) sprawdzanie w części <math>\alpha</math> z wynikiem negatywnym, wtedy przesuwamy wzorzec co najmniej o k,
(2) sprawdzanie części <math>a^k</math> na lewo od {\em pozytywnego} <math>b</math> (w kwadraciku na rysunku), na pozycjach gdzie wcześniej było sprawdzanie{\em negatywnego} b. Wtedy odległość między pozytywnymi kolejnymi b jest co najmniej 2w, gdzie <math>w\le k</math> liczba sprawdzanych na lewo symboli a.Zatem lokalnie przesunięcie jest co najmniej dwukrotnie większe niż liczba dodatkowych operacji.
 
\noindent Suma przesunięć wzorca na tekście <math>y</math> wynosi co najwyżej n, tak więc sumaryczna liczba  dodatkowych   operacjijest co najwyżej <math>\frac{1}{2}n</math>, a liczb wszstkich nie przekracza <math>\frac{3}{2}n</math>.
(2) sprawdzanie części <math>a^k</math> na lewo od ''pozytywnego'' <math>b</math> (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 <math>w\le k</math> 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 <math>y</math> wynosi co najwyżej n, tak więc sumaryczna liczba  dodatkowych operacji jest co najwyżej <math>\frac{1}{2}n</math>, a liczb wszstkich nie przekracza <math>\frac{3}{2}n</math>.

Wersja z 12:52, 8 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 n=|x| 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 x jest każda liczba naturalna niezerowa p taka, żex[i]=x[i+p], 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 nwd(p,q) oznaczanajmnieszy wspólny dzielnik p,q.


Lemat [Lemat o okresowości]

Jeśli x ma okresy p, q oraz p+q|x| to nwd(p,q) 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 p>q 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 p+q|x|+nwd(p,q) to nwd(p,q) 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 |x|per(x) jest długością prefikso-sufiksu x.Jeśli per(x)=|x| to prefikso-sufiksem x jest słowo puste o długości zerowej.

Oznaczmy przez P[k] rozmiar prefikso-sufiksu x[1..k], zatem per(x)=nP[n], gdzie n=|x|.


Przykład

Dla x = abababababb mamy:

P[1..11] = [0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0].

Wartość P[0] jest warością sztuczną (przyjmiemy potem P[0]=1).

Liczenie tablicy Prefisko-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:

x[j]=x[t+1] oraz t=P[j1]  P[j]=t+1

W algorytmie do liczenia P[j] korzystamy z wartości P[k] dla k<j.

Algorytm Prefikso-Sufiksy


P[0]:=1; t:=1;
for j:=1 to m do
   while t0 and x[t+1]x[j] do t:=P[t]
   t:=t+1; P[j]:=t;

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 t:=P[t] zmniejsza wartość t co najmniej o jeden. Prostezastosowanie zasady magazynu (lub potencjału) implikuje, że operacji t:=P[t] wykonujemy conajwyżej n. Dowód poprawności pozostawiamy jako ćwiczenie.

Tablica Silnych Prefisko-Sufiksów

Wprowadzimy silną tablicę prefikso-sufisów dla wzorca x[1..m]:    jeśli j<|x| to P[j]=k, gdzie k jest maksymalnym rozmiarm słowa będącego prefiksem i sufiksem x[1..j]najdłuższego własciwegoi spełniającego dodatkowy warunek x[k+1]x[j+1] dla j<n.
Jeśli takiego k nie ma toprzyjmujemy P[j]=1. Przyjmujemy ponadto, że P[m]=P[m].

Wartości tablicy P' mogą być znacznie mniejsze niż wartości tablicy P.

Przykład

Dla x = abaab mamy:

P[0..5] = [1, 0, 0, 1, 1, 2 ];  P[0..5] = [1, 0, 1, 1, 0, 2 ].

Algorytm bazuje na następującej relacji między P i P':

(t=P[j] oraz x[t+1]x[j+1])  P[j]=t


(t=P[j], t0, oraz x[t+1]=x[j+1])  P[j]=P[t]


Nie musimy liczyć tablicy P, potrzebna jest jedynie ostatnia wartość t=P[j], którą liczymy on-line.


Algorytm Silne-Prefikso-Sufiksy


P[0]:=1; t:=1;
for j:= 1 to m do // t=P[j1]
   while t0 and x[t+1]x[j]do
      t:=P[t];
   t:=t+1;
   if j=m or x[t+1]x[j+1]
      then P[j]:=t else P[j]:=P[t];

Gdyweżmiemy x = abam2 to P[0]=1, P[1]=0, P[2]=1,oraz P[j]=1, dla 3jm. To jest pesymistyczny przypadek dla algorytmu Silne-Prefikso-Sufiksy, algorytm wykonuje3m5 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 y wszystkie (lub pierwsze) wystąpienia danego tekstu x, zwanego wzorcem (ang. pattern).

Oznaczmy m=|x|,n=|y|, gdzie mn.

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 j+1 we wzorcu x, oraz na pozycji i+j+1 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


i:=0; j:=0;
while inm do
   while j<m and x[j+1]=y[i+j+1] do j=j+1;
   if j=m then return(true);
   i:=i+jP[j]; j:=max(0,P[j])

Operacją dominującą w algorytmie jest operacja: x[j+1]=y[i+j+1].

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 i 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 x=ab, y=aa..a 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.

Rysunek 1: Jedna iteracja algorytmu KMP. Przesunięcie shift=jP[j] potencjalnego początku wystąpienia wzorca gdy x[j+1]y[i+j+1].

Wersja on-line algorytmu KMP

Przedstawimy teraz wersję on-line algorytmu KMP. Wczytujemy kolejne symbole y 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(symbol);
   while j>1 and x[j+1]symbol do j:=P[j];
   j:=j+1;
   if j=m then
      write(1); j:=P[m];
   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 x=aaaaa oraz Parser nie mógł rozpoznać (błąd składni): {\displaystyle y=a^{m-1'''b} , to delay(m)=O(1), delay(m)=Θ(m).

Z lematu o okresowości wynika, że zachodzi następujący fakt:

delay(m) = O(logm)

Uzasadnienie pozostawiamy jako ćwiczenie.

Słowa Fibonacciego definiujemy następująco:

F0=a, F1=ab, Fn+1 = FnFn1

Na przykład: F3=abaab, F4=abaababa, F5=abaababaabaab.

Niech F'n oznacza słowo Fibonacciego z obciętymi ostatnimi dwoma symbolami. Jeśli jako wzorzec weżmiemy słowo Fibonacciego Fn, a jako tekst słowo F'ncc to przy wczytywaniu |Fn1|-ego symbolu algorytm ma opóżnienie logarytmiczne, iterujemy Ω(logn) razy operację: j:=P[j]. Uzasadnienie pozostawiamy jako ćwiczenie.

Przy okazji wprowadzenia słów Fibonacciego zostawiamy jako ćwiczenie podaniewzoru na tablice P i P' dla słów Fibonacciego, we wzorze możemy używać liczb Fibonacciego.W związku z tym proponujemy jako ćwiczenie napisanie wersji algorytm KMP dla wzorca będącego słowem Fibonacciego w czasie liniowym i bez dodatkowej tablicy (typu P lub P').

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).

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: j:=0; 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 j=1 then
         j := 0; delete(Kolejka);
      else if x[j+1]first(Kolejka) then j:=P[j];
      else
         j:=j+1; delete(Kolejka);
         if j=m
            output :=1; j :=P[m];
return(output);


Wersja algorytmu KMP z 32n 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 32. Na początku załóżmy, że x=ab.Następujący algorytm znajduje wszystkie wystąpienia wzorca ab w tekście y.

Algorytm Szukanie-ab


wzorcem jest ab
i:=0;
while inm do
   while y[i+2]b doi=i+1;
   if y[i+1]=a then
      wypisz-wystąpienie;i:=i+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, x=akbα, gdzie ab.Oznaczmy x=bα skrócony wzorzec

Przykład

x = aaaabaaaababa, wtedy x = baaaababa, α = aaaababa.


Podamy nieformalny zarys działania oszczędniejszej wersji algorytmu KMP, w której osobno szukamy x' i osobno części ak.


Niech KMP będzie taką wersją algorytmu KMP w której jedynie szukamy wzorca x, ale tablica P jest policzona względem wzorca x.Jeśli j>0 i shiftk to wykonujemy przesunięcie potencjalnego początku i wzorca w y o k+1, gdzie shift=jP[j]. 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 ak.

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 y[k+1..m] algorytmem KMP';
dla każdego wystąpienia x' sprawdzamy czy na lewo jest wystąpienie ak;
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 32n porównan.

Ogólna idea jest przedstawiona na rysunku.


Rysunek 4: Ilustracja tego, że liczba operacji dodatkowych jest ograniczona przez 12n.

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 ak na lewo od pozytywnego b (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 wk 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 y wynosi co najwyżej n, tak więc sumaryczna liczba dodatkowych operacji jest co najwyżej 12n, a liczb wszstkich nie przekracza 32n.