Knuth-Morris-Pratt algoritmus KMP féle sztringkereső algoritmus Szükséges matematikai fogalmak: Legyen Ω egy ábécé és x=x1x2…xn, k∈N karakterekből álló sztring, melynek elemei (xi) az Ω ábécé betűi. Az x sztringnek u-val jelölt részsztringjét x prefixének nevezzük, ha u=x1…xb, 0<=b<=k. Az x sztringnek u-val jelölt részsztringjét x suffixének nevezzük, ha u=xk-b+1…xk, 0<=b<=k. Az x-nek egy u prefixet vagy suffixet valódi prefixnek ill. valódi suffixnek nevezzük, ha u≠x, azaz ha b<k. Ha b=0, akkor u az üres sztring (u=ε). Az r sztringet az x egy borderének nevezzük, ha r megegyezik x egy valódi prefixével és egy valódi suffixével is. 1 23:06:19
Knuth-Morris-Pratt algoritmus Példa X=abacab 6 db valódi prefixe van: ε, a, ab, aba, abac, abaca 6 db valódi suffice van: ε, b, ab, cab, acab, bacab Borderek: ε, ab Az üres sztring (ε), minden legalább 1 hosszúságú Ω ábécé feletti sztringnek bordere. Ugyanakkor ε-nak nincs bordere. 23:06:19 23:06:19 2
Knuth-Morris-Pratt algoritmus Az alapsztringben megtartjuk azt a pozíciót, amelyen áll. A mintát pedig úgy toljuk arrébb, hogy a pozíciónktól balra továbbra is fennálljon az egyezés. Mekkora legyen a léptetés? A bacbababaabcbab ↕↕↕↕↕↕ P ababaca P ababaca P ababaca 23:06:19 23:06:19 3
Knuth-Morris-Pratt algoritmus ababaca, ababaca, ababaca, ababaca ababaca, ababaca, ababaca Megoldás: A minta léptetésének mértékét a minta egyező prefixenek a legszélesebb bordere határozza meg. Ebben a példában az egyező prefix hossza 5. Ennek a leghosszabb bordere pedig 3. A léptetés teljes mértéke 5-3=2. Előfordulhat, hogy ezután sem lesz egyezés. Ekkor még inkább jobbra kell a mintát csúsztatni. Újabb egyező bordereket keresve. (Újabb léptetések: 3-2=1, ill. 1-0=1.) 23:06:19 23:06:19 4
KMP és mezítlábas algoritmusok A bacbababaabcbab ↕ P ababaca 1+2+1+1+6+0+1 ↕↕↕↕ 1+2+1+1+6+1+4 A bacbababaabcbab P ababaca 1+2+1+1+6+0+1+0 ↕ 1+2+1+1+6+1+4+1 A bacbababaabcbab ↕ P ababaca 1+2+1+1+6+0+1+0+1=13 ↕↕ 1+2+1+1+6+1+4+1+2=19 A bacbababaabcbab ↕↕↕↕↕↕ P ababaca 1+2+1+1+6 A bacbababaabcbab P ababaca 1+2+1+1+6+0 ↕ 1+2+1+1+6+1 A bacbababaabcbab ↕↕↕↕↕↕ P ababaca 1+2+1+1+6 A bacbababaabcbab ↕ P ababaca 1 A bacbababaabcbab ↕ P ababaca 1+2+1+1 A bacbababaabcbab ↕↕ P ababaca 1+2 A bacbababaabcbab ↕ P ababaca 1+2+1 23:06:19
Knuth-Morris-Pratt algoritmus Legyen x egy hosszú sztring. Legyen az x sztringnek r is és s is egy bordere, úgy hogy |r|<|s|. x=abacabacaba s=abacaba r=aba Ekkor belátható, hogy r bordere az s-nek is: r prefixe volt x-nek, a hosszuk miatt (|r|<|s|) látható, hogy s-nek is. A suffixre ez hasonlóan belátható. Ha s a legszélesebb bordere x-nek, akkor az x következő (második legszélesebb) bordere az s legszélesebb bordere lesz. 23:06:19 23:06:19 6
Knuth-Morris-Pratt algoritmus A minta egy x prefixének az r bordere, néha bővíthető az a karakterrel úgy, hogy ra bordere xa-nak. (Ha szerencsénk van, a minta a-val folytatódik.) abacababadabacabaca Könnyű belátni, hogy amennyiben r a legszélesebb bordere volt x-nek, akkor ra is a legszélesebb bordere lesz xa-nak. Az algoritmus előfeldolgozási szakaszában egy m+1 elemű következő névvel ellátott tömböt számítunk ki. A tömb KÖV[i] eleme (i-edik eleme) a minta sztring i hosszúságú prefixéhez tartozó legszélesebb border hossza. i=0,..,m. 23:06:19 23:06:19 7
Knuth-Morris-Pratt algoritmus Mivel a 0 hosszúságú üres sztringnek nincs bordere, a KÖV[0]=-1 lesz. (Most 0-val kezdődnek az indexek.) m értéke mindig a mintasztring hossza. Például, ha a számítás során már meghatároztuk a KÖV tömb 0-ás indexű elemét, és még néhány további elemét az i.-ig: KÖV[0],…,KÖV[i], és most meg szeretnénk határozni a következő elemet: KÖV[i+1]. Meg kell nézni, hogy a mintának a p1…pi prefixének egy bordere bővíthető-e az előbbi módon a minta következő, pi+1-edik karakterével. abacababadabacabaca 23:06:19 23:06:19 8
Knuth-Morris-Pratt algoritmus 1:abacababadabacabaca, 11:abacababadabacabaca 2:abacababadabacabaca, 12:abacababadabacabaca 3:abacababadabacabaca, 13:abacababadabacabaca 4:abacababadabacabaca, 14:abacababadabacabaca 5:abacababadabacabaca, 15:abacababadabacabaca 6:abacababadabacabaca, 16:abacababadabacabaca 7:abacababadabacabaca, 17:abacababadabacabaca 8:abacababadabacabaca, 18:abacababadabacabaca 9:abacababadabacabaca, 19:abacababadabacabaca 10:abacababadabacabaca A bővítés akkor tehető meg, ha pköv[i]+1=pi+1. A bordereket KÖV [i], KÖV[KÖV[i]], … behelyettesítve egyre mélyebben a KÖV értékeket, csökkenő sorrendjükben kell megvizsgálni. Ha a border nem bővíthető egy kisebb bordert veszünk veszünk, hátha az bővíthető. Ha az sem, akkor egy mégkisebbet, szűkebbet és így tovább. 23:06:19 23:06:19 9
Előfeldolgozó ciklus pszeudo-kódja Function KÖVFELTÖLT(P) mhossz(P) i0 j-1 KÖV[0] -1 While i<m do If j=-1 vagy P[i+1]=P[j+1] then ii+1 jj+1 KÖV[i]j Else j KÖV[j] End if End while Return KÖV End function 23:06:19 23:06:19 10
KMP előfeldolgozó algoritmus Olyan ciklust tartalmaz, amelyben egy j változó rendre felveszi a KÖV tömb eggyel csökkenő indexű értékeit, addig amíg az értéke -1-re nem csökken. Egy j szélességű border bővíthető lesz a pi+1-s karakterrel, ha a pj+1=pi+1 Ha bővíthető volt a border tovább léptetjük a változókat, majd a KÖV tömb aktuális elemének értékül adjuk a j-t (border hosszát). Ha nem, a j változónak új értéket adunk. 23:06:19
KMP algoritmus pszeudo-kódja Function KMP(A,P) nhossz(A) mhossz(P) KÖVKÖVFELTÖLT(P) ij0 KÖV[0] -1 While i<n és j<m do If j=-1 vagy A[i+1]=P[j+1] then ii+1 jj+1 Else j KÖV[j] End if End while If j=m then Return i-m+1 Return 0 End If End function 23:06:19 23:06:19 12
Knuth-Morris-Pratt algoritmus A borderek vizsgálata akkor ér véget, ha már nincs bővíthető border (j értéke -1). Ha a j változót növeltük, akkor p1…pi+1 prefix legszélesebb bordere j hosszúságú. Példa: p=abacababadabacabaca 23:06:19
Knuth-Morris-Pratt algoritmus Ha eltérést talál az algoritmus a j+1-edik pozíción, a továbbiakban a minta j hosszúságú, illeszkedő prefixének a legszélesebb borderét vizsgáljuk. (Ennek hossza: KÖV[j]). Úgy léptetjük a mintát, hogy ez a border továbbra is illeszkedjen az alapsztring már ellenőrzött részére. A léptetés mértéke: j-KÖV[j]. Ha még mindig eltérés van, a következő bordert vizsgáljuk, addig amíg el nem fogy a border (j=-1), vagy a j+1-edik helyen egyezés van, és a ciklus folytatódhat. A bacbababaabcbab ↕↕↕↕↕↕ P ababaca P ababaca P ababaca 23:06:19
Knuth-Morris-Pratt algoritmus Ha a minta minden karaktere (m db) illeszkedik az alapsztring megfelelő részére (j=m, 14-dik sor), akkor i-m+1-et adja (az illeszkedés következő indexét). Az összehasonlítások során az alapsztringben soha nem vizsgál meg újra a korábban már vizsgált karaktereket (i-t nem csökkenti), szemben a mezítlábas algoritmussal. j változó csökkentésének felső korlátja m (a minta hossza) 23:06:19
Shift-And (Dömölki-féle) algoritmus (Dömölki Bálint formális nyelvekkel foglalkozott). Később publikálták az algoritmust Baeza és Yates. (Dömölki-alg., Baeza-Yates- alg.) Az algoritmus alapötlete: Legyen p a minta sztringünk, amelynek hossza m. Vegyünk egy m elemű D vektort, amelynek a j-edik eleme 1 értékű, akkor, és csak akkor, ha a minta első j karaktere (p1…pj) szuffixe az alapsztring első i karakterének (a1…ai), egyébként pedig nulla. 23:06:19
Shift-And (Dömölki-féle) algoritmus Ha a p minta mérete kisebb mint a számítógép processzorának szóhossza, akkor ez a vektor a processzor egy regiszterében is tárolható. (Ilyenkor a későbbi keresés ezzel gyorsítható.) Tegyük fel, hogy az alapsztringet már megvizsgáltuk az i-edik karakteréig, és most olvassuk az i+1-edik karaktert. Ehhez egy új D’- vel jelölt vektort kell meghatározni. 23:06:19
Shift-And (Dömölki-féle) algoritmus Megfigyelés: A D’ vektor j+1-edik elemének értéke akkor és csak akkor lesz egy, ha egyrészt a D vektor j-edik eleme 1-es volt, vagyis p1…pj szuffixe volt a1…ai-nek, másrészt, ai+1=pj+1,azaz a soron következő karaktere megegyezik a minta soron következő karakterével. Két része van az algoritmusnak: előfeldolgozás és keresés. 23:06:19
Shift-And (Dömölki-féle) algoritmus Előfeldolgozás: Fel kell építeni egy 2 dimenziós B bitmátrixot. Ennek a mátrixnak az oszlopait (m db van belőlük) a minta karaktereivel címkézzük fel, a sorait pedig az ábécé egymástól különböző karaktereivel címkézzük. A sorok címkéi között nem lehet egyforma, de az oszlopoknál igen. A mátrixban egy elem értéke 1-es, ha a sorának és oszlopának az értéke megegyezik, és nulla egyébként. 23:06:19
Shift-And (Dömölki-féle) algoritmus További 3 db m elemű segédvektor is kell, amelyeket a következő kezdőértékkel látunk el: D segédvektort kezdetben csupa nulla értékkel töltjük fel. Az U segédvektor legelső eleme 1, a többi 0, és végül a V segédvektor utolsó, azaz m-edik eleme 1 és a többi 0. Az algoritmus egy „eltoló” (shift) műveletet is fog még alkalmazni: SHIFT(X)=SHIFT(x1,x2,…xm)=(0,x1,…,xm-1). Jobbra tolás: balról bejön egy nulla, jobboldalt az utolsó elem eltűnik. 23:06:19
Shift-And (Dömölki-féle) algoritmus Algoritmus: a sztringet karakterenként vizsgálja, és minden ai karakterenként a D vektort frissiti a következő formula felhasználásával: D’=(SHIFT(D) ٧U)٨Bai Ha a keresés során az i-edik karakter feldolgozásakor teljesül D ٨ V ≠(0,….,0,0,0), akkor megtaláltuk p egy előfordulását a-ban. p első karaktere a i-m+1-edik karakterére illeszkedik. V=(0,0,0,…,0,0,1) 23:06:19
Shift-And (Dömölki-féle) algoritmus Egy Példa: a=atacgatatata p=atat B: a t 1 * i ai D(régi) Shift(D) Shift(D) ٧U Bai D(új) 1 a (0,0,0,0) (1,0,0,0) (1,0,1,0) 2 t (0,1,0,0) (1,1,0,0) (0,1,0,1) 3 (0,0,1,0) 4 c (1,1,0,1) 5 g 6 7 8 9 23:06:19
Shift-And (Dömölki-féle) algoritmus A keresés akkor ér véget, ha a D vektor utolsó pozícióján megjelenik egy 1-es érték. A Dömölki algoritmus viszonylag gyors, a bitmátrix egyszer kerül kiszámításra, aztán bitenkénti ÉS illetve VAGY műveletek vannak csak. (Itt az a lényeg, hogy amit mi egy vektorral elvégzendő műveletsornak látunk (Shift, „vagyolás”, „éselés”), az valójában a számítógépnek egy, vagy két változóval történő egyetlen elemi művelet elvégzését jelenti.) De még mindig lehet javítani ezen az algoritmuson is. 23:06:19
SHIFT-OR-Algoritmus A SHIFT-AND algoritmusnál az 1-es bit sorra vándorolt az utolsó pozícióig. A Shift-Or algoritmus 0-s bittel éri el ugyanezt, mindent a fordítottjával jelöl. A vektorok is fordított bitekkel szerepelnek majd (D,V vektorok). A „vagyolás” kimaradhat, vagyis egy művelettel kevesebbet kell végrehajtani. (Az első „vagyolás” maradhat el, mivel nincs U tömb, az „éselés” pedig „vagyolás” lesz: itt ezt az egy műveletet kell elvégezni.) 23:06:19
SHIFT-OR-Algoritmus Változások a SHIFT-AND algoritmushoz képest: SHIFT(x1,x2,…xm)=(0,x1,…,xm-1) B: negáció, 0: ha a sor és az oszlop cimkéi megegyeznek. U: nincs, megszűnik V: negáció V=(1,1,…,1,0) Az algoritmus lépései módosulnak: D’=SHIFT(D)٧Bai Az U-t megspóroljuk, mert (0,1,…,1) csak 0-ra állítja az első bitet, ami amúgy is nulla, így ez a vektor és ez a lépés felesleges. 23:06:19
Több minta egyidejű illesztése A Shift-And-algoritmussal egyszerre több mintát is kereshetünk az alapsztringben. (A Shift-Or-ral nem lehet egyszerre több mintát vizsgálni, kivéve ha viszavesszük az U vektort.) A B bitmátrixot ki kell egészíteni Sorai ugyanazok Az oszlopai kiegészülnek a többi minta karaktereivel Kitöltése ugyanúgy történik D, U és V is változik: U=(1,0,…,0,0|1,0,…,0,0|…) V=(0,0,…,0,1|0,0,…,0,1|…) 23:06:19
Több minta egyidejű illesztése B: | atat gat tata a | 1010 010 0101 t | 0101 001 1010 g | 0000 100 0000 * | 0000 000 0000 Példa: a=atacgatatata p1=atat p2=gat p3=tata U=(1,0,0,0|1,0,0|1,0,0,0) V=(0,0,0,1|0,0,1|0,0,0,1) D=(0,0,0,0|0,0,0|0,0,0,0) SHIFT(D)٧U=(1,0,0,0|1,0,0|1,0,0,0) (SHIFT(D) ٧U)٨Ba1=(1,0,0,0|0,0,0|0,0,0,0) 23:06:19
Minta illesztő algoritmusok Sok sztringkezelő algoritmus létezik még. Olyanok is vannak, amelyek összetett mintákát is tudnak illeszteni. Pl. „ab*c?d(.e)+f” *: tetszőleges számú (0 vagy több) előfordulás, +: 1 vagy több előfordulás, ?: 0 vagy 1 előfordulás, .: tetszőleges karakter Igy a fenti minta illeszkedik az alábbi alapsztringekre: „fgabbbdreefad”, „rtacdhejefr”, „sabbbcdeenefh”, „addef” de nem illeszkedik az alábbiakra: „abbckld”, „acdbf”, „cvfdcd” 23:06:19