数据结构-KMP算法

暴力匹配算法

定义:

从主串的第一个位置开始,与模式串逐个对齐,挨个比较.若匹配失败,则从主串的第二个位置继续进行匹配,以此类推,直到匹配成功或到达主串的结尾。

举例:

主串:CDCCDCCDDCCDDC
模式串:CCDDCCD
比较过程:

1.1次匹配
CDCCDCCDDCCDDC
√X
CCDDCCD
2.2次匹配
CDCCDCCDDCCDDC
 X
 CCDDCCD
3.3次匹配
CDCCDCCDDCCDDC
  √√√X
  CCDDCCD
...
...
6.匹配成功
CDCCDCCDDCCDDC
	 √√√√√√√
  	 CCDDCCD

缺点:

暴力算法固然好用,但是如果是下面这种情况:
主串:CCCCCCCCCCCCD
模式串:CCCCCD
比较过程:

1.1次匹配
CCCCCCCCCCCCD
√√√√√X
CCCCCD
2.2次匹配
CCCCCCCCCCCCD
 √√√√√X
 CCCCCD
3.3次匹配
CCCCCCCCCCCCD
  √√√√√X
  CCCCCD
...
...
8.匹配成功
CCCCCCCCCCCCD
	   √√√√√√
  	   CCCCCD

那么对于这两个字符串的匹配,能不能只让主串与字符串的第1次匹配过程中依次比较,而第2次到第8次的匹配过程中只需比较模式串最后1个字符和其对应的主串字符是否比对呢?我们可以通过KMP算法达到目的

KMP算法

理解1:

定义数组:A[10],B[6]
主串:A[0-9]
模式串:B[0-5]

1.1次匹配
A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9]
B[0]B[1]B[2]B[3]B[4]B[5]
假设第6次比对失败,得出:
A[0]=B[0]
A[1]=B[1]
A[2]=B[2]
A[3]=B[3]
A[4]=B[4]
A[5]!=B[5]

2.2次匹配
A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9]
    B[0]B[1]B[2]B[3]B[4]B[5]
假设第1次匹配失败后模式串右移1位后成功匹配,得出:
A[1]=B[0]
A[2]=B[1]
A[3]=B[2]
A[4]=B[3]
A[5]=B[4]
A[6]=B[5]

3.结论:
结合第1次和第2次匹配得出:
A[1]=B[0]=A[0]
A[2]=B[1]=A[1]
A[3]=B[2]=A[2]
A[4]=B[3]=A[3]
A[5]=B[4]=A[4]
A[6]=B[5]
是匹配失败后模式串右移1位匹配成功的充要条件
显然B[0]=B[1]=B[2]=B[3]=B[4]
是匹配失败后模式串右移1位匹配成功的必要条件
1.1次匹配
A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9]
B[0]B[1]B[2]B[3]B[4]B[5]
假设第6次比对失败,得出:
A[0]=B[0]
A[1]=B[1]
A[2]=B[2]
A[3]=B[3]
A[4]=B[4]
A[5]!=B[5]

2.2次匹配
A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9]
    	B[0]B[1]B[2]B[3]B[4]B[5]
假设第1次匹配失败后模式串右移2位后成功匹配,得出:
A[2]=B[0]
A[3]=B[1]
A[4]=B[2]
A[5]=B[3]
A[6]=B[4]
A[7]=B[5]

3.结论:
结合第1次和第2次匹配得出:
A[2]=B[0]=A[0]
A[3]=B[1]=A[1]
A[4]=B[2]=A[2]
A[5]=B[3]=A[3]
A[6]=B[4]=A[4]
A[7]=B[5]
是匹配失败后模式串右移2位匹配成功的充要条件
显然B[0]=B[2],B[1]=B[3],B[2]=B[4],B[3]=B[5]
是匹配失败后模式串右移2位匹配成功的必要条件
1.1次匹配
A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9]
B[0]B[1]B[2]B[3]B[4]B[5]
假设第6次比对失败,得出:
A[0]=B[0]
A[1]=B[1]
A[2]=B[2]
A[3]=B[3]
A[4]=B[4]
A[5]!=B[5]

2.2次匹配
A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9]
    		B[0]B[1]B[2]B[3]B[4]B[5]
假设第1次匹配失败后模式串右移3位后成功匹配,得出:
A[3]=B[0]
A[4]=B[1]
A[5]=B[2]
A[6]=B[3]
A[7]=B[4]
A[8]=B[5]

3.结论:
结合第1次和第2次匹配得出:
A[3]=B[0]=A[0]
A[4]=B[1]=A[1]
A[5]=B[2]=A[2]
A[6]=B[3]=A[3]
A[7]=B[4]=A[4]
A[8]=B[5]
是匹配失败后模式串右移3位匹配成功的充要条件
显然B[0]=B[3],B[1]=B[4]是匹配失败后模式串右移3位匹配成功的必要条件
1.1次匹配
A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9]
B[0]B[1]B[2]B[3]B[4]B[5]
假设第6次比对失败,得出:
A[0]=B[0]
A[1]=B[1]
A[2]=B[2]
A[3]=B[3]
A[4]=B[4]
A[5]!=B[5]

2.2次匹配
A[0]A[1]A[2]A[3]A[4]A[5]A[6]A[7]A[8]A[9]
    			B[0]B[1]B[2]B[3]B[4]B[5]
假设第1次匹配失败后模式串右移4位后成功匹配,得出:
A[4]=B[0]
A[5]=B[1]
A[6]=B[2]
A[7]=B[3]
A[8]=B[4]
A[9]=B[5]

3.结论:
结合第1次和第2次匹配得出:
A[4]=B[0]=A[0]
A[5]=B[1]=A[1]
A[6]=B[2]=A[2]
A[7]=B[3]=A[3]
A[8]=B[4]=A[4]
A[9]=B[5]
是匹配失败后模式串右移4位匹配成功的充要条件
显然B[0]=B[4]是匹配失败后模式串右移4位匹配成功的必要条件

理解2:

定义:

定义两个指针i,j
i扫描主串,j扫描模式串
二者分别指向主串和模式串的第1个位置

举例:

主串:ABABBBAAABABABBA
模式串:ABABABB
Si表示前一次i与j扫描到同位置的状态,
Si+1表示后一次i与j扫描到同位置的状态
匹配过程是重复的由Si推进到Si+1的过程

1.保留主串和模式串

Si状态下:
123456789-------
ABABBBAAABABABBA
√√√√X
ABABABB
1234567
123456789-------
ABABBBAAABABABBA
 X
 ABABABB
 1234567
Si+1状态下:
123456789-------
ABABBBAAABABABBA
  √√?
  ABABABB
  1234567

2.仅保留模式串

Si和Si+1状态下:
 12 34 5 67
 AB AB A BB
 FL FR j
 	FL j
    AB A BABB
    12 3 4567

这里可以看出:如果让Si直接跳转到Si+1,而不经过中间的匹配过程,只需要模式串前移,能够使FL和FR重合即可

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值