数据结构之串的模式匹配(C语言实现)
2017-08-29 17:34
411 查看
一、暴力匹配算法(BF)
BF全称为Brute-Force,最简单直观的模式匹配算法。1.算法思想
两个字符串进行匹配时,一个主串和一个模式串,就是按照我们最容易想到的算法来进行匹配。用两个变量i,j分别记录主串和模式串的匹配位置,如果两者在某个字符不匹配,则将记录主串匹配位置的变量i回退到匹配前i的位置的后一个位置,将j回头到模式串的第一个字符位置;如果i和j指向的主串和模式串字符匹配,则将两者同时向后走一个位置,继续比较;最后,如果j的位置已经走过了模式串的所有字符,则说明此时匹配成功。
这个算法很简单,也容易理解,下面直接给出代码。
2.代码实现
#include<stdio.h> #include <string.h> int BF(const char *MainStr, const char *PatternStr) { int i = 0; //主串的匹配起始位置 int j = 0; //模式串的匹配起始位置 int iMainLen = strlen(MainStr); //主串长度 int iPatLen = strlen(PatternStr); //模式串长度 while (i < iMainLen && j < iPatLen) { if (MainStr[i] == PatternStr[j]) { ++i; //当前字符匹配成功,两者均往后走一个位置 ++j; } else { i = i - j + 1; //每次未匹配成功时i回退到原来i的后一位置 j = 0; //模式串每次未匹配成功时回退到0位置 } } if (j >= iPatLen) //条件满足说明j走过了模式串的所有字符 { return i - j; } return -1; } int main(void) { const char *MainStr = "abcdabddabc"; const char *PatternStr = "dabc"; int iPos = BF(MainStr, PatternStr); printf("iPos = %d\n", iPos); return 0; }
二、KMP算法
KMP算法的高明之处在于当主串和模式串在某个字符不匹配时,指示主串匹配位置的变量不需要回退,而直接回退指示模式串匹配位置的变量,而且该变量回退时也不需要像BF算法中回退到起始位置,而是基于原来已匹配过的结果来回退。关于KMP算法推导的过程很多博客中都有,而且很多书上也讲的很清楚,大家可以参考严奶奶的《数据结构》,里面有很清楚的推导,我就不写推导过程了。
下面就我在理解KMP算法中遇到的问题加以说明,并给出KMP算法的实现代码。
问题1.next数组的本质
找到匹配成功部分的两个尽可能长的相等的真子串,一个子串以0下标开始,另一个真子串以j-1下标结尾。(这里的j表示模式串的第j个位置,从0开始计数)
问题2.next[j]=k的含义
next [j] = k,代表j 之前的字符串中有最大长度为k 的相同前缀后缀
问题3.解释next[0]=-1,next[1]=0
假设i指示主串的当前匹配位置,j指示模式串的当前匹配位置。从问题2可以知道next[0]=-1的含义就是当
了。但是我们知道下一次匹配的情况,那就是主串的匹配位置往后走一个(即i+1位置),继续和模式串的0号位置匹配,所以此时应该将模式串的匹配位置也向后走一个(即从-1加1为0,从0号位置开始匹配,便于写代码)。
同理next[1]=0,这个更容易理解,它表示的含义是当模式串的1号位置和主串不匹配时,模式串应该回退到0号位置进行匹配,这是理所当然的做法,也是退到无路可退。
问题4.解释if(j==-1 || sub[j] ==s[i])中j==-1这个条件
当j为-1时,说明此时模式串的第一个字符和主串不匹配,此时模式串第一个字符应该和主串的下一个字符继续比较,即应该要sub[0]和s[i+1]比较,这两种状态切换也是i++和j++的一个过程,所以可以将两者合在一起来写。
代码实现
#include<stdio.h> #include <string.h> #include <stdlib.h> void GetNext(const char *PatternStr, int *next) { int i = 1; int j = 0; next[0] = -1; next[1] = 0; int iPatLen = strlen(PatternStr); while (i < iPatLen) { if (j == -1 || PatternStr[i] == PatternStr[j]) { ++i; ++j; next[i] = j; } else { j = next[j]; } } } int KMP(const char *MainStr, const char *PatternStr) { int i = 0; int j = 0; int iMainLen = strlen(MainStr); //主串长度 int iPatLen = strlen(PatternStr); //模式串长度 int *next = (int*)malloc(sizeof(int) * iPatLen); GetNext(PatternStr, next); while (i < iMainLen && j < iPatLen) { if (j == -1 || MainStr[i] == PatternStr[j]) { ++i; ++j; } else { j = next[j]; } } if (j >= iPatLen) { return i - j; } return -1; } int main(void) { const char *MainStr = "abcdabddabc"; const char *PatternStr = "dabc"; int iPos = KMP(MainStr, PatternStr); printf("iPos = %d\n", iPos); return 0; }
在最后给出一点提醒,大家仔细看KMP()和GetNext()这两个函数,可以发现其实两者很相似,想想为什么,可以更好帮助你理解KMP算法。
相关文章推荐
- 数据结构之---C语言实现括号匹配(栈实现)
- 数据结构之串的KMP模式匹配算法的实现
- BM模式匹配算法-实现(C语言)(转)
- 一、数据结构基础之顺序表C语言实现
- 三、数据结构基础之顺序栈C语言实现
- 数据结构之kmp模式匹配
- BM模式匹配算法-实现(C语言)
- 数据结构 学习笔记之:静态链表--史上最简单的C语言实现——只为掌握概念——不清楚静态链表的鸟鸟们有福了!
- 算法:C语言实现 (第1-4部分)基础知识、数据结构……
- 六、数据结构基础之链队列C语言实现
- 数据结构之队列的实现(c语言)
- 数据结构(Data structure):用链表实现多项式的表示和运算(C语言)
- C语言实现通用数据类型栈结构
- 五、数据结构基础之循环队列C语言实现
- 数据结构课程设计:括号匹配问题(实现检验匹配并输出不匹配的位置)
- 数据结构之单链表C语言实现
- 经典算法研究:模式匹配(子串匹配)之 BM 算法(C语言实现版)初版
- 数据结构——队列(C语言实现)
- 数据结构c语言实现字符串定位(模式匹配)
- 数据结构之选择排序的实现(C语言)