尊重產權,轉載請註明出處。
ex:找一個單詞在一篇文章中的定位 問題 :這種子串的定位操作
通常叫做 串的模式匹配。
ex 我們要從 goodgoogle 中 找 google 這個單詞。
樸素的方法是:
1、取子串的第一個字符叫做子首,主串 向後查找,
直到找到第一個與子首相等的字符叫做主首;
2、子首後移一位,主首後移一位,再次比較(重複此過程)
要是直到查找了n次(n = 子串長度),仍然是次次對應相等,
說明子串就是主串真正的子串。
3、比如:
主串:goodgoogle;
子串:google;主串一開始與子串比較,子串比較到 g-d 發現不相等了,指向主串的指針退回到第二個字符o再重複2過程,
ex-2 : (設 n 爲主串長度,m 爲子串長度):
主串:00000000000000000000000000000000000000000001 n=44
子串:0000000000000000001 m= 19;
需要比較的次數約爲:(n-m)*m (比較簡單)
其實這是完全沒有必要的,因爲 當比較到 g-d 時候,
我們就能知道前面的六個字符肯定都不符合,
根本不需要退回到主串的第二個字符重新搜索
那,有人會問,幹嘛非要討論這種極端情況呢?
不,其實真的很有必要!
因爲當m 越小,出現這種低效匹配的概率越高,
而若當m 越大,所導致的後果也就越嚴重。
不過,蠻力算法也並不是一無是處,比如在實際情況如搜索引擎裏,
n是對應着需要搜索的庫,m是用戶輸入的關鍵字,
n相對m來說是遠遠大於m的,所以O(n-m+1)*m 也等於 O(n),
極端情況的概率也就變得很小了。
*************************KMP講解:****************************
比如:比較 abcdefgab 和 abcdex
仔細觀察發現:子串的首字符a 與其後的bcdex 都不相等,
那麼對於主串abcdefgab 的 與子串對應相等的前五位而言已經失去了比較的意義。主串只需要直接跳轉到f 開始比較就行。
那麼主、子串要是這樣:
S = abcabcabx
T = abcabx 觀察到子串中T1 = T4, 這種情況怎麼辦呢?
可以確定S2 S3肯定是不用再次比較了,所以T只需要與S4 S5 對齊即可。
子串如何滑動與主串是沒有關係的,因爲出現失配的前面 肯定都是匹配的,
所以指向主串的計數變量 i 不動,指向模式串(子串)的計數變量 j 會根據next 來確定滑動距離。
下面我們就以失配前匹配的那一段前綴來構建next[ ]數組以期確定下一次子串滑動的方向
那麼next 數組究竟啓什麼作用?
返回失配位之前的最長公共前後綴!
具體來講,KMP算法想要解決的主要矛盾是子串的自匹配所造成的重複冗餘。
↑ 其中一律取 0 :就是從模式串的第一個字符開始 重新比較唄,
模式串中 沒有重複的部分,那我們的KMP 也就無用武之地了。
說了這麼多,那如何構建一個next[]數組呢? ↓
<<<<<<<<<<代碼君>>>>>>>>>>>
int main() {
int next[10]; int pos = 0;
char T[MAXSIZE],S[MAXSIZE];
printf("Please input the main string and the model string \n");
while(scanf("%s%s",S,T)) {
Getnext(T,next);
int result = KMP(S,T,pos,next);
if(result)
printf("We found it :%d \n\n",result);
else
printf("NO FOUND!v\n\n");
}
system("pause") ;
return 0;
}
/* 在主串 S 的第 pos 個位置開始查找子串 T,返回模式串在主串中的位置*/
int Getnext(char *T,int next[]) {
int j = 0 , k = -1;int tlen = strlen(T);
next[0] = -1;
while( j < tlen) {
if(k == -1 || T[j] == T[k] ) {
j++;
k++;
next[j] = k;
} else
k = next[k];
}
}
int KMP(char *S,char *T,int pos,int next[]) {
int i = pos - 1;
int j = 0;
int slen = strlen(S);
int tlen = strlen(T);
while(i < slen && j < tlen) {
if(j == -1 || S[i] == T[j]) {
i++ ;
j++ ;
} else
j = next[j];
}
if(j >= tlen)
return i - tlen + 1;
else
return -1;
}