zoukankan      html  css  js  c++  java
  • KMP模式匹配算法

    KMP 字符串匹配算法,用它来实现字符串的匹配,效率很高,特别是当字符串很长的时候。
    prefix_table();是一个前缀计算函数。
    首先前缀的计算只与模板有关,而与原字符串无关。
    如:ABCABDABCAB前缀为
    00012012345
    第一个A前面没有与它相同的故为0,接下来为AB,A也与B不相同,ABC仍然没有一样的,ABCA,此时最后一个字符A与第一个字符A相同,故为1,
    ABCAB,AB重复故为2,依次计算。其实每次计算都是从第一个字符相比较,但是再计算时,假如目前为ABCAB,我们已经知道前面的A匹配了,那我们
    只需要比较新加入的字符与第二个字符是否匹配了,如果匹配,那么就加1,如果不匹配则为0.

    在写程序时,模板肯定是要传入的,为了后续的使用前缀表,最好也传入一个前缀数组。

    void prefix_table(char pattern[] , int prefix[] ,int patternLength)
    {
    	prefix[0] = 0;//前缀的第一个为0
    	int patternIndex = 1;//因为第一个已经确定了
    	int prefixPreviesLength = 0; //用来标记当前位置前最大的字串长度
    	while ( patternIndex < patternLength )
    	{
    		if (pattern[patternIndex] == pattern[prefixPreviesLength])
    		{
    			prefixPreviesLength++;
    			prefix[patternIndex] = prefixPreviesLength ;
    			patternIndex ++;
    		}
    		else
    		{
    			if( prefixPreviesLength > 0)///保证不越界
    					prefixPreviesLength = prefix[prefixPreviesLength-1];
    					//如果不相等则调整,当前位置最大的字符串长度,变为模板的前一个前缀,继续比较
    			else
    			{
    				  prefix[patternIndex] = 0; ///已经找不到了,为0
    				  patternIndex++;//计算下一个的前缀
    			}
    		}
    		
    	}
    
    }

    一般为了后续程序的书写,将得到的前缀表右移一位,将prefix[0] = -1;
    void move_prefix_table(int prefix[] ,int n)
    {
    	for (int i = n-1 ; i > 0 ; i -- )
    	{
    		prefix[i] = prefix[i - 1];
    	}
    	prefix[0] = -1 ;
    }
    
    
    

      准备工作都做好,最后就是与原字符串的匹配了。在匹配前,先完成对前缀表的计算

        prefix_table(pattern, prefix ,PatternLength );
        move_prefix_table(prefix ,PatternLength );

       在匹配过程中,原字符串的索引是一直增加的,不会回溯,这也就是为什么KMP算法相比暴力搜索法高效的原因。

       当当前的模板索引与模板长度-1相同时,判断当前的字符与原字符串中的字符是否相等,如果相等,就输出它匹配的位置,

    并将前字符的前缀值赋予索引,继续查找,寻找是否还有相匹配的。

    void kmp_search(char data[] , char pattern[] )
    {
    	int DataLength = strlen(data);
    	int PatternLength = strlen(pattern);
    	int* prefix = new int[PatternLength];
    	prefix_table(pattern, prefix ,PatternLength );
    	move_prefix_table(prefix ,PatternLength );
    	int DataIndex = 0;
    	int PatternIndex = 0;
    	while ( DataIndex < DataLength )
    	{
    		if (PatternIndex == PatternLength-1 && data[DataIndex] == pattern[PatternIndex])
    		{
    			printf("Found pattern at %d . 
    " , DataIndex-PatternIndex);
    			PatternIndex = prefix[PatternIndex];
    		}
    		if ( data[DataIndex] == pattern[PatternIndex])
    		{
    			DataIndex++;
    			PatternIndex++;
    		}
    		else
    		{
    			PatternIndex = prefix[PatternIndex] ;//回溯查找,回溯到适当的位置
    			if ( PatternIndex == -1)
    			{
    				PatternIndex++;
    				DataIndex++;
    			}
    
    		}
    	}
    }
    

      

    int main(int argc, char* argv[])
    
    {
    	
    	char data[] = {'a','a','x','a','a','x',''};
    	char pattern[] = {'a','a','x',''};
    	kmp_search(data ,pattern );
    
    	char *data1 = "aaasaadfgdsasvcd";
    	char *pattern1 = "as";
    	kmp_search(data1 ,pattern1 );
    
    	return 0;
    
    }
    

    结果为:

    Found pattern at 0 .
    Found pattern at 3 .
    Found pattern at 2 .
    Found pattern at 11 .

    注意:若使用的是数组,需要在传递的时候,在数组的最后加上,因为strlen只有检测到才会停止。

     
    To get,you have to give.To give,you need learn to insist.If you really find it is hard for you,then you quit.But once you quit.Don't complain.
  • 相关阅读:
    hdu 5115 Dire Wolf 区间DP
    泛型兼容的注意事项
    maven web项目不能创建src/main/java等文件夹的问题
    error the @annotation pointcut expression is only supported at Java 5
    HashSet重复元素判断
    oracle 分库分表(sharding)
    关系型数据库分库分表解决方案
    JDK7中匿名内部类中使用局部变量要加final,JDK8中不需要,但jdk会默认加上final
    eclipse中更改配置使得switch语句不出错
    java io流中怎么在一个文本中追加字符串
  • 原文地址:https://www.cnblogs.com/hit-ycy/p/10823505.html
Copyright © 2011-2022 走看看