几种常见的字符串匹配算法

article/2025/9/21 11:55:23

转自http://www.360doc.com/content/14/0325/15/15064667_363609292.shtml

1. 朴素算法

朴素算法是最简单的字符串匹配算法,也是人们接触得最多的字符串匹配算法。代码一看就懂,在此不在赘述。

#include<stdio.h>
#include<string.h>
void search(char *pat, char *txt)
{int M = strlen(pat);//计算字符串长度int N = strlen(txt);/* A loop to slide pat[] one by one */for (int i = 0; i <= N - M; i++){int j;/* For current index i, check for pattern match */从i=0开始匹配,匹配过程中中发现其中一个字符不一样,退出然后向右移1位,for (j = 0; j < M; j++){if (txt[i+j] != pat[j])break;}if (j == M)  // if pat[0...M-1] = txt[i, i+1, ...i+M-1]  //如果j的计算次数达到字符串pat的长度时,取此时的i值作为匹配开始位。{printf("Pattern found at index %d \n", i);}}
}/* Driver program to test above function */
int main()
{char *txt = "AABAACAADAABAAABAA";char *pat = "AABA";search(pat, txt);getchar();return 0;
}

朴素算法有两层循环,外层循环执行N-M+1次,内层循环执行M次,所以它的时间复杂度为O((N-M+1)*M)。

参考资料:http://www.geeksforgeeks.org/searching-for-patterns-set-1-naive-pattern-searching/

2. Rabin-Karp算法

我们再来看一个时间复杂度为O((N-M+1)*M)的字符串匹配算法,即Rabin-Karp算法。Rabin-Karp算法的预处理时间是O(m), 匹配时间OO((N-M+1)*M),既然与朴素算法的匹配时间一样,而且还多了一些预处理时间,那为什么我们 还要学习这个算法呢?

虽然Rain-Karp在最坏的情况下与朴素的世间复杂度一样,但是实际应用中往往比朴素算法快很多。而且该算法的 期望匹配时间是O(N+M)(参照《算法导论》)。

在朴素算法中,我们需要挨个比较所有字符,才知道目标字符串中是否包含子串。那么, 是否有别的方法可以用来判断目标字符串是否包含子串呢?

答案是肯定的,确实存在一种更快的方法。为了避免挨个字符对目标字符串和子串进行比较, 我们可以尝试一次性判断两者是否相等。因此,我们需要一个好的哈希函数(hash function)。 通过哈希函数,我们可以算出子串的哈希值,然后将它和目标字符串中的子串的哈希值进行比较。 这个新方法在速度上比暴力法有显著提升。

Rabin-Karp算法的思想:

  1. 假设子串的长度为M,目标字符串的长度为N
  2. 计算子串的hash值
  3. 计算目标字符串中每个长度为M的子串的hash值(共需要计算N-M+1次)
  4. 比较hash值
  5. 如果hash值不同,字符串必然不匹配,如果hash值相同,还需要使用朴素算法再次判断

为了快速的计算出目标字符串中每一个子串的hash值,Rabin-Karp算法并不是对目标字符串的 每一个长度为M的子串都重新计算hash值,而是在前几个字串的基础之上, 计算下一个子串的 hash值,这就加快了hash之的计算速度,将朴素算法中的内循环的世间复杂度从O(M)将到了O(1)。

关于hash函数的详细内容,可以参考这里或者《算法导论》。

下面是一个Rabin-Karp算法的实现:

/* Following program is a C implementation of the Rabin Karp Algorithm given in the CLRS book */#include<stdio.h>
#include<string.h>// d is the number of characters in input alphabet d是输入字母表中的字符数
#define d 256 /*  pat  -> patterntxt  -> textq    -> A prime number
*/
void search(char *pat, char *txt, int q)
{int M = strlen(pat);int N = strlen(txt);int i, j;int p = 0;  // hash value for patternint t = 0; // hash value for txtint h = 1;// The value of h would be "pow(d, M-1)%q"  计算h的值for (i = 0; i < M-1; i++)h = (h*d)%q;// Calculate the hash value of pattern and first window of textfor (i = 0; i < M; i++) //p和t是hash值{p = (d*p + pat[i])%q;t = (d*t + txt[i])%q;}// Slide the pattern over text one by one for (i = 0; i <= N - M; i++)   //匹配hash值{// Chaeck the hash values of current window of text and pattern// If the hash values match then only check for characters on by oneif ( p == t ){/* Check for characters one by one */for (j = 0; j < M; j++){if (txt[i+j] != pat[j])break;}if (j == M)  // if p == t and pat[0...M-1] = txt[i, i+1, ...i+M-1]{printf("Pattern found at index %d \n", i);}}// Calulate hash value for next window of text: Remove leading digit, // add trailing digit           if ( i < N-M ){t = (d*(t - txt[i]*h) + txt[i+M])%q;// We might get negative value of t, converting it to positiveif(t < 0) t = (t + q); }}
}/* Driver program to test above function */
int main()
{char *txt = "GEEKS FOR GEEKS";char *pat = "GEEK";int q = 101;  // A prime numbersearch(pat, txt, q);getchar();return 0;
}

参考资料:http://www.geeksforgeeks.org/searching-for-patterns-set-3-rabin-karp-algorithm/

3. KMP算法

KMP算法是一个比较难以理解的算法。国内非顶尖的大学数据结构大都使用的是清华严老师的 《数据结构》,这本书在第四章讲到了KMP算法,我认真看了两遍没有看懂。到现在我终于明白 了以后,我想说,真的是严老师实在讲得太烂了。

KMP算法要讲清楚很不容易,网络上一搜一大堆材料,看完还是似懂非懂。我不准备再讲一遍, 我也不相信自己会讲得比网络上大多数文章讲得好,在此给大家推荐阮一峰老师的《字符串匹配的KMP算法》。

学习KMP算法请牢记两点:

  1. KMP算法的思想就是,当子串与目标字符串不匹配时,其实你已经知道了前面已经匹配成功那 一部分的字符(包括子串与目标字符串)。以阮一峰的文章为例,当空格与D不匹配时,你其实 知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置" 移回已经比较过的位置,继续把它向后移,这样就提高了效率

    img1

  2. 部分匹配表是模式自己与自己的匹配

下面推荐几个KMP算法的练习:

4. Boyer-Moore算法

待补充。http://blog.jobbole.com/52830/

5. Sunday算法

http://blog.163.com/yangfan876@126/blog/static/80612456201342205056344


http://chatgpt.dhexx.cn/article/gCS8Mtr5.shtml

相关文章

字符串匹配算法——JavaScript

字符串匹配算法——javascript 文章目录 字符串匹配算法——javascript字符串匹配BF算法 &#xff08;暴力匹配&#xff09; √KMP算法 √BM算法**坏字符规则**好后缀规则 Trid树&#xff08;字典树&#xff09;√ 字符串匹配 字符串匹配问题的形式定义&#xff1a; **文本&a…

数据结构与算法--字符串匹配算法

目录 概要 单模式与多模式的区别 单模式匹配算法 BF算法 概念 代码实现 时间复杂度 应用 RK算法 概念 代码实现 时间复杂度 应用 BM算法 概念 算法原理 代码实现 时间复杂度 应用 多模式匹配算法 Trie树 概念 Trie树的插入 Trie树的查找 代码实现 时间复杂度 应用 概要 字符…

简单高效的字符串匹配算法

Quick Search算法 算法简介 Quick Search算法属于Sunday算法的一种。Sunday算法由Daniel M Sunday在1990年提出。论文原文&#xff1a;A VERV FAST SU6STRINC SEARCH ALGORITHM 在论文中&#xff0c;作者提出了三个不同的算法&#xff1a;Quick Search算法、Maximal Shift算…

算法之字符串匹配

字符串匹配&#xff1a;设 S 和 T 是给定的两个串&#xff0c;在主串 S 中找到模式串 T 的过程称为字符串匹配&#xff0c;如果在主串 S 中找到模式串 T &#xff0c;则称匹配成功&#xff0c;函数返回 T 在 S 中首次出现的位置&#xff0c;否则匹配不成功&#xff0c;返回 -1。…

经典字符串匹配算法——KMP算法

KMP算法 KMP算法是一种高效的字符串匹配算法&#xff0c;在传统暴力遍历匹配的基础上做了一定的优化。 首先KMP算法的实现也是使用了回退思想&#xff0c;不过与暴力遍历不同&#xff0c;KMP的回退&#xff0c;是让子串进行匹配&#xff0c;而不是主串。 KMP示例 首先我们来…

16.算法之字符串匹配算法

前言 字符串匹配是我们在程序开发中经常遇见的功能&#xff0c;比如sql语句中的like,java中的indexof,都是用来判断一个字符串是否包含另外一个字符串的。那么&#xff0c;这些关键字&#xff0c;方法&#xff0c;底层算法是怎么实现的么&#xff1f;本节&#xff0c;我们来探…

字符串匹配算法(BM)

文章目录 1. BM&#xff08;Boyer-Moore&#xff09;算法1.1 坏字符规则1.2 好后缀规则1.3 两种规则如何选择 2. BM算法代码实现2.1 坏字符2.2 好后缀2.3 完整代码2.4 调试 3. 总结 1. BM&#xff08;Boyer-Moore&#xff09;算法 思想&#xff1a;有模式串中不存在的字符&…

六种字符串匹配算法详解(含代码演示)

1. Brute-Force算法 2. Rabin-Karp Hash算法 3. Kmp算法 4. Kmp的优化算法 5. Sunday算法 6. Shift-And算法 ps&#xff1a;字符串匹配其实是单模匹配问题 1.Brute-Force 朴素匹配算法&#xff08;暴力匹配&#xff09; 时间复杂度&#xff1a;O(n*m) //返回 文本串s中第一…

字符串匹配算法(BF、KMP)

BF算法 描述&#xff1a; BF&#xff0c;Brute Force&#xff0c;暴力匹配的意思&#xff0c;是最简单直观的字符串匹配算法。假设有主串s1和子串s2&#xff0c;根据BF算法判断s1是否包含s2的步骤如下&#xff1a; 初始下标指针 i, j 分别指向s1, s2的首位置&#xff0c;若s1…

这可能是全网最好的字符串匹配算法讲解

点击上方 好好学java &#xff0c;选择 星标 公众号重磅资讯&#xff0c;干货&#xff0c;第一时间送达 今日推荐&#xff1a;14 个 github 项目&#xff01;个人原创100W 访问量博客&#xff1a;点击前往&#xff0c;查看更多为保证代码严谨性&#xff0c;文中所有代码均在 le…

Spring boot 项目(五)——AOP切面

一、AOP简介 1、在软件业&#xff0c;AOP为Aspect Oriented Programming的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。 2、AOP是OOP的延续&#xff0c;是软件开发中的一个热点&#xff0c;也…

Spring AOP 切面(Aspect)应用详解

1. AOP 切面应用 下面是一个AOP切面的一个简单的应用实例 引入AOP依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>创建切面类对象 Aspect Component pub…

springboot实现AOP切面编程

概述 AOP(Aspect Oriented Programming) 即面向切面编程。面向切面是面向对象中的一种方式而已。在代码执行过程中&#xff0c;动态嵌入其他代码&#xff0c;叫做面向切面编程&#xff08;将交叉业务逻辑封装成成切面&#xff0c;利用AOP功能将切面织入到主业务逻辑———与主…

spring AOP切面及日志记录实现

目录 1.什么是AOP切面 2.理解AOP 3.AOP实例 1.自定义注解 2.创建一个切面类 3.将自定义注解标注在测试接口上 1.什么是AOP切面 AOP&#xff08;Aspect Oriented Programming&#xff09;&#xff0c;面向切面思想&#xff0c;是Spring的三大核心思想之一。 在项目中经常…

Aop切面自定义注解的使用

一&#xff1a;功能简介 本文主要记录如何使用aop切面的方式来实现日志记录功能。 主要记录的信息有: 操作人&#xff0c;方法名&#xff0c;参数&#xff0c;运行时间&#xff0c;操作类型(增删改查)&#xff0c;详细描述&#xff0c;返回值。 二&#xff1a;项目结构图 三…

AOP切面注解

一.前言 在以前的项目中&#xff0c;很少去关注spring aop的具体实现与理论&#xff0c;只是简单了解了一下什么是aop具体怎么用&#xff0c;看到了一篇博文写得还不错&#xff0c;就转载来学习一下&#xff0c;博文地址&#xff1a;http://www.cnblogs.com/xrq730/p/4919025.h…

AOP切面执行顺序

文章目录 一. 概述二. 讲述1. 单切面中各通知方法的执行顺序2. 多切面中各通知方法的执行顺序3. 多切面的通知方法中抛出异常 参考资料 一. 概述 本文主要讲述以下几点 单AOP切面时&#xff0c;各通知方法的执行顺序。多AOP切面时&#xff0c;多切面的执行顺序和各通知方法的执…

spring aop切面执行顺序

spring aop切面执行顺序 切面执行顺序 现有切面1、切面2对同一个切点按先后顺序执行&#xff08;切面1先于切面2执行&#xff09; 切面1&#xff1a;Before、After、AfterReturnning、AfterThrowing、Around 执行前、Around 正常执行、Around 异常执行、Around 执行后切面2&am…

一文带你搞定AOP切面

摘要&#xff1a;AOP在spring中又叫“面向切面编程”&#xff0c;是对传统我们面向对象编程的一个补充&#xff0c;主要操作对象就是“ 切面”&#xff0c; 可以简单的理解它是贯穿于方法之中&#xff0c;在方法执行前、执行时、执行后、返回值后、异常后要执行的操作。 本文分…

SpringBoot AOP切面实现

文章目录 一、AOP简介二、AOP体系与概念三、AOP实例1、创建SpringBoot工程2、添加依赖3、AOP相关注解3.1、Aspect3.2、Pointcut3.2.1、execution()3.2.2、annotation() 3.3、Around3.4、Before3.5、After3.6、AfterReturning3.7、AfterThrowing 一、AOP简介 AOP&#xff08;As…