前几天看有人问什么是kmp算法,额,我当时也不知道,然后查了下资料,才发现这个算法很不错,之前遇到过很多类似的情况,却都是采用那些本方法,固步自封啊。
想学习这个算法的时候,看了一些网上的文章,感觉基本意思都说出来,但是“为什么”这样讲的都很隐晦,例子给的也没有特殊性,结合之前看过的一些博客,记录一下自己对这个算法的一些认识。
1、传统算法为什么慢
这里我给一个例子,我认为这个例子是很好的,能体现出kmp算法的优势所在
char s1[128] = "aabaabababa";
char s2[128] = "aababa";
哈哈,就是这个,运用情况就是查找s1中是否包含s2
传统算法是什么样的呢?
其实就相当于
对s1就拆分成aabaab,abaaba,baabab,aababa,abaaba,bababa,这样六组字符串,逐个与s2比较是否相同(我把它想象成strcmp)
好,这里存在一个问题,就是每次比较过程中是产生了一定信息的,这个信息就是被上面的这种比较浪费了,可以这样理解,某一次比较中,如果在比较到某个字符时候失败了,那么之前其实是有一部分相同的,这一部分是和s2存在某种联系的,但是我们舍弃了这个信息,而继续对下一种可能的情况重头开始进行比较,这样就会造成算法开销的浪费。
举个现实生活中的例子吧,有一个班级考试,之后出了一个成绩单,我是一个特别无聊的,人,我就想看看成绩连续的五个人是不是在考试的时候有四个或者以上坐一起了,有的话,我认为存在作弊,好,那我看24,25,26,27,28,如果只存在24,25,27坐一起,三个,不符合作弊情况,这时候继续找,那么记下来肯定不会傻傻的重新分析23,-27,而是直接看看23是不是和24,25,27,是不是坐在一起,这就是人脑的一个分析过程。 所以说,kmp算法,就是要模拟人脑的整个分析过程,把之前的比较的一些信息记录下来,来加快之后的比较过程。
2、如何整理并使用这些信息
void getNext(char *p,int *nNext)
{
for(int i = 0;i < strlen(p);i++)
{
if(i == 0)
{
nNext[i] = -1;
}
else
{
bool bEnter = false;
int nMax = strlen(p);
for(int j = 1;j < i;j++)
{
char cTemp1[128] = {0};
char cTemp2[128] = {0};
memcpy(cTemp1,p,j);
memcpy(cTemp2,p+i-j,j);
if(strcmp(cTemp1,cTemp2) == 0)
{
if(j < nMax)
{
bEnter = true;
nMax = j;
}
}
}
if(bEnter == true)
{
nNext[i] = nMax;
}
else
{
nNext[i] = 0;
}
}
}
}
int KMPMatch(char *s,char *p)
{
int next[100];
int i,j;
i=0;
j=0;
getNext(p,next);
while(i<strlen(s))
{
if(j==-1||s[i]==p[j])
{
i++;
j++;
}
else
{
j=next[j];
}
if(j==strlen(p))
{
return i-strlen(p);
}
}
return -1;
额,想了半天,还是先吧代码贴上吧,我感觉这是一个先有鸡还是先有蛋的悖论,因为我感觉,如果突然告诉你要根绝next[]的信息进行比较,肯定回想问,问什么这个信息就可以做这个操作,如果先讲next[]是怎么得来和为什么这样,那么肯定又看的一头雾水,额!!!!
我决定还是想讲一下next[]是怎么得来的!!!!
对于next[]数组的定义如下:
1) next[j] = -1 j = 0
2) next[j] = max(k): 0<k<j P[0...k-1]=P[j-k,j-1]
3) next[j] = 0 其他
这是就是准则,类似与结构体对齐三原则一样的东西好!看第二条,其实翻译过来就是这样
一个字符串上某pos位置,存在从起始位置开始位置的头n个位置和pos位置邻近的n个位置(这里不包含pos位置)内容相同,那么n就是next[pos]的值
这句话其实的意思就是在这个位置之前的n个字符和开始的n个字符如果有相同的,就记录下这个信息n。这里因为这个位置之前的几个字符是刚刚比较过的,如果这个信息恰巧也和开始的n个字符相同,那么这样的话,前面的几个字符是可以不做比较的!!!!!好的,就是这句话,我表达不太好,但就是这个意思。
好,这里的next[]储存的全是这个信息。
3、关于kmp算法的效率
确实高,但是绝没有想象的那么高,求next[]是要进行o(n2)的处理的
这里还是要说下这些算法,优化,我还是认为,一切算法的优化都是要在利用之前的信息的储存的基础之上实现的,是么堆排序,快排,我感觉是一个思想