KMP模式匹配演算法 兩種

2021-10-19 02:54:42 字數 4946 閱讀 2314

具體可分為:字首(prefix)法和next陣列法

1. 思路:

1)求出字首(prefix)表 2)依照字首(prefix)表來幫助匹配查詢

所以,找出字首(prefix)表是最核心的步驟

2. 方法:

給出兩種求字首(prefix)表的方法,這兩種方法的核心大致相當,都利用回溯的思想

本例中用指標j進行回溯,所以我把它倆都稱之為:j值回溯法,來計算字首(prefix)表

1)求未成熟的字首(prefix)表,將未成熟的表處理為成熟的字首(prefix)表,加工處理過程為:prefix陣列每個元素都後移一位(最後乙個元素理所應當被覆蓋),再將prefix[0]置為-1即可

以str = "ababax"為例:

字首(prefix)表,**如下:

void

prefixtable

(void

)//字首表函式

else}}

//未成熟字首表求值結束,接下來為處理環節

for(i = n -

1; i >

0; i--

) prefix[i]

= prefix[i -1]

; prefix[0]

=-1;

//處理完畢,輸出成熟字首表

for(i =

0; i < n; i++

)printf

("%2d "

, prefix[i]);

return

;}

2)方法1)改進,改變初始指標的位置,改變prefix[0]的值,使之從1)中的0變成2)中的-1

void

prefix_table

(void

)else

j = prefix[j]

;//若字元不相同,則j值回溯(正下)

}//結束成熟字首表的求值,因為是成熟的,不需要加工,接下來列印成熟字首表

for(i =

0; i < n; i++

)printf

("%2d "

, prefix[i]);

return

;}

兩個方法大致相當,只不過回溯略有區別,1)中回溯為左下回溯,2)中回溯為正下回溯,解釋一下:

方法1):

​ 下標:0 1 2 3 4 5 初始 i = 1, j = 0

​ 字元:a b a b a x

prefix: 0 ? ?

prefix[0]初始化為0定義的時候,判斷str[i]與str[j]是否相等,如果相等,那麼立馬就能將prefix[1]填入相應的值,然後 i 後移,再次判斷,倘若str[i] 與str[j]不相等,就需要回溯j的值,j = prefix[j-1],意思就是,暫時得不到prefix[i]的值,把j所指元素的前乙個的prefix值即prefix[j-1]賦給j,完成回溯,由於j和prefix[j-1]的位置關係(如圖prefix[j-1]在j的左下位置),所以稱其為左下回溯法

方法2):

下標:-1 0 1 2 3 4 5 初始 i = 0, j = -1

字元:空 a b a b a x

prefix: -1 ? ?

prefix[0]初始化為-1,判斷if (j == -1 || str[i] == str[j]),str[-1]不存在,但是前面 j == -1成立時,後面就不計算了,所以無影響。這次如果if條件為假,那麼將j回溯, j = prefix[j],由於j和prefix[j]的位置關係(如圖prefix[j]在j的正下方),所以稱之為正下回溯法

下面給出完全**:

void

kmpsearch

(void

)else}}

for(i = n -

1; i >

0; i--

) prefix[i]

= prefix[i -1]

; prefix[0]

=-1;

for(i =

0; i < n; i++

)printf

("%2d "

, prefix[i]);

printf

("\n");

//以上部分可完全用方法2)求字首表來替換

j =0; i =0;

while

(i < m)

if(text[i]

== str[j]

) i++

, j++

;else

}for

(i =

0; i < n; i++

)printf

("%2d "

, prefix[i]);

return

;}

總結:方法1)和方法2)由於指標i、j初始位置不同,prefix[0]不同,回溯方式不同,得到的字首(prefix)表不同,方法2)直接一步算出,方法1)先算出未成熟的字首(prefix)表,再加工而得到成熟的字首(prefix)表,得到字首(prefix)表後,按照上述操作可進行匹配查詢

1. 思路:

1)求出next陣列 2)利用next陣列進行匹配查詢

2. 方法:

1)這裡的next陣列,實際上數值對應關係上為prefix陣列元素+1,舉個例子:prefix: -1 0 0 1 1 2 0 1,那麼next為:0 1 1 2 2 3 1 2,記住一點,對應關係為next[i]=prefix[i-1]+1,i>=1 直接利用上面的**(回頭看)進行+1操作

當然有更直接的方法:調節i,j指標,和字元陣列存放位置,這種方法就是上面方法2)求字首(prefix)表的改版,下面講一講具體操作:

2)初始i、j指標的位置:i = 1, j = 0; 因此字元在陣列中的存放應該是這樣,以str = "ababax"為例:

str : 0 1 2 3 4 5 6

字元 無 a b a b a x

str[0]不放字元,它只是乙個用來回溯的出發點設定(j = 0),像程杰老師著的《大話資料結構》一書中,就把字串的長度放在了str[0]中(原書是t[0]),所以**即為上面方法2)的小改版:

void

nextproces

(void

)else

j = next[j]

;//若字元不相同,則j值回溯

}for

(i =

1; i < n; i++

)printf

("%2d "

, next[i]);

return

;}

注:這種直接算next陣列的方法和prefix+1算next的方法結果略有不同:主要是位置不一樣,直接算next陣列結果從next[1]next[6]有的6個數,而j用prefix+1算next是從next[0]next[5]的6個數

接下來,就是用next陣列進行匹配查詢

查詢過程中,需要用到兩個指標,分別是i和j,i指標為主串指標,j指標為子串指標,通過子串j值回溯,進行匹配查詢,下面講一講next陣列進行匹配查詢的核心思路:

next陣列與(成熟)字首(prefix)表最大的區別有兩點,也是我反覆說的:

1. next陣列第一位即next[0]不存放有效數字,實際上是從1開始,子串第一位str[0]也不存放有效字元,比如對於str = "ababax"和next,實際上應該寫為str = 「xababax」,因此得到的next陣列也是從1開始,而字首(prefix)表從0開始

2. 數字關係上,有效數字對應為:next = prefix + 1,不考慮有效性(下標)的情況下,為next[i] = prefix[i-1]+1,i從1開始

注:next陣列法,在程杰所著《大話資料結構》中,子串str(書中為t串)和主串text(書中為s串),均是陣列下標從1開始的

程杰《資料結構》版總體**如下(有改動):

void

kmpsearch

(void

)else

j = next[j]

;//若字元不相同,則j值回溯

} j =

1, i =0;

//等價於j = i = 1;

while

(i <= m)

if(j ==

0|| text[i]

== str[j]

)else

j = next[j];}

return

;}

下面聊一聊我的想法,我認為陣列下標從1開始,不符合正常邏輯,所以我們還是將str陣列、text陣列下標從0開始,得到的next陣列也從0開始存放值,由於字首(prefix)表與next陣列特殊關係,所以我用字首(prefix)表改出了與上面新next陣列,與原next陣列不同的是,該新next陣列從0開始存放數值,下面給出我的**:

void

kmp_search

(void

)else

j = next[j]

;//若字元不相同,則j值回溯(正下)

}for

(i =

0; i < n; i ++

) next[i]+=

1;while

(i < m)

if(text[i]

== str[j]

)++i,

++j;

else

}return

;}

以上就是全部內容了,我表達意思可能不到位,多多包涵~~謝謝你的**!

串的兩種模式匹配演算法

靜時亦覺意思好,才遇事便不同,如何?是徒知靜養而不用克己工夫也。如此,臨事便要傾倒。人須在事上磨,方立得住,方能 靜亦定,動亦定。此時正宜用功。若此時放過,閒時講學何用?人正要在此等時磨鍊。子串的定位操作 串的模式匹配 挨個遍歷,例如在asdfghjkl中尋找dfg,需要將dfg與asdfghjkl...

模式匹配 KMP演算法

字串匹配演算法 include includeusing namespace std define ok 1 define error 0 define overflow 2 typedef int status define maxstrlen 255 使用者可在255以內定義最長串長 typed...

模式匹配KMP演算法

前些日子在為目前該學習什麼而苦惱,就問了一下已經從事多年軟體開發的表哥,他說乙個程式設計師要走的遠,就要學好資料結構和演算法,於是我就重新開始學習資料結構和演算法了 拿起以前上過的資料結構看,看到第四章串的模式匹配時,頗感興趣,就寫了一下程式,實踐了一下。感覺還蠻爽,於是就把以下幾個重要的函式放在此...