串的模式匹配算法
一、基本概念
1、模式匹配(定位)
设有主串S和子串T(将S称为目标串,将T称为模式串),在主串S中,从位置start开始查找,如若在主串S中找到一个与子串T相等的子串,则返回T的第一个字符在主串中的位置,否则返回-1。
2、算法目的
确定主串中所含子串第一次出现的位置(定位)
3、算法种类
BF算法 (又称古典的、经典的、朴素的、穷举的)
KMP算法
1、Brute-Force算法的设计思想:
• 将主串S的第一个字符和模式T的第1个字符比较,
若相等,继续逐个比较后续字符;
若不等,从主串S的下一字符起,重新与T第一个字符比较。
• 直到主串S的一个连续子串字符序列与模式T相等。返回值为S中与T匹配的子序列第一个字符的序号,即匹配成功。
否则,匹配失败,返回值 -1。
2、 Brute-Force算法的实现
typedef struct
{ char str[MaxSize];
int length;
}String;
int BFIndex(String S, int start, String T)
{ int i = start, j = 0, v;
while(i < S.length && j < T.length)
{ if(S.str[i] == T.str[j]) {i++; j++; }
else{ i = i-j+1; j = 0; }
}
if (j==T.length) v=i-T.length;
else v=-1;
return v;
}
3、BF算法的时间复杂度
讨论:
若n为主串长度,m为子串长度,则串的BF匹配算法最坏的情况下需要比较字符的总次数为(n-m+1)*m=O(n*m)
最好的情况是:一配就中! 只比较了m次。
最恶劣情况是:主串前面n-m个位置都部分匹配到子串的最后一位,即这n-m位比较了m次,别忘了最后m位也各比较了一次,还要加上m!所以总次数为:(n-m)*m+m =(n-m+1)*m
能否利用已部分匹配过的信息而加快模式串的滑动速度?
能!而且主串S的指针i不必回溯!最坏情况也能达到O(n+m)
请看KMP算法!
三、KMP算法
1、KMP算法设计思想:
尽量利用已经部分匹配的结果信息,尽量让i不要回溯,加快模式串的滑动速度。
如图:
需要讨论两个问题:
①如何由当前部分匹配结果确定模式向右滑动的新比较起点k?
② 模式应该向右滑多远才是高效率的?
如图:
新起点 k怎么求?
根据模式串T的规律: “T0…Tk-1”=“Tj-k …Tj-1”
由当前失配位置j(已知) ,可以归纳计算新起点 k的表达式。
如图:
(1)k值仅取决于模式串本身而与相匹配的主串无关。
(2)k值为模式串从头向后及从j向前的两部分的最大相同子串的长度。
(3)这里的两部分子串可以有部分重叠的字符,但不可以全部重叠。
next[j]函数表征着模式T中最大相同前缀子串和后缀子串(真子串)的长度。
可见,模式中相似部分越多,则next[j]函数越大,它既表示模式T字符之间的相关度越高,也表示j位置以前与主串部分匹配的字符数越多。
即:next[j]越大,模式串向右滑动得越远,与主串进行比较的次数越少,时间复杂度就越低(时间效率)。
再想一想:如果主串是外存中一个大文件,用KMP算法效果又如何?
如图:
下一个要讨论的问题是:如何用递推方式来求出最大相同子串的长度呢?这个问题一旦解决,整个KMP算法就可以掌握得很透彻了。
求子串next[i]值的算法:
void GetNext(String T, int next[])
{ int j = 0, k = 0;
next[0] = -1;
while(j < T.length){
if(T.str[j]==T.str[k])
{ next[j+1]=k+1; j++; k++; }
else if (k==0){ next[j+1]=0; j++; }
else k=next[k];
}
}
KMP算法的思想
设s为主串,t为模式串,设i为主串s当前比较字符的下标,j为模式串t当前比较字符的下标,令i和j的初值为0。当si = tj时,i和j分别增1再继续比较;否则 i不变,j改变为next[j]值(即模式串右滑)后再继续比较。依次类推,直到出现下列两种情况之一:一是 j退回到某个j=next[j]值时有si = tj ,则 i和j分别增1后再继续比较;二是j退回到j=-1时,令主串和子串的下标各增1,随后比较si+1和t0 。这样的循环过程一直进行到变量大于等于S.length或变量j大于等于T.length时为止。
KMP算法的实现
第一步,先把模式T所有可能的失配点j 所对应的next[j]计算出来;
第二步:执行定位函数Index_kmp (与BF算法模块非常相似)
int KMPIndex(String S, int start,String T, int next[ ])
{int i=start,j=0,v;
while ( i<=S.length && j<T.length ) {
if (j==-1|| S.str[i] = = T.str[j] ) {i++; j++ } //不失配则继续比较后续字符
else j=next[j]; //特点:S第一步,先把模式T所有可能的失配点j 所对应的next[j]
}
if(j==T.length) v=I-T.length;
else v=-1;
return v;
}
主函数
void main(void)
{ String S = {{"cddcdc"}, 6}, T = {{"cdc"}, 3};
int next[8], pos;
GetNext(T, next);
pos = KMPIndex(S, 0, T, next);
printf("pos = %d\n", pos);
}
2、KMP算法的时间复杂度
回顾BF的最恶劣情况:S与T之间存在大量的部分匹配,比较总次数为: (n-m+1)*m=O(n*m)
而此时KMP的情况是:由于指针i无须回溯,比较次数仅为n,即使加上计算next[j]时所用的比较次数m,比较总次数也仅为n+m=O(n+m),大大快于BF算法
注意:由于BF算法在一般情况下的时间复杂度也近似于O(n+m),所以至今仍被广泛采用。
KMP算法的用途:
因为主串指针i不必回溯,所以从外存输入文件时可以做到边读入边查找——“流水作业”
如图:
- 大小: 26.5 KB
- 大小: 77.9 KB
- 大小: 24.1 KB
- 大小: 78.4 KB
- 大小: 34.6 KB
分享到:
相关推荐
KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法。简单匹配算法的时间复杂度为O(m*n);KMP匹配算法。可以证明它的时间复杂度为O(m+n).。 一.简单匹配算法 先来看一个简单匹配算法的函数: ...
在此背景下,Boyer和Moore于1977年提出了一种革命性的字符串匹配算法——Boyer-Moore算法,该算法不仅在理论上具有线性时间复杂度的优势,在实际应用中也展现出极高的效率,尤其是在处理长文本和模式时。随后,R....
总的来说,"基于BF和KMP的串模式匹配算法设计与实现(C语言)"这一资源提供了从理论到实践的全面讲解,无论是对算法的理解还是编程技巧的提升,都具有很高的学习价值。通过阅读和实践,读者可以深入理解串模式匹配的...
Wu-Manber多模式匹配算法是一种高效且实用的字符串搜索算法,尤其在处理大量模式字符串时表现优秀。该算法由Michael Wu和Steven Manber于1992年提出,其主要目的是解决在一个大文本中同时查找多个模式字符串的问题。...
算法的基本思想是从文本串的起始位置开始,逐个字符与模式串进行比较,如果发现不匹配,则将文本串的指针向右移动一位,然后再次尝试匹配。这个过程一直持续到找到匹配或者文本串的结束。朴素串匹配算法虽然简单易懂...
在探讨数据结构教学方法时,字符串模式匹配算法是一个重要的议题。字符串是计算机处理文本编辑问题时常用的数据结构,而模式匹配算法是进行此类操作时最基础的操作之一。文章中提到的BF算法和KMP算法,是字符串模式...
入侵检测系统(IDS)作为网络安全的第一道防线,其核心功能之一是通过模式匹配算法来识别网络流量中的恶意行为。传统的单模式字符串匹配算法,如KMP算法、Boyer-Moore算法等,在处理单一模式串时表现出色,但在面对...
在朴素模式匹配算法中,当模式串和目标串之间的某个字符不匹配时,通常会将目标串向右移动一个位置,然后从头开始再次比较。而KMP算法通过构建一个辅助数组`next[]`,使得在发生失配时能够快速跳过一些比较,从而...
简单字符串匹配算法是最基础的一种方法,其基本思想是从文本串的第一个字符开始,逐个比较文本串中的字符与模式串中的字符是否相同。如果全部字符都匹配,则表示找到模式串;如果有任何字符不匹配,则将模式串向右...
- 主串与模式串匹配:从主串S的起始位置和模式串P的起始位置开始比较,如果当前字符匹配,则移动主串和模式串的指针;若不匹配,则根据部分匹配表确定模式串的下一个位置,继续比较,直到找到匹配或模式串遍历完。 ...
一种基于Bloomfilter的高速浮动关键词匹配算法 ...10. FSLSPM算法的意义:FSLSPM算法的提出解决了传统浮动关键词匹配算法的缺陷,具有重要的理论和实践意义,对大规模网络和数据挖掘系统的发展具有重要影响。
KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,由Donald Knuth、James H. Morris以及Vaughan Pratt共同提出。该算法针对传统的BF(Brute-Force)算法进行了优化,避免了不必要的回溯操作,从而将时间...
这里我们将深入探讨HString(哈希字符串)的基本操作以及模式匹配算法,特别是KMP(Knuth-Morris-Pratt)算法的实现。 首先,HString是一种基于哈希函数的数据结构,用于高效地存储和操作字符串。它通过将字符串...
Simon算法是一种利用随机化思想的字符串匹配算法,适用于大规模数据集。 - **描述:** 通过随机选取文本串的一部分,与模式串进行比较,以减少不必要的完全比较次数。 - **代码:** 需要设计随机选择策略和比较逻辑...
正则表达式匹配算法依赖于有穷自动机理论,将正则表达式转化为状态机,然后在输入数据中搜索符合该状态机的所有可能模式。FPGA实现的算法可以根据具体需求构建不同的自动机模型,以适应不同的匹配任务。 4. 算法...
传统的简单匹配算法(例如朴素字符串匹配算法)会在遇到不匹配的情况下回溯并重新尝试,这种方法的时间复杂度最高可达\(O(nm)\),其中\(n\)为文本串`T`的长度,\(m\)为模式串`P`的长度。 #### 三、KMP算法原理 ###...