日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

KMP算法模式匹配

發布時間:2024/3/26 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 KMP算法模式匹配 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請注明出處

http://blog.csdn.net/pony_maggie/article/details/37832707

作者:小馬


在一個長串中查找一個子串是較常用的操作。各種信息檢索系統,文字處理系統都少不了。本文介紹一個非常著名的KMP模式匹配算法用于子串查找。

?

先拋開KMP,正常情況一下我們會如何設計這個邏輯。一個主串S, 要在里面查找一個子串T,如果找到了返回T在S中開始的位置,否則返回-1。應該不難,需要一個輔助函數,從一個串口的指定位置,取出指定長度的子串。思想是這樣:

在主串S中從開始位置,取長度和T相等的子串比羅,若相等,返回該位置的索引值,否則位置增加1, 繼續上面的過程。代碼很簡單,如下:

?

//普通方法查找子串 //在主串s中查找t, 若找到匹配,返回索引位置(從0到len-1) //否則返回-1 int IndexOfString(char* srcString, char* keyString) {int nSrcLen = 0;int nKeyString = 0;int i = 0;char szTemp[1024] = {0};//假設足夠大if ((srcString == NULL) || (keyString == NULL)){return -1;}nSrcLen = strlen(srcString);nKeyString = strlen(keyString);if (nKeyString > nSrcLen){return -1;}while(i < (nSrcLen-nKeyString)){memset(szTemp, 0x00, sizeof(szTemp));SubString(srcString, szTemp, i, nKeyString);if (memcmp(szTemp, keyString, nKeyString) != 0){i++;}else return i;}return -1; }
再進一步,把輔助函數去掉,通過頻繁操作下標也同樣可以實現,思想跟上面查不多,只不過換成一個個字符比較,代碼如下:

?

int IndexOfString1(char* srcString, char* keyString) {int nSrcLen = 0;int nKeyLen = 0;int i = 0;int j = 0;char szTemp[1024] = {0};//假設足夠大if ((srcString == NULL) || (keyString == NULL)){return -1;}nSrcLen = strlen(srcString);nKeyLen = strlen(keyString);if (nKeyLen > nSrcLen){return -1;}while((i < nSrcLen) && (j <nKeyLen)){if (srcString[i] == keyString[j]){i++;j++;}else{i = i - j + 1;//主串回退到下一個位置j = 0; //子串重新開始}}if (j >= nKeyLen){return (i - nKeyLen);//找到}return -1; }

分析一下上面算法的時間復雜度(兩個算法其實是一樣的)。舉個例子,主串是:

“A STRING SEARCHING EXAMPLE CONSISTINGOF SIMPLE TEXT”

子串是

“STING”

?

用上面的算法,會發現除了上面標記紅色的字符比較了兩次,其它都是比較一次,如果主串的長度是m, 子串的長度是n, 時間復雜度基本是O(m+n)。好像不錯,效率挺高。再來看一個。主串是:

“000000000000000000000000000000000000000000000000000000000001”

子串是

“00000001”

?

在腦海里想像一下這個過程,很容易得出它的時間復雜度是O(m*n)。所以這種類似窮舉的查找子串算法,時間復雜度與主串和子串的內容有很大關系,復雜度不固定。而且像上面那樣的01串在計算機處理中還比較常見,所以需要更好的算法。

?

KMP(三個發明人的名字首字母)算法可以保證不論哪種情況都可以在O(m+n)的時間復雜度內完成匹配。它改進的地方是當出現比較不等時,主串中位置不回退,而是利用已經匹配的結果,將子串向右滑動盡可能遠的距離后,再繼續比較,看個例子:


?

在第三趟匹配中,當i=12, j=7時,字符不相等,這時不用回退到i=7,j=1重新比較,而是i不變,j變成next[j]的值就行了,上圖中是3, 也就是圖中第四趟的比較位置。

?

這個確實很強大,現在要解決的問題是next[j]如何計算。其實這個推導也不難,很多算法的書上都有詳細的過程,我這里就不贅述了。只把結果給出來:

?

1 當j = 0時,next[j] =-1。

2 當j =1時,next[j] = 0。

3 滿足1 < k < j,且p[0…k-1] =p[j-k…j-1]的最大的k, next[j] = k。

4 其它情況,next[j] = 0。

?

根據上面的邏輯,很容易寫出一個計算next的函數,如下:

static void getNext(char* strSub) {int j, k, temp;int nLen = 0;j = k = temp = 0;nLen = strlen(strSub);memset(g_next, 0x00, sizeof(g_next));//每次進來都清空for (j = 0; j < nLen; j++){if (j == 0){g_next[j] = -1;}else if (j == 1){g_next[j] = 0;}else //取集合不為空時的最大值{temp = j - 1;for (k = temp; k > 0; k--){if (isEqual(strSub, j, k)){g_next[j] = k;break;}}if (k == 0)//集合為空{g_next[j] = 0;}}}}
得到next之后,整個過程如下: 以指針i和j分別表示主串和子串中正在比較的字符,若Si = Pj, 則i和j都增1,繼續下一個字符的比較。否則i不變,j退到next[j]的位置再比較,若相等,再各自增1,否則j再退到next[j]。循環進行,如果中間遇到next[j]為-1的情況,此時主串要增1,子串j變為0,表示要從主串的下一個位置重新開始比較。

?

把上面的過程轉化為代碼:

//KMP算法查找子串 //在主串s中查找t, 若找到匹配,返回索引位置(從0到len-1) //否則返回-1 int IndexOfStringKMP(char* srcString, char* keyString) {int i = 0; int j = 0;int nSrcLen = 0;int nKeyLen = 0;if ((srcString == NULL) || (keyString == NULL)){return -1;}nSrcLen = strlen(srcString);nKeyLen = strlen(keyString);if (nKeyLen > nSrcLen){return -1;}getNext(keyString);//先計算next值while ((i < nSrcLen) && (j < nKeyLen)){if ((srcString[i] == keyString[j]) || (j == -1)){i++;j++;}else{j = g_next[j];}}if (j >= nKeyLen){return (i - nKeyLen);//找到}return -1; }

代碼下載地址:

http://download.csdn.net/detail/pony_maggie/7630329

https://github.com/pony-maggie/StringIndex

總結

以上是生活随笔為你收集整理的KMP算法模式匹配的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。