Andrzej Jastrz bski Akademia ETI
Wyszukiwanie wzorca Wyszukiwaniem wzorca nazywamy sprawdzenie, czy w podanym tekscie T znajduje si podci g P. Szukamy sªowa kot: Ala ma kota, kot ma ale.
Algorytm naiwny Algorytm ten sprawdza wszystkie podci gi tekstu T o dªugo±ci takiej jak P i sprawdza czy s identyczne z P. Zªo»ono± tego algorytmu to O(n m), gdzie n to dªugo± tekstu, m dªugo± wzorca.
void find(char txt[], char wz[]) { int i,j; int len_txt = strlen(txt); int len_wz = strlen(wz); for(i=0; i<=len_txt-len_wz; i++) { for(j=0; j<len_wz; j++) { if(txt[i+j]!=wz[j]) break; if(j==len_wz) printf("wzorzec na miejscu %d", i);
void find(const string &txt, const string &wz) { int i,j; for(i=0; i<=txt.length()-wz.length(); i++) { for(j=0; j<wz.length(); j++) { if(txt[i+j]!=wz[j]) break; if(j==wz.length()) cout << "wzorzec na miejscu " << i;
Algorytm RabinaKarpa Algorytm RabinaKarpa u»ywa do wyszukiwania wzorca pewnej heurystyki (funkcji dobroci) H(x). Algorytm wylicza funkcj dla P oraz dla ka»dego podci gu tekstu T o dªugo±ci takiej jak P. Je±li warto± heurystyki pewnego podci gu jest równa H(P), to sprawdzamy czy ten podci g jest równy P. Pesymistyczna zªo»ono± algorytmu to O(m n), ale ±rednia zªo»ono± jest du»o lepsza.
Heurystyka u»ywana w algorytmie Funkcja musi si dawa ªatwo oblicza, poniewa» obliczamy kolejne warto±ci heurystyki w ka»dym podci gu tekstu T. Niech k, p b d dowolnymi liczbami wzgl dnie pierwszymi. Niech m b dzie dªugo±ci wzorca P. P(A) = P[0] k m 1 + P[1] k m 2 +... +P[m 2] k + P[m 1] (mod p)
Obliczanie kolejnych wyrazów Je±li h 0 jest warto±ci heurystyki pierwszego podci gu, h 1 drugiego itd., to ªatwo mo»na obliczy h i+1 maj c h i. h i = T [i] k m 1 + T [i + 1] k m 2 + +... + T [i + m 2] k + T [i + m 1] (mod p) h i+1 = T [i + 1] k m 1 + T [i] k m 2 + Z tego wynika,»e +... + T [i + m 1] k + T [i + m] (mod p) h i+1 k h i = T [i + m] T [i] k m (mod p)
Na nast pnym slajdzie znajduj si procedury pomocnicze dla algorytmu Rabina-Karpa. obl_heur jest procedur obliczaj c pierwsz warto± heurystyki. Jest to algorytm Hornera obliczania warto±ci wielomianu. obl_pot obliczanie reszty z dzielenia pot gi (k m mod p); przedstawiony algorytm nie jest najszybszym znanym algorytmem pot gowania. Procedura obl_pot zwraca p (k m mod p), aby obliczenia nie wykonywaªy si na liczbach ujemnych.
int obl_heur(char txt[], int len_txt, int k, int p) { int i, odp = 0; for(i=0; i<len_txt; i++) { odp *= k; odp += txt[i]; odp %= p; return odp; int obl_pot(int k, int p, int pot) { int i, odp=1; for(i=0; i<pot; i++) { odp *= k; odp %= p; return p-odp;
int obl_heur(const string &txt, int m, int k, int p) { int i, odp = 0; for(i=0; i<m; i++) { odp *= k; odp += txt[i]; odp %= p; return odp; int obl_pot(int k, int p, int pot) { int i, odp=1; for(i=0; i<pot; i++) { odp *= k; odp %= p; return p-odp;
void findrk(char txt[], char wz[], int k, int p) { int i,j; int len_txt = strlen(txt); int len_wz = strlen(wz); int heur = obl_heur(wz, len_wz, k, p); int heur_txt = obl_heur(txt, len_wz, k, p); int k_m = obl_odwr(k, p, len_wz); for(i=0; i<=len_txt-len_wz; i++) { if(heur==heur_txt) { for(j=0; j<len_wz; j++) if(txt[i+j]!=wz[j]) break; if(j==len_wz) printf("wzorzec na miejscu %d", i); heur_txt = (k*heur_txt+txt[i+len_wz]+txt[i]*k_m)%p;
void findrk(const string &txt, const string &wz, int k, int p) { int i,j; int heur = obl_heur(wz, wz.length(), k, p); int heur_txt = obl_heur(txt, wz.length(), k, p); int k_m = obl_odwr(k, p, wz.length()); for(i=0; i<=txt.length()-wz.length(); i++) { if(heur==heur_txt) { for(j=0; j<wz.length(); j++) if(txt[i+j]!=wz[j]) break; if(j==wz.length()) cout << "wzorzec na miejscu " << i; heur_txt = (k*heur_txt+txt[i+wz.length()] +txt[i]*k_m)%p;
Wyszukiwanie wzorca przy pomocy automatu Automat to maszyna logiczna posiadaj ca sko«czon liczb stanów oraz reguª, które powoduj ustalon (deterministyczn ) zmian stanu. Na podstawie wzorca mo»na stworzy automat poszukuj cy wzorca.
Automat do wyszukiwania wzorca 'aabaabc' a a a b a a b c 0 1 2 3 4 5 6 7.. a...... a Stan 7 oznacza znalezienie wzorca w wyszukiwanym tek±cie. Kropki przy kraw dziach oznaczaj inne litery ni» podane przy kraw dziach wyj±ciowych np. przy stanie 6 kropka oznacza litery inne ni» a,c; przy stanie 4 litery ro»ne od a.
W prezentacji nie b dziemy przedstawia procedury do zmiany stanów ch_stan jak i procedury do tworzenia tablicy przej± stanów.
void find(char txt[], int len_wz) { int i,stan=0; int len_txt = strlen(txt); for(i=0; i<len_txt; i++) { stan = ch_stan(stan, txt[i]); if(stan==len_wz) printf("wzorzec na miejscu %d", i-len_wz);
void find(const string &txt, int len_wz) { int stan=0; for(int i=0; i<txt.length(); i++) { stan = ch_stan(stan, txt[i]); if(stan==len_wz) cout << "wzorzec na miejscu " << i-len_wz;
Algorytm Knutha-Morrisa-Pratta Jest to algorytm podobny do algorytmu z automatem, ale tworzenie automatu jest tu sprytniejsze i szybsze. Zwi zane jest to z przypisywaniem podobie«stwa pomi dzy pocz tkowymi, a kolejnymi elementami tablicy wzorca.
int* get_tab_stan(char wz[]) { int len_wz = strlen(wz); int *tab_stan = (int*) malloc((len_wz+1)*sizeof(int)); int stan = tab_stan[0] = -1; int i=0; while(i<len_wz) { while(stan>=0 && wz[i]!=wz[stan]) stan = tab_stan[stan]; i++; stan++; if(wz[i]==wz[stan]) tab_stan[i] = tab_stan[stan]; else tab_stan[i] = stan; return tab_stan;
void find(char txt[], char wz[]) { int i = 0, stan = 0; int *tab_stan = get_tab_stan(wz); int len_txt = strlen(txt); int len_wz = strlen(wz); while(i<len_txt) { while(stan>=0 && wz[stan]!=txt[i]) stan = tab_stan[stan]; i++; stan++; if(stan==len_wz) { printf("wzorzec na miejscu %d", i-len_wz+1); stan = tab_stan[stan]; free(tab_stan);
vector<int> get_tab_stan(const char &wz) { vector<int> tab_stan(wz.length()+1); int stan,i=0; stan = tab_stan[0] = -1; while(i<wz.length()) { while(stan>=0 && wz[i]!=wz[stan]) stan = tab_stan[stan]; i++; stan++; if(wz[i]==wz[stan]) tab_stan[i] = tab_stan[stan]; else tab_stan[i] = stan; return tab_stan;
void find(const string &txt, const string &wz) { int i = 0, stan = 0; vector<int> tab_stan = get_tab_stan(wz); while(i<txt.length()) { while(stan>=0 && wz[stan]!=txt[i]) stan = tab_stan[stan]; i++; stan++; if(stan==wz.length()) { cout << "wzorzec na miejscu " << i-wz.length()+1; stan = tab_stan[stan];
Mo»na zauwa»y,»e powy»sze procedury wyg daj bardzo podobnie. Procedura get_tab_stan wyszukuje samopodobie«stwa we wzorcu, natomiast procedura find wyszukuje podobie«stwa pomi dzy wzorcem a tekstem. Tablica przej± dla wzorca 'aabaabac' a a b a a b a c 1 0 1 0 1 2 3 4 0 0 1 2 3 4 5 6 7 8 Tablica przej± dla wzorca 'aabaabaa' a a b a a b a a 1 0 1 0 1 2 3 4 5 0 1 2 3 4 5 6 7 8