字串匹配演算法 KMP

2021-06-16 10:42:00 字數 2301 閱讀 9117

昨天初步學習了下字串匹配的演算法,有樸素匹配法(又稱brute-force)、rabin-karp演算法、有限自動機匹配法 以及 kmp演算法。

本文只是列出kmp演算法的**,以及我個人的一點兒膚淺的理解。我是做好準備,將來理解得更深入時,會更新本文。

本文**又是基本照搬別人的》_<。。原文在此 

約定:模式串pattern,記為p,其長度為m;目標串test,記為t,其長度為n;字元的集合記為σ

隱含假設:模式串一般比目標串短,故m = o(n)

樸素匹配法bf

樸素匹配法的之所以效率低,說到底就是資訊冗餘了,沒有有效利用。而後三個都是一定程度上減小了資訊冗餘度,提高了效率。

後三個演算法,在匹配過程中,分為兩步操作,第一步對字串進行預處理,第二步再進行匹配。其中預處理是減少冗餘資訊的關鍵步驟。

rabin-karp

rabin-karp在匹配時利用子串的hash值的比較,達到匹配的目的。這本身並沒有帶來冗餘度的減少,但是因為計算某乙個子串a的hash值之後,能夠根據它的值,在很短時間內計算出下乙個子串b的hash值,從而提高匹配效率。這裡的資訊冗餘就是子串a和子串b重疊那一部分子串的hash值,減少了不必要的第二遍計算。當然,我們要考慮到模式串pattern可能比較長,如果把它看做|σ|進製的乙個數,可能會太大不方便儲存。於是,改進的版本,就利用數論知識,通過每一步計算都對某個常數q取餘,降低數的數量級。這樣一來,不會影響到本來就匹配的所有命中點,但是會增加一些偽命中點。當遇到乙個可能的命中點時,通過最樸素的方法——逐位的字元匹配(執行時間o(m)),來進一步驗證到底是命中點還是偽命中點。

去偽辦法還是逐位匹配,而最壞的情況是每次都偽命中,每次都要逐位匹配,所以rabin-karp演算法的最壞執行時間還是o(m*n)。期望執行時間比較難算,近似認為偽命中的概率等於從1到q的q個數中選中q的概率,即為1/q,如此 則期望執行時間為o(n) + o(m(v + n/q))。其中q是選取的乙個常數(一般為素數),v是有效位移數。如果選取q >= m且v = o(1) ,則期望執行時間為o(n)。

有限自動機匹配法fam 

fam方法,借助有限自動機,為字串的所有可能匹配過程建立狀態和轉移。其中包含5個要素:q, q0, a, σ 和 δ 。

q為狀態的有限集合,q0為初始狀態, a是接受狀態的集合, σ 是字元的集合(也稱輸入字母表), δ 是乙個從q * σ到q的函式,成為有限自動機的轉移函式。

δ (i, a) = j 即表示狀態i接受字元a就轉入狀態j。

預處理階段,fam方法可以在o(m^3 * |σ|)時間內(改進版本可以做到o(m * |σ|)的時間),計算出全部的狀態轉移函式。然後在匹配階段,利用狀態轉移函式,在o(n)時間內進行匹配。改進版本的總時間為 o(m * |σ|) + o(n)。

knuth-morris-pratt演算法kmp

kmp演算法跟fam方法有類似的思想,只不過它在預處理階段可以用o(m)的時間計算出字首函式pi,處理時間是o(n),故總時間o(m) + o(n) = o(n)。

kmp比fam高效一點兒,後者因為要對每乙個字元a∈σ都進行計算,故預處理時間多了乙個σ因子。

計算字首函式pi

void computeprefixfunc(char *p, char *pi, int sizep, int sizepi)

/*如果匹配,字首長度加一*/

if(p[k] == p[q-1])

/*記錄q位置的當前字首值*/

pi[q] = k;

}}

kmp匹配

void kmp_match(char *p, char *pi, char *t, int sizep, int sizepi, int sizet)

/*如果匹配,則匹配長度加一*/

if(t[i] == p[q])

/*如果匹配長度達到模式串的長度,則找到了乙個成功的匹配,

此時將匹配長度置為其字首長度,做好準備接受下乙個匹配*/

if(q == sizep)

for(int i = 0;i < t_size;i++)

/*計算kmp_match執行的時間*/

clock_t start_time = clock();

kmp_match(parr, pi, tarr, p_size, p_size + 1, t_size);

clock_t end_time = clock();

double cost = (double)(end_time - start_time) / clocks_per_sec * 1000;

std::cout<<"running time is "<

KMP演算法 字串匹配

kmp演算法基本思想 我們在用常規的思想做 字串匹配時候是 如 對如 字元如果 t abab 用p ba 去匹配,常規思路是 看 t 第乙個元素 a 是否 和p 的乙個 b 匹配 匹配的話 檢視各自的第二個元素,不匹配 則將 t 串的 第二個元素開始 和 p 的第乙個匹配,如此 一步一步 的後移 來...

KMP字串匹配演算法

kmp核心思想 計算模式串的next陣列,主串的索引在比較的過程中不回朔 ifndef kmp h define kmp h class kmp endif include kmp.h include include include using namespace std int kmp calcu...

KMP字串匹配演算法

在介紹kmp演算法之前,先介紹一下bf演算法。一.bf演算法 bf演算法是普通的模式匹配演算法,bf演算法的思想就是將目標串s的第乙個字元與模式串p的第乙個字元進行匹配,若相等,則繼續比較s的第二個字元和p的第二個字元 若不相等,則比較s的第二個字元和p的第乙個字元,依次比較下去,直到得出最後的匹配...