給定乙個文字串s,和乙個匹配串p,要求查詢p第一次在s中出現的位置。
常見的方法如暴力搜素,逐個匹配s[i],p[j],若匹配,下標後移。不匹配,i回溯到這次匹配前的下一位置,j置為0,重新匹配。最壞情況,時間複雜度o(n*m)。
int violencesearch(char *s,char *p)
else
}if(j==len) return i-j;
return ;
}
每次s[i] , p[j]不匹配總要將i回溯到到下一位置,j置0,這樣做可能還是會導致不匹配,又要i回溯,j置0……造成不必要的開銷,kmp查詢演算法的做法就是令i不回溯,當不匹配的時候令j置為next[j], 再將s[i]與p[next[j]]進行匹配,這種做法的好處是不用回溯i,最壞情況時間複雜度o(n+m)。
int kmpsearch(char *s,char *p)
else
j=next[j];
}if(j==lenp)return i-j;
return ;
}
這裡維護的next[j]是在匹配串p上p[j]之前(不包含p[j])的子串的相同最長字首字尾的長度如給定匹配串abcdabd,對應next:
kmp的精髓應該就在求解next陣列上,即知道next[0….j],如何求解next[j+1]:
•若p[k] == p[j],則next[j + 1 ] = next [j] + 1 = k + 1;
•若p[k ] ≠ p[j],如果此時p[ next[k] ] == p[j ],則next[ j + 1 ] = next[k] + 1,否則繼續遞迴字首索引k = next[k],而後重複此過程。 相當於在字元p[j+1]之前不存在長度為k+1的字首」p0 p1, …, pk-1 pk」跟字尾「pj-k pj-k+1, …, pj-1 pj」相等,那麼是否可能存在另乙個值t+1 < k+1,使得長度更小的字首 「p0 p1, …, pt-1 pt」 等於長度更小的字尾 「pj-t pj-t+1, …, pj-1 pj」 呢?如果存在,那麼這個t+1 便是next[ j+1]的值,此相當於利用已經求得的next 陣列(next [0, …, k, …, j])進行p串字首跟p串字尾的匹配。
void getnext(char *p,int
next)
else
k=next[k]; }}
其實next [j]陣列只要將各個最大字首字尾(這時包括next[j]這個元素)的公共元素的長度值右移一位,且把初值賦為-1 即可。
next陣列的優化:
當匹配串p[j]!=s[i]的時候,這時就要用p[next[j]]與s[i]進行匹配但是如
果p[j]==p[next[j]],就一定會導致這次的匹配失敗。所以不允許p[j]==p
[next[j]],如果相等,就再次遞迴讓p[next[next[j]]]與s[i]進行匹配
(即next[j]=next[next[j]])。
void getnextval(char *p,int
next)
else
k=next[k]; }}
唯一參考:
精簡了參考的這篇經典博文,是學習的乙個記錄,很多細節都沒詳細的闡述。
字串查詢演算法kmp
字串查詢最簡單的方法就是乙個乙個地 滑動 查詢。這樣查詢演算法複雜度可定很高,假設pattern的長度為m,文字txt的長度為n,那麼演算法複雜度為o m n m 1 kmp模式搜尋演算法 kmp knuth morris pratt 我只認識knuth,大名鼎鼎的高納德老頭子嘛。kmp演算法的基本...
字串查詢KMP演算法
如果你用過ctrl f這個快捷鍵,那麼你有很大的概率使用過這個演算法,這就是在待查詢字串 可能有成千上萬個字元 中找出模式串 比較小,可能有幾個字元 可能找到大於或者等於1次的位置。例如,在ababcd中找出abc。這裡介紹演算法思想,只給出了第一次出現的位置。void find char t,ch...
KMP 演算法 字串查詢演算法
knuth morris pratt algorithm 克努斯 莫里斯 普拉特 演算法 克努斯 莫里斯 普拉特演算法 部分匹配表 字首 指除了最後乙個字元以外,乙個字串的全部頭部組合 字尾 指除了第乙個字元以外,乙個字串的全部尾部組合 部分匹配值 就是 字首 和 字尾 的最長的共有元素的長度。以 ...