标签:
KMP算法基本思想有许多博客都写到了,写得也十分形象,不懂得可以参考下面的传送门,我就不解释基本思想了。本文主要给出KMP算法及next数组的计算方法(主要是很多网上的代码本人(相信应该是许多人吧)看不懂,直接拿来用也是各种问题),这里的代码封装性和优化都有待考究,但是基本能实现KMP算法
http://www.cnblogs.com/c-cloud/p/3224788.html
这里提醒各位看官,while循环次数不是常见的固定次数的循环,而是动态根据实际情况将大家固认为的“一趟循环”分解成几次,看代码时留意这点,对各位看官应该有所帮助。
1.KMP的next数组生成方法。
根据链接中的15来看,可以根据搜索的字符串strKey的长度确定分析的次数(第一次显然是0),第1-len次分析的长度刚好就是左边字符个数(1-len),相应次数的前缀后最的共同元素的最长长度为对应next数组的值。
同时我们发现规律:根据前缀和后缀的特点,我们可以从每次分析的字符串(每次分析的字符串都不一样)的最后一个字符开始,向前进行字符匹配。
每次匹配成功一个字符就后缀索引backIndex-1;
每次匹配字符失败,需要判断是否已经有部分匹配的字符串,若有,应重置后缀索引backIndex=0,相应next数值为0;若无,前缀索引frontIndex+1即可
每趟大循环,如果遇到已经计算到next的相应数值则进入分析下一组(这里组的概念类似链接的第15点的分析步骤);若遇到该组没有分析完,但是遇到了一些情况:比如说frontIndex =0,或者匹配成功一个字符,则进入大循环,但是是继续分析还没有分析完的这组
1 void cal_next(char * strKey, int * next, int len) 2 { 3 int calTimes = 2;//计算次数 ,第一次肯定为零 4 int frontIndex=0;//负责在前缀里边索引元素 5 int backIndex = 0;//负责在后缀里边索引元素 6 //清零 7 for (frontIndex = 0; frontIndex < len; frontIndex++) 8 { 9 next[frontIndex] = 0; 10 } 11 frontIndex = calTimes-2;//取得可能的最大前缀和后缀的共同元素的最长的长度0- 12 backIndex = calTimes-1;//0- 13 while (calTimes<=len) 14 { 15 printf("calTimes:%d\r\n",calTimes); 16 printf("frontIdex:%d\r\n", frontIndex); 17 printf("backIdex:%d\r\n", backIndex); 18 while (frontIndex > 0 && strKey[backIndex] != strKey[frontIndex ])//最多calTimes次比较 19 { 20 printf(" There is a unmatched char\r\n"); 21 if (next[calTimes - 1] != 0)//已经有部分字符匹配,中途出现了不匹配的字符 22 { 23 next[calTimes-1] = 0; 24 backIndex = calTimes-1;//重置后缀索引 25 break; 26 } 27 frontIndex--; 28 } 29 if (frontIndex == 0 && strKey[backIndex ] != strKey[0])//最差的情况,一次都没有匹配成功 30 { 31 next[calTimes-1] =0; 32 calTimes++; 33 frontIndex = calTimes-2; 34 backIndex = calTimes-1; 35 printf(" There is never matched\r\n"); 36 } 37 else if (frontIndex == 0 && strKey[backIndex ] == strKey[0])//最后一个字符匹配成功 38 { 39 next[calTimes - 1] +=1; 40 calTimes++; 41 frontIndex = calTimes-2; 42 backIndex = calTimes-1; 43 printf(" the last char matched\r\n"); 44 } 45 else 46 { 47 if (frontIndex > 0 && strKey[backIndex ] == strKey[frontIndex ]) //匹配成功一个 48 { 49 next[calTimes - 1]++; 50 backIndex -= 1; 51 frontIndex--; 52 printf(" a char matched\r\n"); 53 } 54 } 55 } 56 }
2.KMP算法的实现
这里的实现步骤其实就是算法了步骤了,应该没有什么可讲的,基本的实现思路跟next的生成方法差不多。
1 void kmp(char * strText, char *strKey) 2 { 3 int *next = new int[strlen(strKey)]; 4 //计算next 数组 5 cal_next(strKey,next,strlen(strKey)); 6 //查找 7 int textLenght = strlen(strText); 8 int keyLenght = strlen(strKey); 9 int textIndex = 0; 10 int keyIndex = 0; 11 int successNums = 0; 12 while (textIndex < textLenght) 13 { 14 while (textIndex <textLenght && strKey[keyIndex] != strText[textIndex]) 15 { 16 printf(" There is a unmatched char\r\n"); 17 if (keyIndex != 0)//已经匹配部分字符中途遇到不匹配的字符 18 { 19 textIndex -= next[keyIndex-1]; 20 printf(" keyIndex %d next %c\r\n", keyIndex, strText[textIndex]); 21 keyIndex = 0; 22 }else 23 textIndex++; 24 } 25 if (textIndex == textLenght )//一个都没有匹配成功(textLenght-1 时,一定是不予strKey的“相应字符匹配”,所以才会进入textIndex++) 26 { 27 if (successNums==0) 28 printf(" Summary: Never Matched\r\n"); 29 else printf(" Summary: %d Matched\r\n",successNums); 30 } 31 else if (strKey[keyIndex] == strText[textIndex])//找到匹配的字符 32 { 33 keyIndex++; 34 textIndex++; 35 if (keyIndex == keyLenght) 36 { 37 keyIndex = 0; 38 successNums++; 39 printf(" Summary: Matched @textIndex=%d\r\n", textIndex - keyLenght); 40 } 41 printf(" There is a Matched Char\r\n"); 42 } 43 } 44 }
3.main
1 int _tmain(int argc, _TCHAR* argv[]) 2 { 3 char Search[10] = {‘a‘,‘b‘,‘\0‘}; 4 char Text[100] = "abababdhello"; 5 kmp(Text, Search); 6 7 while (1); 8 return 0; 9 }
标签:
原文地址:http://www.cnblogs.com/guiguzhixing/p/5873615.html