KMP算法与朴素模式匹配算法(C语言)
2016-10-29 21:57
411 查看
在上一篇博客中介绍了KMP算法和朴素模式匹配算法的区别,本文主要针对这两种算法的C语言实现进行讲解。
本文的代码主要包含120行到130行,求取该文本中aware的个数;132行到138行,利用朴素模式匹配方法求着8个单词的位置;142行到148行利用KMP算法求8个单词的位置;
感兴趣的朋友可以利用朴素匹配方法和KMP算法求单词总数;
下面针对代码进行说明:
朴素模式匹配方法:
跳出while循环的条件有两个,i大于等于文档字符总数(sizeBuffer)或者j大于匹配字符串字符总数(本文是5:aware)。
当有5个字符连续匹配成功,则j为5,跳出循环;*inx = i - sizeCheck;计算出单词起始位置。
inx表示开始查询的位置;
KMP算法
next数组的求取
请注意这里的i和j与上一篇博文中的i和j意义不同,上一篇文章中的i表示文本的索引;j表示匹配字符串的索引;这篇文章中i表示匹配字符串前缀的索引,j表示后缀的索引;
j的取值最大为当前字符的前一个字符,所以为aware中j最大取到r及j=0到j=3;所以j小于sizeChar.
当check[i] == check[j]成立,count增加,同时i和j继续增加;
若不成立
说明字符不是连续相等,计数器count清零;
此时,如果前缀索引为0及第一个字母,则后缀需要向后增加一个字符;否则后缀不变,前缀向前移动一个字符;
关于i的回溯;
举个例子:
ababaaba
第一个字符和第二个字符不相等;
那么以后无论哪个字符从第二个字符b开始的后缀都不可能和前缀相等;以为第二个b开始的后缀对应的是第一个a开始的前缀;
此时最大的前后缀只能是以第三个a开始的后缀;
本程序的回溯存在一些问题,但是目前测试的字符串计算的结果都是正确的,以后发现更好的回溯方法再更正,欢迎指正;
关于next数组的求取办法及详细代码实现分析和i的回溯问题请查看如下博客:
http://blog.csdn.net/u011028771/article/details/52993198
http://blog.csdn.net/u011028771/article/details/52966473
KMP程序
仔细观察就会发现,朴素匹配是
而KMP算法是
可以看到二者的区别是i值得变化;朴素匹配法回溯的是i值;KMP算法回溯的是j值;所以对于匹配字符串中相同的字符串比较多时,KMP算法的效率会优于朴素匹配;若匹配字符串中字符全部不相同,KMP算法优势并不明显。
关于KMP算法还有改进的方法,以后会继续讨论。
#include<stdio.h> #define OK 0 #define ERROR -1 #define FAILED 1 int readFile(char **buffer) { FILE *fp; int length; int error; fp = fopen("readFile.txt", "rt"); if (fp == NULL) { printf("open file failed!\n"); return ERROR; } fseek(fp, 0, SEEK_SET); fseek(fp, 0, SEEK_END); length = ftell(fp); (*buffer) = (char *)malloc(length); if ((*buffer) == NULL) { printf("malloc failed!\n"); return ERROR; } fseek(fp, 0, SEEK_SET); error = fread((*buffer), sizeof(char), length / sizeof(char), fp); if (error == 0 ) { printf("Read file failed!\n"); return ERROR; } fclose(fp); return OK; } //朴素的模式匹配算法 int index(char *buffer, char *check, int *inx, int sizeBuffer,int sizeCheck) { int i = *inx; int j = 0; while (i < sizeBuffer && j < sizeCheck) { if (buffer[i] == check[j]) { i++; j++; } else { i = i - j+1; j = 0; } } if (j == sizeCheck) *inx = i - sizeCheck; else return FAILED; return OK; } //KMP模式匹配算法 //计算next数组 int compNext(char *check, int *next, int sizeCheck) { int j = 1; int i = 0; int count = 0; while (j < sizeCheck-1) { if (check[i] == check[j]) { i++; count++; j++; next[j] = count; } else { count = 0; if (i == 0) { j++; next[j] = i; } else i--; } } // for (i = 0; i < sizeCheck; i++) { // printf("%d", next[i]); // } return OK; } //KMP字符匹配 int index_kmp(char *buffer, char *check, int sizeCheck, int sizeBuffer, int *inx) { int i = *inx; int j = 0; int flag = 0; int count = 0; int next[5] = { 0 }; compNext(check, next, sizeCheck); while (i <sizeBuffer && j<sizeCheck) { if (buffer[i] == check[j]) { i++; j++; } else { if (j == 0) i++; j = next[j]; } } if (j == sizeCheck) *inx = i - sizeCheck; else return FAILED; return OK; } int main() { int error; char *buffer; char checkChar[6] = "aware"; int i = 0; int flag = 0; int count = 0; int inx = 0; int sizeCheck = sizeof(checkChar)/sizeof(char)-1; error = readFile(&buffer); if (error == ERROR) { getchar(); } while (buffer[i] != '\0') { for (int j = 0; j < sizeCheck; j++) { if (checkChar[j] == buffer[i + j]) flag++; } if (flag == 5) count++; flag = 0; i++; } printf("The total number is %d\n", count); printf("The local of them are:\n"); while (error != 1) { error = index(buffer, checkChar, &inx, i, sizeCheck); if (error == OK) { printf("%d\n", inx); } inx = inx + 4; } inx = 0; error = 0; printf("The local of them are:\n"); while (error != 1) { error = index_kmp(buffer, checkChar, sizeCheck, i,&inx); if (error == OK) { printf("%d\n", inx); } inx = inx + 4; } free(buffer); return 0; }
本文的代码主要包含120行到130行,求取该文本中aware的个数;132行到138行,利用朴素模式匹配方法求着8个单词的位置;142行到148行利用KMP算法求8个单词的位置;
感兴趣的朋友可以利用朴素匹配方法和KMP算法求单词总数;
下面针对代码进行说明:
朴素模式匹配方法:
int index(char *buffer, char *check, int *inx, int sizeBuffer,int sizeCheck) { int i = *inx; int j = 0; while (i < sizeBuffer && j < sizeCheck) { if (buffer[i] == check[j]) { i++; j++; } else { i = i - j+1; j = 0; } } if (j == sizeCheck) *inx = i - sizeCheck; else return FAILED; return OK; }
跳出while循环的条件有两个,i大于等于文档字符总数(sizeBuffer)或者j大于匹配字符串字符总数(本文是5:aware)。
当有5个字符连续匹配成功,则j为5,跳出循环;*inx = i - sizeCheck;计算出单词起始位置。
inx表示开始查询的位置;
KMP算法
next数组的求取
//计算next数组 int compNext(char *check, int *next, int sizeCheck) { int j = 1; int i = 0; int count = 0; while (j < sizeCheck-1) { if (check[i] == check[j]) { i++; count++; j++; next[j] = count; } else { count = 0; if (i == 0) { j++; next[j] = i; } else i--; } } // for (i = 0; i < sizeCheck; i++) { // printf("%d", next[i]); // } return OK; }
请注意这里的i和j与上一篇博文中的i和j意义不同,上一篇文章中的i表示文本的索引;j表示匹配字符串的索引;这篇文章中i表示匹配字符串前缀的索引,j表示后缀的索引;
j的取值最大为当前字符的前一个字符,所以为aware中j最大取到r及j=0到j=3;所以j小于sizeChar.
当check[i] == check[j]成立,count增加,同时i和j继续增加;
若不成立
说明字符不是连续相等,计数器count清零;
此时,如果前缀索引为0及第一个字母,则后缀需要向后增加一个字符;否则后缀不变,前缀向前移动一个字符;
关于i的回溯;
举个例子:
ababaaba
第一个字符和第二个字符不相等;
那么以后无论哪个字符从第二个字符b开始的后缀都不可能和前缀相等;以为第二个b开始的后缀对应的是第一个a开始的前缀;
此时最大的前后缀只能是以第三个a开始的后缀;
本程序的回溯存在一些问题,但是目前测试的字符串计算的结果都是正确的,以后发现更好的回溯方法再更正,欢迎指正;
关于next数组的求取办法及详细代码实现分析和i的回溯问题请查看如下博客:
http://blog.csdn.net/u011028771/article/details/52993198
http://blog.csdn.net/u011028771/article/details/52966473
KMP程序
//KMP字符匹配 int index_kmp(char *buffer, char *check, int sizeCheck, int sizeBuffer, int *inx) { int i = *inx; int j = 0; int flag = 0; int count = 0; int next[5] = { 0 }; compNext(check, next, sizeCheck); while (i <sizeBuffer && j<sizeCheck) { if (buffer[i] == check[j]) { i++; j++; } else { if (j == 0) i++; j = next[j]; } } if (j == sizeCheck) *inx = i - sizeCheck; else return FAILED; return OK; }
仔细观察就会发现,朴素匹配是
else { i = i - j+1; j = 0; }
而KMP算法是
else { if (j == 0) i++; j = next[j]; }
可以看到二者的区别是i值得变化;朴素匹配法回溯的是i值;KMP算法回溯的是j值;所以对于匹配字符串中相同的字符串比较多时,KMP算法的效率会优于朴素匹配;若匹配字符串中字符全部不相同,KMP算法优势并不明显。
关于KMP算法还有改进的方法,以后会继续讨论。
欢迎指正
相关文章推荐
- (11)串的模式匹配:朴素的模式匹配算法,KMP算法
- 朴素的模式匹配算法(C语言)
- 3. 字符串匹配算法:朴素的匹配算法、KMP算法。
- 数据结构(11)--串的模式匹配算法之BF、KMP算法
- 经典算法研究:模式匹配(子串匹配)之 KMP 算法(C语言实现版)
- 经典算法研究:模式匹配(子串匹配)之 BM 算法(C语言实现版)初版
- 朴素和KMP模式匹配算法(Java)
- 改进的模式匹配算法——KMP算法
- 朴素的模式匹配和改进的模式匹配(KMP)算法说明
- 字符串模式匹配算法1 - BF和KMP算法
- 单模式匹配算法-KMP算法
- 模式串的快速匹配算法,kmp算法,尊重前人成果,创造新未来
- 改进的模式匹配算法——KMP算法
- C语言朴素模式匹配
- 朴素的模式匹配(布鲁特-福斯算法)
- 【算法】模式串的匹配-KMP算法
- Java数据结构之字符串模式匹配算法---KMP算法
- 改进的模式匹配算法——KMP算法
- 改进的模式匹配算法——KMP算法
- 朴素模式匹配算法java实现