您的位置:首页 > 理论基础 > 数据结构算法

数据结构 字符串比较 KMP算法

2009-07-30 13:51 218 查看
KMP算法:最简单的字符串匹配算法由于需要回溯查找,时间复杂度大。而改进型的KMP算法充分利用字符串的特性,减少了主字符串回溯需要查找的时间,大大的降低了其复杂度,大小为O(n+m),n为主字符串长度,m为从字符串长度。
下面介绍下KMP算法的步骤:
主字符串:aabbdcacaabca 从字符串:aabca
首先要设定指向主和从的指针i,j.KMP算法规定主指针不能回头,即网前移动后不能倒回去寻找匹配字符,那么就根据这个规定我们看下有什么变化和要求。
1.首先aabbdcacaabca的第一位和aabca的第一位比较,如果相等i和j都跳到下一位比较,如果不等,i不变j调到前一位比较直到找到相等的。
i=1
a
a
b
b
d
c
a
c
a
a
b
c
a
a
j=1
2.同步骤1,比较了i=2和i=3
i=3
a
a
b
b
d
c
a
c
a
a
b
c
a
a
a
b
j=3
3.当i=3时发现c!=b,这时让从串回溯,看3.1后的演示:
i=4
a
a
b
b
d
c
a
c
a
a
b
c
a
a
a
b
c!=b
j=4
3.1由于i不能动,现在我们也不知道j应该在哪个值可行,那只有一个一个试。
考虑从j-1位置依次往从字符串首靠比较合理。发先j=2处,a != b,因为只要一个不
匹配,说明主串对应的段绝对不会与字串匹配。因此移动j-1位继续移动。
i=4
a
a
b
b
d
c
a
c
a
a
b
c
a
a
a
b
j=3
3.2这时j=2,发现也不匹配。
i=4
a
a
b
b
d
c
a
c
a
a
b
c
a
a
a
j=2
3.3这时j=1,发现也不匹配,现在的从串数据都比较完了,
那么这时i和j都跳到下一位比较。
i=4
a
a
b
b
d
c
a
c
a
a
b
c
a
a
j=1
4这时两者有从头开始比较
i=5
a
a
b
b
d
c
a
c
a
a
b
c
a
a
j=1
从上面3发现 c!=b后,有没有未卜先知的功能让从字符串的比较一下子
跳到步骤4,而省去3.1,3.2和3.3这样的累赘,不就轻松很多。呵呵,
(^_^)我们的大师K,M和P就想出了省力讨好偷懒的办法
这个值怎么算到让j一下子跳到哪个位置还是有点复杂。
1. 首先规定第一个位置为0,0代表的意思是在这个位置的从字符和主字符串都
不匹配,两者都跳到下一个位置达到从来!比如从字符串的第一个a,如果主不是的a话那么他们都跳到下一个位置比较。
当next大于0时,它的意义就是,主字符串的指针不变,从的字符串调到对应的next值位与主字符串现在的位置做比较。比如主是aadcef,从是aabca, 从的next值是aabca.其中从b的对应next值为2,也就是说当比较到b这位不匹配时,从应回溯到从2对应的位置上与主进行比较,即从的第二个a上面。

b

a
a
b
c
a
1
next
0
2. 第1位匹配,假如第2位不匹配时,发现第1位a和
第2位a一样的值,那么next也一样。

a
b

a
a
b
c
a
2
next
0
0
3. 如果第3位不匹配,因为2位和3位不一样,当3不行的时候,可以把
2位移过来,且第1位与主字符串完全匹配。

a
a
c

a
a
b
c
a
3
next
0
0
2
4.第4位不匹配时,同上可得。

a
a
b
b

a
a
b
c
a
4
next
0
0
2
1
5.第5位不匹配时,按同样的方法。

a
a
b
c
c

a
a
b
c
a
5
next
0
0
2
1
0
说个一般性规律,还真不好说,我现在只是意会到了,言传太难了!!!
详细请看源代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//计算nextValue的值
//其中不明白的地方是
int getNext( const char t[], int next[] )
{
unsigned int i,j;
i = 1;
next[1] = 0; //第一个必定为0
j = 0;
while( i < ( strlen( t )+1 ) )
{
if( j==0 || ( ( j > 0 ) && ( t[i-1] == t[j-1] )  ) )
{
i++;
j++;
if( t[i-1] != t[j-1] )
{
next[i] = j;
}
else
{
next[i] = next[j];
}
}
else
{
j = next[j];
}
}
return 1;
}

int main( void )
{
char *s = "aavnsghsabc"; //随机设置字符串
char *t = "abaabcac";

int t_len, s_len;
int pos=-1;
int i,j,k;
int *next;

t_len = strlen( t );
s_len = strlen( s );

next = ( int * )malloc( sizeof( int ) * ( t_len+2 ) );
getNext( t, next ); //计算出从字符串的nextValue值

for( j = 0; j < t_len+1; j++ )
next[j] = next[j+1]; //将nextValue值平移到从数组0开始位置

i = 0; j = 0;
while( i < (s_len+1 ) && j < ( t_len+1 ) )
{//寻找相匹配的位置
if( s[i] == t[j] )
{
i++;
j++;
}
else
{
k = next[j];
if( k == 0 )
{
j++;
i++;
}
else
{
j = k - 1;
}
}
if( t[j] == '/0' )
pos = i - j + 1;
}

if( pos > 0 )
{
printf( "在%d的个位置找到相同的字符串/n", pos );
}
else
{
printf( "没有找到相匹配的字符串/n" );
}

if( next )
free( next );
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: