KMP算法:基于自动机的理解

 

KMP 算法学习总结

 

KMP 算法看似简单,其实想要完全理解还是有困难的。

 

KMP 其实可以搜索过程可以看成是一个自动机,分为 2 部分,第一部分自动机的构造 ( 对应一般的说法就是失效函数,转移函数, overlap 函数 ) ,第二部分在自动机上搜索过程。

举个例子: 目标串味 T = acabaabaabcacaabc; 模式串 P=abaabcac

 

第一步:根据模式串构造自动机

向前的箭头表示搜索前进的方向。向后的箭头表示不匹配的回溯,即失效函数,或者状态变迁函数。例如:

  f(j=1) = 0;

  f(j=2) = 0;

  f(j=3) = 1;

  f(j=4) = 1;

f(j=5) = 2;

f(j=6) = 0;

f(j=7) = 1;

 

 

 

 

 

 

 

 

假如已经构造出该自动机,那么匹配算法用伪代码描述如下:

KMP-Search

  int j = 0;   // 指示当前自动机所在状态

  int i;     // 指示目标串匹配过程中的位置

  int n;    // 目标串的长度

  int m;  // 模式串的长度

  for(i =0; i < n; i++) {       // 对目标串进行匹配

         for(;;) {

             if( T[i] == pattern[j] ) {

                  j++;

                 if ( j == m) {

  found a match// 找到一个匹配

j = overlap(j);   // 再找下一个匹配

}

                   break;

   }

            else if( j == 0 )   break;    // 如果没有与 T[i] 匹配,直接 i+1

            else j = overlap(j);   // 匹配了一部分出错的,根据箭头的指向回溯

}

}

 

接下里,就是对失效函数的构造,

KMP-Table

overlap(Pattern pattern)

{

   初始化 overlap 用来存放失效函数的值 ;

       overlap [0] = -1; overlap [1] = 0;

   Int j = 2;                                  // 状态机的位置

   Int cnd;                                 // 当前回溯的位置

   While j < m

   {

       If( pattern[ j -1 ] == pattern[cnd])        // 当前匹配成功 , 移到下一个位置,

          overlap [j] = cnd +1 ; cnd++; j++;

       Else if( cnd > 0 )  cnd = overlap [cnd];   // cnd > 0 说明匹配了一部分后遇到不匹配, // 根据箭头方向回溯,重新匹配;

       Else overlap[j] = 0; j++;               // cnd = 0 说明当前不匹配

}

Return overlap

}

 

 

算法实现:

#include <iostream>
using namespace std;

/**
*KMP-Table
*input: pattern 
*output : overlap[]
*/
void kmp_table(const char * P, int * overlap)
{
	overlap[0] = -1;
	overlap[1] = 0;
	unsigned int j = 2;
	int cnd = 0;

	while(j < strlen(P))
	{
		if( P[j-1] == P[cnd])
		{
			overlap[j] = cnd + 1;
			++j;
			++cnd;
		}
		else if( cnd > 0)
			cnd = overlap[cnd];
		else 
		{
			overlap[j] = 0;
			++j;
		}
	}
}

/**
*KMP_Search
*input: char * Target ;  char * Pattern:
*output ; the position of the Pattern in Traget;
**/
int kmp_search(const char * T, const char * P)
{
	int n = strlen(T);
	int m = strlen(P);
    int * overlap = new int[m];
    int j = 0;

	kmp_table(P,overlap);

	for( int k = 0; k < m; k++)
	{
		cout<<overlap[k]<< "" ;
	}
	cout<<endl;

	for( int i = 0; i < n; i++)
	{
		for(;;)
		{
			if( T[i] == P[j])
			{
				j++;
				if(j == m)
					return i-m + 1  ;
				break;
			}
			else if(j == 0) break;
			else
			{
				j = overlap[j];
			}
		}
	}
	return -1;
}

int main()
{
	char * S = "acabaabaabcacaabc";
	char * W = "abaabcac";

	int p = kmp_search(S,W);

	cout<<"p = "<< p <<endl;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值