sunday算法简单易懂,比KMP和BM都更容易理解。以后再补充KMP的算法。
竟然有人看我的文章。。。本来以为没人看的,所以就偷懒,原来的文字说明只有上面那一句,这下弄得我好羞愧。。。
来补充多点解释吧。
sunday算法是一个外国人在1990年发明的。。具体是谁忘记了,但他的名字里有sunday这个词,所以我猜这就是为什么叫sunday算法。
首先因为sunday算法每次的位置移动比BM算法还要大,所以程序更快也更有效率,在我的文章里,我把每次的位置移动称为喜闻乐见的跳跃运动。
先放到一个简单的例子里来看吧。
例如,在文本串“ABCDEFGABCDEFYABCHHYWYQCD”中寻找“HHYWYQ”
。。。。。。。。等等。我去做图。。这样纯手打不好讲。
EXCEL简单制图。。。别嫌弃。
首先“HHYWYQ”是一共六位,于是对齐上面的长文本串的前六位。
为了方便说明,我用string1表示那串长长长的文本串,用string2表示HHYWYQ这一小串。
用sunday实现在string1中查找是否存在string2,如果存在,则返回所在位置,不存在则返回0。
好了,开始比较。
但是只用比较第一位。即比较“A”和“H”。看图。
所有人都看见的跟我一样不相同吧?好的,不相同那我们就准备跳跃。下面加载跳跃运动。
找到String1中的strlen(string2)+1位,即第七位,这是我们的跳跃运动员。因为string2长度为6,所以就是比较第(6+1=)7位。看图。
就是string1中的G。找到第7位了,那么怎么比较呢?就是看在string2中有没有G这个字母。在这里显然是没有的。(具体原理稍后解释,现在我先把整个查找过程讲完。)
于是跳跃运动加载完毕。好了,起跳。看图。
华丽的跳了一大步,跳过了七位。正是因为sunday算法的跳跃步伐比BM的大,所以sunday的速度也快。
然后继续比较,这时就是比较string1的第8位和string2的第一位。看图。
还是一样,只需要比较这一位。比较结果是,不同。那么下面又开始加载跳跃运动。
这次的跳跃运动员就是string1的第14位,因为8+6=14,就是又加一次string2的长度。看图。
然后发现在HHYWYQ中有Y这个字母。于是跳跃运动加载失败。这下不能跳了。
然后就在string2中从右到左查找Y这个字母。从右到左第2个就是Y。
然后移动string2对齐右边的第一个Y,即移动2步。看图。
然后可以比较string2的第一位与相应的string1的位。看图。
不相同,那么就继续在string2中寻找还有没有Y。于是发现前面还有一个Y,所以不能放过它。
于是string2再次移动,让另一个Y对齐string1中的Y。看图。
不用说了,再次比较string2的第一位与相应的string1的位。看图。
结果是不相同。同时我这个例子里在string2中已经把所有的Y都比较过了,所以可以继续下面的步骤。如果你的文本里还有尚未比较的Y,还要先逐一比较完。
然后就可以继续跳跃了。找下一位。这时就是string1中的H。
然后又是移动string2。看图吧,图说明得直接点。
好了,已经可以看到很接近了!!但是别激动,计算机还不知道接近了啊。于是按步骤继续比较。看图。
C跟H不一样,于是继续比较string2中左边的H。看图。
终于快完了啊啊啊啊!!!然后计算机对比完成,终于知道找到了。看图。
整个比较的过程就是这样。T T。一直看别人的这么多博客,自己写真的好累。
然后回到开头遗留的问题,我来解释下为什么只比较第一位A和H,还有为什么如果G不在HHYWYQ中,就可以直接跳过七位。
@@首先如果A和H不相等,就只是两串字符的第一位不相等而已。这没什么。但是如果G不在HHYWYQ中,这就意味着从A开始的字母一直到G,与string2绝对不相同,于是可以直接跳过strlen(string2)+1位。
这个我再举个例子吧。
这个是当G存在string2中的情况。
如果不存在,那就是下面的这种情况。
算法实现:
#include<stdio.h>
#include<string.h>
int inthestring2 (char a,char *string2){ // 检查a是否在string2中
int ct = strlen(string2)-1;
while(ct >= 0){
if (string2[ct] == a)
return (strlen(string2) - ct); //返回a在string2中的位置
ct--;
}
return 0; //a不在string2中
}
int sunday (char *string1,int len1,char *string2,int len2){
int j = 0,i = 0,n;
while(j<=len1){
i = 0;
while(string1[i+j] == string2[i])
i++;
if (i == len2)
return i+j-len2+1;//返回string2在string1中的位置
if( (n=inthestring2(string1[j + len2],string2)) != 0)
j += n;
else
j += (len2 +1);
}
return 0;//如果在string1中没有找到string2,则返回0
}
int main()
{
char *string1,*string2;
string1 = "ABCDEFYHIJKHHYWYQXYZWQWQW";
string2 = "HHYWYQ";
/* string1 = "ABCDEFGHIJKLMNOPQ";
string2 = "XYZ";*/
int len1 = strlen(string1),len2 = strlen(string2);
int n;
n = sunday(string1,len1,string2,len2);
printf("位置为:n = %d。\n",n);
return 0;
}
我的代码是可以用的,可以复制然后自己再运行一遍。代码里一共有两组可供测试的数据,第二组放在注释里的是不匹配的情况,即在string1里是找不到string2的,运行的结果是可以返回0。
。。。。终于完了。可能有些地方还是不太详尽,欢迎提出疑虑和修改建议。