KMP 算法——C
? ? 昨天看了一下用于字符子串查找的KMP算法,很巧妙,也很難編,程序不長,理解起來可真是費勁。因為要用C語言來實現,所以書里KMP算法定義的next數組的求值方法需要改動,因為C語言里的字符串數據結構并不是讓第一位存儲字符串長度,而是直接保存了第一個字符,就是這樣一個小小的變化,可讓我傷透了腦筋,而且即便如此,對于算法的本質也不算了解得很透徹,幾乎是在死命調試的情況下把程序給實現出來,里面是不是有bug也不敢確定,編程可真是件糾結的事,要是早些接觸就好了,可以靜靜的思考,不用背負著找工作的壓力來學習。
? ? 尋找字符串的子串,結果返回第一個匹配的子串首字符的位置,從0開始。
1.先從簡單算法開始,簡單算法主要是通過循環來實現。
? ? int Index( char* s, char* t, int pos ) ? ? ? ?/*s為目標字符串,t為要尋找的字串,pos為s中的開始位置*/
? ? {
? ? ? ? int slen, tlen;
? ? ? ? int i = pos, j = 0; ? ? ? ?/*使用i標記s中的位置,使用j標記t中的位置*/
? ? ? ??if( s == NULL || t == NULL )
? ? ? ? ? ? return -1;
? ? ? ? slen = strlen( s );
? ? ? ? tlen = strlen( t );
? ? ? ? if( tlen > slen || pos < 0 || pos > tlen - 1 )
? ? ? ? ? ? return -1;
? ? ? ? while( i < slen && j < tlen )
? ? ? ? {
? ? ? ? ? ? if( s[i] == t[j] )
? ? ? ? ? ? { ++i; ++j }
? ? ? ? ? ? else
? ? ? ? ? ? { i = i - j + 1; j = 0; } ? ? ? ?/*通過回溯i指針并將j重新指向起始位置*/
? ? ? ? }
? ? ? ? if( j >= tlen )
? ? ? ? ? ? return i - j;
? ? ? ? else
? ? ? ? ? ? return -1;
? ? }
2.首位匹配算法
類似簡單算法,只是要先比較模式串t的首尾字符,首尾字符比較完后,再應用簡單算法比較中間字符
int Index_FL( char* s, char* t, int pos )
{
? ? int slen, tlen, patStart, patEnd;
? ? int i = pos, j, k;
? ??if( s == NULL || t == NULL )
? ? ? ? ? ? return -1;
? ? slen = strlen( s );
? ? tlen = strlen( t );
? ? if( tlen > slen || pos < 0 || pos > tlen - 1 )
? ? ? ? return -1;
? ? patStart = t[0];
? ? patEnd = t[ tlen - 1 ];
? ? while( i <= slen - tlen ) ? ? ? ?/*最后一個匹配位置為i = slen - tlen*/
? ? {
? ? ? ? if( s[i] != patStart ) ++i;
? ? ? ? else if( s[ i + tlen - 1 ] != patEnd ) ++i;
? ? ? ? else
? ? ? ? {
? ? ? ? ? ? k = 1; j = 1; ? ? ? ?/*用k來標記s中的位置, 以i + 1為起點*/
? ? ? ? ? ? while( j < tlen - 1 && s[ i + k ] == t[j] ) ? ? ? ?/*對中間字符串應用簡單算法進行匹配*/
? ? ? ? ? ? { j++; k++;?}
? ? ? ? ? ? if( j >= tlen - 1 ) ? ? ? ?/*由于末尾已經檢測過相等,所以當 j = tlen - 1時表明匹配*/
? ? ? ? ? ? ? ?return i;
? ? ? ? ? ? else ? ? ? ?/*不匹配則i右移一位*/
? ? ? ? ? ? ? ? i++;?
? ? ? ? }
? ? }
? ? return -1;
}
3.KMP算法,主要差別就在于,之前在遇到不匹配的情況時都是回溯s字符串的i指針,使用該算法則保持i不變,回溯t字符串的j指針,并且通過將t數組的首尾字串的重合位數記錄在next數組中,在匹配過程中,通過next數組的值,來確定j指針的回溯位置。(說的比較抽象,具體學習還是參看教材,我這里就是做個記錄便于以后復習或改進O(∩_∩)O)
紅色部分是跟原先算法主要的不同之處
void get_next( char* t, int next[] ) ? ? ? ?/*若不存在k使得‘p0...pk-1’ = ‘pj-k...pj-1’,則令next[j] = 0(原先算法是令這種情況的next值為1)*/
{
? ? int tlen;
? ? int i = 1, j = 0;
? ? next[0] = 0;
? ? next[1] = 0;
? ? tlen = strlen( t );
? ? while( i < tlen )
? ? {
? ? ? ? if( t[i] == t[j] )
? ? ? ? { ++i; ++j; next[i] = j; }
? ? ? ? else
? ? ? ? {
? ? ? ? ? ? j = next[j];
? ? ? ? ? ? if( j == 0?) ? ? ? ?/*j == 0則代表next[i + 1] = 0,即不存在k使得‘p0...pk’ = ‘pi-k...pi’*/
? ? ? ? ? ? ? ? next[++i] = 0;
? ? ? ? }
? ? }
}
?
int Index_KMP( char* s, char* t, int pos )
{
? ? ? ? int slen, tlen, i, j;
? ? ? ? int next[100];
? ? ? ??if( s == NULL || t == NULL )
? ? ? ? ? ? return -1;
? ? ? ? slen = strlen( s );
? ? ? ? tlen = strlen( t );
? ? ? ? get_next( t, next );
? ? ? ? if( tlen > slen || pos < 0 || pos > tlen - 1 )
? ? ? ? ? ? return -1;
? ? ? ? i = pos; j = 0;
? ? ? ? while( i < slen && j < tlen )
? ? ? ? {
? ? ? ? ? ? if( s[i] == t[j] ) { ++i; ++j; }
? ? ? ? ? ? else
? ? ? ? ? ? {
? ? ? ? ? ? ? ? if( j == 0 ) ? ? ? ?/*當s[i] != t[0]時直接將i移至下一位進行比較*/
? ? ? ? ? ? ? ? ? ? ++i;
? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? j = next[j];
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? if( j >= tlen )
? ? ? ? ? ? return i - tlen;
? ? ? ? else
? ? ? ? ? ? return 0;
}
? ??
轉載于:https://www.cnblogs.com/liangchao/archive/2012/09/20/2695233.html
總結
- 上一篇: 在路上(on the road)
- 下一篇: UIWebView相关应用