数据结构- 串的模式匹配算法:BF和 KMP算法
Brute-Force算法的思想
1.BF(Brute-Force)算法
Brute-Force算法的基本思想是:
1) 从目标串s 的第一个字符起和模式串t的第一个字符进行比较,若相等,则继续逐个比较后续字符,否则从串s 的第二个字符起再重新和串t进行比较。
2) 依此类推,直至串t 中的每个字符依次和串s的一个连续的字符序列相等,则称模式匹配成功,此时串t的第一个字符在串s 中的位置就是t 在s中的位置,否则模式匹配不成功。
Brute-Force算法的实现
c语言实现:
- // Test.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <stdio.h>
- #include "stdlib.h"
- #include <iostream>
- using namespace std;
- //宏定义
- #define TRUE 1
- #define FALSE 0
- #define OK 1
- #define ERROR 0
- #define MAXSTRLEN 100
- typedef char SString[MAXSTRLEN + 1];
- /************************************************************************/
- /*
- 返回子串T在主串S中第pos位置之后的位置,若不存在,返回0
- */
- /************************************************************************/
- int BFindex(SString S, SString T, int pos)
- {
- if (pos <1 || pos > S[0] ) exit(ERROR);
- int i = pos, j =1;
- while (i<= S[0] && j <= T[0])
- {
- if (S[i] == T[j])
- {
- ++i; ++j;
- } else {
- i = i- j+ 2;
- j = 1;
- }
- }
- if(j > T[0]) return i - T[0];
- return ERROR;
- }
- void main(){
- SString S = {13,'a','b','a','b','c','a','b','c','a','c','b','a','b'};
- SString T = {5,'a','b','c','a','c'};
- int pos;
- pos = BFindex( S, T, 1);
- cout<<"Pos:"<<pos;
- }
2.KMP算法
2.1 算法思想:
每当一趟匹配过程中出现字符比较不等时,不需要回溯I指针,而是利用已经的带的“部分匹配”的结果将模式向右滑动尽可能远的一段距离后,继续进行比较。
即尽量利用已经部分匹配的结果信息,尽量让i不要回溯,加快模式串的滑动速度。
需要讨论两个问题:
①如何由当前部分匹配结果确定模式向右滑动的新比较起点k?
② 模式应该向右滑多远才是高效率的?
现在讨论一般情况:
假设 主串:s: ‘s(1) s(2) s(3) ……s(n)’ ; 模式串 :p: ‘p(1) p(2) p(3)…..p(m)’
现在我们假设 主串第i个字符与模式串的第j(j<=m)个字符‘失配’后,主串第i个字符与模式串的第k(k<j)个字符继续比较。
此时,s(i)≠p(j):
由此,我们得到关系式:即得到到1 到 j -1 的"部分匹配"结果:
‘P(1) P(2) P(3)…..P(j-1)’ = ’ S(i-j+1)……S(i-1)’
从而推导出k 到 j- 1位的“部分匹配”:即P的j-1~j-k=S前i-1~i- (k -1))位
‘P(j - k + 1) …..P(j-1)’ = ’S(i-k+1)S(i-k+2)……S(i-1)’
由于s(i)≠p(j),接下来s(i)将与p(k)继续比较,则模式串中的前(k-1)个字符的子串必须满足下列关系式,并且不可能存在 k’>k 满足下列关系式:(k<j)
有关系式: 即(P的前k- 1 ~ 1位= S前i-1~i-(k-1) )位 ) ,:
‘P(1) P(2) P(3)…..P(k-1)’ = ’S(i-k+1)S(i-k+2)……S(i-1)’
现在我们把前面总结的关系综合一下,有:
由上,我们得到关系:
‘p(1) p(2) p(3)…..p(k-1)’ = ‘p(j - k + 1) …..p(j-1)’
反之,若模式串中满足该等式的两个子串,则当匹配过程中,主串中的第i 个字符与模式中的第j个字符等时,仅需要将模式向右滑动至模式中的第k个字符和主串中的第i个字符对齐。此时,模式中头k-1个字符的子串‘p(1) p(2) p(3)…..p(k-1)’ 必定与主串中的第i 个字符之前长度为k-1 的子串 ’s(j-k+1)s(j-k+2)……s(j-1)’相等,由此,匹配仅需要从模式中的第 k 个字符与主串中的第 i 个字符比较起 继续进行。 若令 next[j] = k ,则next[j] 表明当模式中第j个字符与主串中相应字符“失配”时,在模式中需要重新和主串中该字符进行的比较的位置。由此可引出模式串的next函数:
根据模式串P的规律: ‘p(1) p(2) p(3)…..p(k-1)’ = ‘p(j - k + 1) …..p(j-1)’
由当前失配位置j(已知) ,可以归纳计算新起点k的表达式。
由此定义可推出下列模式串next函数值:
模式匹配过程:
KMP算法的实现:
第一步,先把模式T所有可能的失配点j所对应的next[j]计算出来;
第二步:执行定位函数Index_kmp(与BF算法模块非常相似)
- int KMPindex(SString S, SString T, int pos)
- {
- if (pos <1 || pos > S[0] ) exit(ERROR);
- int i = pos, j =1;
- while (i<= S[0] && j <= T[0])
- {
- if (S[i] == T[j]) {
- ++i; ++j;
- } else {
- j = next[j+1];
- }
- }
- if(j > T[0]) return i - T[0];
- return ERROR;
- }
完整实现代码:
- // Test.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <stdio.h>
- #include "stdlib.h"
- #include <iostream>
- using namespace std;
- //宏定义
- #define TRUE 1
- #define FALSE 0
- #define OK 1
- #define ERROR 0
- #define MAXSTRLEN 100
- typedef char SString[MAXSTRLEN + 1];
- void GetNext(SString T, int next[]);
- int KMPindex(SString S, SString T, int pos);
- /************************************************************************/
- /*
- 返回子串T在主串S中第pos位置之后的位置,若不存在,返回0
- */
- /************************************************************************/
- int KMPindex(SString S, SString T, int pos)
- {
- if (pos <1 || pos > S[0] ) exit(ERROR);
- int i = pos, j =1;
- int next[MAXSTRLEN];
- GetNext( T, next);
- while (i<= S[0] && j <= T[0])
- {
- if (S[i] == T[j]) {
- ++i; ++j;
- } else {
- j = next[j];
- }
- }
- if(j > T[0]) return i - T[0];
- return ERROR;
- }
- /************************************************************************/
- /* 求子串next[i]值的算法
- */
- /************************************************************************/
- void GetNext(SString T, int next[])
- { int j = 1, k = 0;
- next[1] = 0;
- while(j < T[0]){
- if(k == 0 || T[j]==T[k]) {
- ++j; ++k; next[j] = k;
- } else {
- k = next[k];
- }
- }
- }
- void main(){
- SString S = {13,'a','b','a','b','c','a','b','c','a','c','b','a','b'};
- SString T = {5,'a','b','c','a','c'};
- int pos;
- pos = KMPindex( S, T, 1);
- cout<<"Pos:"<<pos;
- }
2.2 求串的模式值next[n]
k值仅取决于模式串本身而与相匹配的主串无关。
我们使用递推到方式求next函数:
1)由定义可知:
next[1] = 0;
2) 设 next[j] = k ,这个表面在模式串中存在下列关系:
‘P(1) ….. P(k-1)’ = ‘P(j - k + 1) ….. P(j-1)’
其中k为满足1< k <j的某个值,并且不可能存在k` > 满足:
‘P(1) ….. P(k`-1)’ = ‘P(j - k` + 1) ….. P(j-1)’
此时next[j+1] = ?可能有两种情况:
(1) 若Pk = Pj,则表明在模式串中:
‘P(1) ….. P(k)’ = ‘P(j - k + 1) ….. P(j)’
并且不可能存在k` > 满足: ‘P(1) ….. P(k`)’ = ‘P(j - k` + 1) ….. P(j)’
即next[j+1] = k + 1 推到=》:
next[j+1] = next[j] + 1;
(2) 若PkPj 则表明在模式串中:
‘P(1) ….. P(k)’ ‘P(j - k + 1) ….. P(j)’
此时可把next函数值的问题看成是一个模式匹配的问题,整个模式串即是主串又是模式串,
而当前匹配的过程中,已有:
Pj-k+1 = P1, Pj-k+2 = P2,... Pj-1 = Pk-1.
则当PkPj时应将模式向右滑动至以模式中的第next[k]个字符和主串中的第 j 个字符相比较。
若next[k] = k`,且Pj= Pk`, 则说明在主串中的第j+1 个字符之前存在一个长度为k` (即next[k])的最长子串,和模式串
从首字符其长度为看k`的子串箱等。即
‘P(1) ….. P(k`)’ = ‘P(j - k` + 1) ….. P(j)’
也就是说next[j+1] = k` +1 即
next[j+1] = next[k] + 1
同理,若Pj Pk` ,则将模式继续向右滑动直至将模式串中的第next[k`]个字符和Pj对齐,
... ,一次类推,直至Pj和模式中某个字符匹配成功或者不存在k`(1< k` < j)满足,则:
next[j+1] =1;
- /************************************************************************/
- /* 求子串next[i]值的算法
- */
- /************************************************************************/
- void GetNext(SString T, int next[])
- { int j = 1, k = 0;
- next[1] = 0;
- while(j < T[0]){
- if(k == 0 || T[j]==T[k]) {
- ++j; ++k; next[j] = k;
- } else {
- k = next[k];
- }
- }
- }
注意:
(1)k值仅取决于模式串本身而与相匹配的主串无关。
(2)k值为模式串从头向后及从j向前的两部分的最大相同子串的长度。
(3)这里的两部分子串可以有部分重叠的字符,但不可以全部重叠。
next[j]函数表征着模式P中最大相同前缀子串和后缀子串(真子串)的长度。
可见,模式中相似部分越多,则next[j]函数越大,它既表示模式T字符之间的相关度越高,也表示j位置以前与主串部分匹配的字符数越多。
即:next[j]越大,模式串向右滑动得越远,与主串进行比较的次数越少,时间复杂度就越低(时间效率)。
数据结构- 串的模式匹配算法:BF和 KMP算法的更多相关文章
- 字符串模式匹配算法--BF和KMP详解
1,问题描述 字符串模式匹配:串的模式匹配 ,是求第一个字符串(模式串:str2)在第二个字符串(主串:str1)中的起始位置. 注意区分: 子串:要求连续 (如:abc 是abcdef的子串) ...
- 串、串的模式匹配算法(子串查找)BF算法、KMP算法
串的定长顺序存储#define MAXSTRLEN 255,//超出这个长度则超出部分被舍去,称为截断 串的模式匹配: 串的定义:0个或多个字符组成的有限序列S = 'a1a2a3…….an ' n ...
- 【Java】 大话数据结构(8) 串的模式匹配算法(朴素、KMP、改进算法)
本文根据<大话数据结构>一书,实现了Java版的串的朴素模式匹配算法.KMP模式匹配算法.KMP模式匹配算法的改进算法. 1.朴素的模式匹配算法 为主串和子串分别定义指针i,j. (1)当 ...
- 《数据结构》之串的模式匹配算法——KMP算法
//串的模式匹配算法 //KMP算法,时间复杂度为O(n+m) #include <iostream> #include <string> #include <cstri ...
- 大话数据结构(8) 串的模式匹配算法(朴素、KMP、改进算法)
--喜欢记得关注我哟[shoshana]-- 目录 1.朴素的模式匹配算法2.KMP模式匹配算法 2.1 KMP模式匹配算法的主体思路 2.2 next[]的定义与求解 2.3 KMP完整代码 2.4 ...
- 数据结构学习之字符串匹配算法(BF||KMP)
数据结构学习之字符串匹配算法(BF||KMP) 0x1 实验目的 通过实验深入了解字符串常用的匹配算法(BF暴力匹配.KMP.优化KMP算法)思想. 0x2 实验要求 编写出BF暴力匹配.KM ...
- 【算法】串的模式匹配算法(KMP)
串的模式匹配算法 问题: 求子串位置的定位函数如何写? int index(SString S,SString T,int pos); 给定串S,子串T,问T在 ...
- 字符串模式匹配算法1 - BF和KMP算法
在字符串S中定位/查找某个子字符串P的操作,通常称为字符串的模式匹配,其中P称为模式串.模式匹配有多种算法,这里先总结一下BF算法和KMP算法. 注意:本文在讨论字符位置/指针/下标时,全部使用C语法 ...
- 串的模式匹配算法 ------ KMP算法
//KMP串的模式匹配算法 #include <stdio.h> #include <stdlib.h> #include <string.h> int* get_ ...
随机推荐
- 基于HTTP协议下载文件的实现
最近在开发文件下载的程序,该程序是基于HTTP开发的. 首先是了解了文件传输到客户端的大概格式,然后分析该格式,实现写入文件的功能. 自己构造的HTTP包如下: GET /*********.rar ...
- Labview学习之远程控制VI
Labview学习之远程控制VI 从LabVIEW 6.1开始,LabVIEW集成了Remote Panels技术,允许用户直接在客户端计算机上打开并操作位于服务器端计算机上的VI的前面 ...
- vi、vim 配置上下左右方向键和删除键
vi.vim 配置上下左右方向键和删除键 " An example for a vimrc file. " " Maintainer: Bram Moolenaar &l ...
- 输入输出函数库stdio.h
函数名 函数类型与形参类型 函数功能 函数返回值 clearerr void clearerr(fp) FILE * fp; 清除文件指针错误 无 close int close(fp) int fp ...
- Web开发者需具备的8个好习惯
优秀的Web开发人员工作效率更高,因为他们拥有丰富的经验和良好的习惯.作者Gregor Dorfbauer分享了用于Web开发中的8个好习惯,这些良好的工作习惯不仅能提高效率,还能让您创建更加优秀的应 ...
- 常见iis错误之一
1.win7配置iis 出现:HTTP 错误 403.14 - Forbidden 打开 IIS 管理器. 在“功能”视图中,双击“目录浏览”. 在“目录浏览”页上,在“操作”窗格中单击“启用”. 确 ...
- CDN库地址搜集2
常用开源库 http://open.bootcss.com/
- cloneNode小结
js原生API中有个cloneNode,还有一个可选的参数, true代表复制子节点,包括任何包裹在标签之间的东西,当然包括文本节点,也就是标签之间有什么,它就会不假思索的全部都克隆一份. false ...
- kohana(3.2)和gleez(1.1.5)的安装
*保证在kohanna的环境下安装gleez 一.配置虚拟主机(即添加端口:例如localhost:801) 以http://www.gleezcms.com为例 1: cd /etc/apache2 ...
- css学习笔记四
广州天气变冷了,css学习笔记还是要总结. 总结: 1:几米页面静态页面主要是一列结构头部banner图,mainbody部分放文字内容和图书图片,底部是页面的版权信息 2:腾讯软件中心静态页面制作( ...