KMP的应用实例

    在没学习kmp之前,如果要在一个串里匹配查找另一个串。可能的实现如下:

#include
#include

int match(const char *W,const char *T)
{
    int target_length = strlen(W);
    int pattern_length = strlen(T);
    int target_index = 0;
    int pattern_index = 0;
	
    while (target_index < target_length - pattern_length + 1 && pattern_index < pattern_length){
        
        if (W[target_index] == T[pattern_index]){
            ++target_index;
            ++pattern_index;
        }
        else {
            //每次失配T都只移动一个元素
            target_index -= (pattern_index - 1);
            pattern_index = 0;
        }
    }
	
	if (pattern_index == pattern_length)
        return target_index - pattern_length;
    else
        return -1;
}

int main()
{
	const char *W = "banananobano";
	const char *T = "nano";
	
	printf("============%d===========\n", match(W, T));

    return 0;
}

上面的算法时间复杂度是O(pattern_length*target_length)。

我们主要把时间浪费在什么地方观查index =2那一步,我们已经匹配了3个字符,而第4个字符是不匹配的,这时我们已经匹配的字符序列是nan,

此时如果向右移动一位,那么nan最先匹配的字符序列将是an,这肯定是不能匹配的,之后再右移一位,匹配的是nan最先匹配的序列是n,这是可以匹配的。

如果我们事先知道pattern本身的这些信息就不用每次匹配失败后都把target_index回退回去,这种回退就浪费了很多不必要的时间,

如果能事先计算出pattern本身的这些性质,那么就可以在失配时直接把pattern移动到下一个可能的位置,把其中根本不可能匹配的过程省略掉,

如上表所示我们在index=2时失配,此时就可以直接把pattern移动到index=4的状态,kmp算法就是用来解决这个问题的。


下面是应用kmp优化后的实现


#include
#include

inline void BuildNext(const char *T, int Next[])  
{  
    int i,j;  
  
    //T[0]是最开始的元素,没有备胎可选,用-1表示;  
    //T[1]也很无奈,只能选择T[0]做备胎,所以Next[1] = 0;  
    Next[0] = -1;  
    j = Next[1] = 0;  

    for (i = 2; i < strlen(T); i++){  
          
        while (j > 0 && T[i-1] != T[j]) j = Next[j];  
  
        if (T[i-1] == T[j]) j++;  
  
        Next[i] = j;  
    }  
  
}  

int match(const char *W, const char *T)
{
    int target_length = strlen(W);
    int pattern_length = strlen(T);
    int target_index = 0;
    int pattern_index = 0;
    int Next[128] = {0};
	
    //构建Next数组
    BuildNext(T, Next);
	
    while (target_index < target_length - pattern_length + 1 && pattern_index < pattern_length){
        
        if (W[target_index] == T[pattern_index]){
            ++target_index;
            ++pattern_index;
        }
        else if (0 == pattern_index){
            ++target_index; //如果模式串第一个字符就失配
        }
        else {
            //利用Next数组,避免无意义的比较
            pattern_index = Next[pattern_index];
        }
    }
	
    if (pattern_index == pattern_length)
        return target_index - pattern_length;
    else
        return -1;
}

int main()
{
	const char *W = "banananobano";
	const char *T = "nano";
	
	printf("============%d===========\n", match(W, T));

    return 0;
}


参考文档:

    http://blog.csdn.net/yutianzuijin/article/details/11954939

    http://blog.csdn.net/power721/article/details/6132380


你可能感兴趣的:(数据结构与算法)