|
Serwis Edukacyjny w I-LO w Tarnowie
Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
ProblemW łańcuchu s należy wyznaczyć wszystkie
wystąpienia |
Zadanie znajdowania wzorca w łańcuchu rozwiązuje algorytm opracowany przez
Załóżmy, iż poszukujemy pierwszego wystąpienie wzorca
p w danym łańcuchu
tekstowym s. W trakcie porównywania kolejnych znaków łańcucha ze znakami
wzorca natrafiliśmy na sytuację, w której pewien prefiks wzorca
p, o długości b znaków, pasuje do prefiksu okna w łańcuchu
s przed pozycją

Algorytm N w takiej sytuacji przesuwa okno
wzorca o jedną pozycję w prawo względem przeszukiwanego tekstu i rozpoczyna od początku porównywanie znaków wzorca
p ze znakami okna nie
korzystając zupełnie z faktu zgodności części znaków. To marnotrawstwo prowadzi
w efekcie do klasy złożoności obliczeniowej

Dzięki temu podejściu pomijamy niepotrzebne porównania znaków
oraz unikamy cofania się
Dla każdego prefiksu wzorca szerokość maksymalnego
bb = Π[b]
Teraz porównujemy znak
Jeśli otrzymamy zgodność, to pasujący prefiks zwiększa swoją długość o 1 znak. Przesuwamy również indeks i o 1, ponieważ znak na tej pozycji został już całkowicie wykorzystany przez algorytm MP.
Jeśli prefiks obejmie cały wzorzec
Zwróć uwagę, iż algorytm MP nigdy nie cofa indeksu i. Dzięki tej własności algorytm umożliwia przetwarzanie danych sekwencyjnych – np. wyszukiwanie położenia wzorca w dużym pliku, który fizycznie może nie mieścić się w pamięci operacyjnej komputera – każdy znak pliku jest odczytywany tylko jeden raz.
K01: Wyznacz tablicę Π ; wyznaczamy tablicę maksymalnych prefikso-sufiksów K02: pp ← -1 ; wstępna pozycja wzorca ustawiona na -1 K03: b ← 0 ; wstępną długość prefikso-sufiksu ustawiamy na 0 K04: Dla i = 0, 1, …|s|-1: ; pętla wyznacza znaki łańcucha do porównania wykonuj kroki K05…K10 ; ze znakami wzorca K05: Dopóki (b > -1)(p[b] ≠ s[i]), ; Szukamy we wzorcu p rozszerzalnego wykonuj b ← Π[b] ; prefiksu pasującego do prefiksu okna wzorca. ; Pętlę K05 przerywamy, jeśli znajdziemy ; rozszerzalny prefiks lub napotkamy wartownika -1 K06: b ← b+1 ; Rozszerzamy prefiks o 1 znak. Jeśli prefiks był ; wartownikiem, to otrzymuje wartość 0. K07: Jeśli b < |p|, ; Jeśli prefiks nie obejmuje całego wzorca, to następny obieg pętli K04 ; to kontynuujemy pętlę K04, czyli porównujemy ; znak p[b] z kolejnym znakiem łańcucha s. K08: pp ← i-b+1 ; wyznaczamy pozycję wzorca p w łańcuchu s K09: Pisz pp ; wyprowadzamy tę pozycję K10: b ← Π[b] ; redukujemy b do długości prefikso-sufiksu wzorca K11: Jeśli pp = -1, ; jeśli wzorzec p nie występuje w s, wyprowadzamy -1 to pisz -1 K12: Zakończ
Uwaga: Porównaj algorytm MP wyszukiwania wzorca z algorytmem wyznaczania
tablicy
|
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
| Program generuje |
Pascal// Wyszukiwanie wzorca algorytmem MP
// Data: 3.06.2008
// (C)2020 mgr Jerzy Wałaszek
//----------------------------------
program prg;
const
N = 79; // długość łańcucha s
M = 5; // długość wzorca p
var
s, p : ansistring;
PI : array [0..M] of integer;
i, b, pp : integer;
begin
randomize;
// generujemy łańcuch s
s := '';
for i := 1 to N do
s := s+chr(65+random(2));
// generujemy wzorzec
p := '';
for i := 1 to M do
p := p+chr(65+random(2));
// dla wzorca obliczamy tablicę PI[]
PI[0] := -1;
b := -1;
for i := 1 to M do
begin
while(b > -1) and (p[b+1] <> p[i]) do
b := PI[b];
inc(b); PI[i] := b;
end;
// wypisujemy wzorzec p
writeln(p);
// wypisujemy łańcuch s
writeln(s);
// poszukujemy pozycji wzorca w łańcuchu
pp := 0; b := 0;
for i := 1 to N do
begin
while(b > -1) and (p[b+1] <> s[i]) do
b := PI[b];
inc(b);
if b = M then
begin
while pp < i-b do
begin
write(' '); inc(pp);
end;
write('^'); inc(pp);
b := PI[b];
end
end;
writeln;
end. |
// Wyszukiwanie wzorca algorytmem MP
// Data: 3.06.2008
// (C)2020 mgr Jerzy Wałaszek
//----------------------------------
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
const int N = 79; // długość łańcucha s
const int M = 5; // długość wzorca p
int main()
{
string s, p;
int PI[M+1], i, b, pp;
srand(time(NULL));
// generujemy łańcuch s
s = "";
for(i = 0; i < N; i++)
s += 65+rand() % 2;
// generujemy wzorzec
p = "";
for(i = 0; i < M; i++)
p += 65+rand() % 2;
// dla wzorca obliczamy tablicę PI[]
PI[0] = b = -1;
for(i = 1; i <= M; i++)
{
while((b > -1) && (p[b] != p[i-1]))
b = PI[b];
PI[i] = ++b;
}
// wypisujemy wzorzec
cout << p << endl;
// wypisujemy łańcuch s
cout << s << endl;
// poszukujemy pozycji wzorca w łańcuchu
pp = b = 0;
for(i = 0; i < N; i++)
{
while((b > -1) && (p[b] != s[i]))
b = PI[b];
if(++b == M)
{
while(pp < i-b+1)
{
cout << " "; pp++;
}
cout << "^"; pp++;
b = PI[b];
}
}
cout << endl;
return 0;
} |
Basic' Wyszukiwanie wzorca algorytmem MP
' Data: 3.06.2008
' (C)2020 mgr Jerzy Wałaszek
'----------------------------------
Const N = 79 ' długość łańcucha s
Const M = 5 ' długość wzorca p
Dim As String s, p
Dim As Integer PI(M), i, b, pp
Randomize
' generujemy łańcuch s
s = ""
For i = 1 To N
s += Chr(65+Cint(Rnd))
Next
' generujemy wzorzec
p = ""
For i = 1 To M
p += Chr(65+Cint(Rnd))
Next
' dla wzorca obliczamy tablicę PI[]
PI(0) = -1: b = -1
For i = 1 To M
While (b > -1) And _
(Mid(p, b+1, 1) <> Mid(p, i, 1))
b = PI(b)
Wend
b += 1: PI(i) = b
Next
' wypisujemy wzorzec p
Print p
' wypisujemy łańcuch s
Print s
' poszukujemy pozycji wzorca w łańcuchu
pp = 0: b = 0
For i = 1 To N
While (b > -1) And _
(Mid(p, b+1, 1) <> Mid(s, i, 1))
b = PI(b)
Wend
b += 1
If b = M Then
While pp < i-b
Print " ";: pp += 1
Wend
Print "^";: pp += 1
b = PI(b)
End If
Next
Print
End |
Python
(dodatek)# Wyszukiwanie wzorca algorytmem MP
# Data: 7.03.2024
# (C)2024 mgr Jerzy Wałaszek
#----------------------------------
import random
N = 79 # długość łańcucha s
M = 5 # długość wzorca p
# generujemy łańcuch s
s = ""
for i in range(N):
s += chr(random.randrange(65, 67))
# generujemy wzorzec
p = ""
for i in range(M):
p += chr(random.randrange(65, 67))
# dla wzorca obliczamy tablicę PI[]
tpi = [-1]
b = -1
for i in range(1, M+1):
while (b > -1) and (p[b] != p[i-1]):
b = tpi[b]
b += 1
tpi.append(b)
# wypisujemy wzorzec p
print(p)
# wypisujemy łańcuch s
print(s)
# poszukujemy pozycji wzorca w łańcuchu
pp = 0
b = 0
for i in range(N):
while (b > -1) and (p[b] != s[i]):
b = tpi[b]
b += 1
if b == M:
while pp < i-b+1:
print(" ", end="")
pp += 1
print("^", end="")
pp += 1
b = tpi[b]
print()
|
| Wynik: |
BBABA
BBBBAAABAABABBBABABAAABABBBABABAAABBAAABABBBBAAABAAAABBABBAABABBBBBBABAAABBBABA
^ ^ ^ ^
|
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.