字符串查找:

BF算法:

(朴素查找算法)

当查找不成功时,主串返回刚刚起始字符的下一个,子串返回第一个字符位置

时间复杂度:O(n*m)

int BF(const char* str, const char* sub, int pos)//pos开始查找的位置
{assert(str!=NULL && sub!=NULL);if(pos<0){pos=0;}int lenstr=strlen(str);int lensub=strlen(sub);int i=pos;int j=0;while(i<lenstr && j<lensub){if(sub[i]==str[j]){i++;j++;}else{i=i-j+1;j=0;}}if(j>=lensub)//只要子串都走完就是找到{return i-j;}else{return -1;}
}
  • BF算法很简单,只需记得失配后子串回退到第一个字符,主串回退到上次开始匹配的字符的下一个;主串为什么要回退:

如图,在红线处失配后,如果i 不回退,那么将匹配失败,但其实可以成功,只是因为i 不回退导致了漏配。

KMP算法:

static void Get(const char* sub, int *next)
{int lensub=strlen(sub);//算出每一个字符的K 值int next[0]=-1;int next[1]=0;int j=1;int k=0;while(j+1<lensub){if(k==-1 || sub[j]==sub[k]){next[j+1]=k+1;j++;k++;}//修正后/*if(k==-1 || sub[j]==sub[k]){++j;++k;if(sub[j]!=sub[k]) {next[j]=k; }else {next[j]=next[k];}}*/else{k=next[k];}}
}int KMP(const char* str, const char* sub, int pos)
{assert(str!=NULL && sub!=NULL);if(pos<0){pos=0;}int *next=(int*)malloc(sizeof(int));Get(sub, next);if(next==NULL){printf("error");return -2;}int lenstr=strlen(str);int lensub=strlen(sub);int i=pos;int j=0;while(i<lenstr && j<lensub){if(j==-1 || sub[j]==str[i]){i++;j++;}else{//i不回退j=next[j];}}free(next);if(j>=lensub){return i-j;}else{return -1;}
}

KMP算法时间复杂度只有O(n+m),原因是i 不回退,j每次回退到下标k 位置处,再次匹配就会成功,所以框架和BF类似,核心算法就是寻找k 位置。

1、首先来说为什么i 不需要回退:

P:主串

S:模式串

如图,当在红线位置失配时,在i, j 都回退后,再次匹配时,i 还是会到之前的位置(如果不理解的话可以根据BF的算法自己在纸上画一下,就会发现i 的回退是多余的,重复的,对于BF算法提到的特殊情况也是一样的道理)

如图,在红线失配后,按照KMP算法,i 不会退,j 只需要回退到(k=2)位置处,接下来即可匹配成功,大大降低了时间复杂度,所以接下来就需要计算K值。

在失配前:

因为两个字符串相等的话长度也相等,所以下标差值肯定相等即可推出。

假设此时主串应该与模式串中第k(该例中k = 2)个字符继续比较,也就是说j 回退到该位置就可以匹配成功,那么模式串中k-1 个字符肯定满足:

根据(1)式,可以构造出:

因为k<j,所以Si-k...Si-1肯定是Si-j...Si-1的子串,Px...Pj-1肯定也是P0...Pj-1的子串,所以相等字符串的子串只要二者对应长度相等那么这两个子串也相等。

根据(2)(3)推出:

则在子串失配前找到两个相等的真子串,且满足如下特点:

1、一个串以P0做为开头

2、另一个串以失配前的最后一个字符作为结尾

k就是该真子串的长度。

  • 那么对于每一个字符(每一个字符都有失配的可能)都有一个相应的k 值,存放在next[]数组中,当失配时,就取在next数组中相应的k值,现在就需要构建next数组。

规定字符串前两个的k 值为-1,0(也可以0,1需要修改相应代码),计算K 值的原理就是根据已经规定的K 的值来计算后面字符的K 值,这里有两种情况:

1、Pk==Pj:

根据推导可以看出Pk==Pj,就等于直接给满足条件的前后两个真子串长度各加一个相同字符,自然而然k 也就加 1,所以next[j+1]=k+1;

2、Pk!=Pj:

此时可以将求next 函数值的问题又看成一个模式匹配的问题,只不过此时的模式串是主串,子串是模式串的子串

(P0...Pk)

k=next[k],前部分的next数组已经构建,所以是直接获取值,之后继续匹配,在该算法中k 值会被置为-1,所以要加判断。

此时还可以继续优化该算法,因为当前算法在某些情况下还有缺陷:

如图,下标为3处失配,按照next数组,还需要i = 3, j = 1; i=3, j=0; i=3,j=-1,这三次比较,实际上,因为模式串中前四个字符都相等,因此不需要再和主串第四个字符比较,而是将模式串直接向右滑动4个字符的位置,直接和主串第五个字符比较即可。

当next[j]==k,模式串中Pj==Pk时,对于主串如果Sj != Pj ,就不需要再和Pk比较,而是和Pnext[k]比较,此时next[j]应该等于next[k]

  • BF算法和KMP算法在一般情况下,BF其实近似于KMP,所以BF由于其简单易懂仍在被沿用,但是当主串与模式串存在许多“部分匹配”的情况下KMP算法就会快很多(因为对于BF,主串与模式串总是在匹配部分后i,j又要回退,这样的次数增多就会耗时);

  • 由于KMP只需对于主串从头到尾扫描一遍,所以对处理从外设输入的庞大文件很有效,可以边读边匹配,无需回头重读;

字符串查找算法BF、KMP详解相关推荐

  1. python字符串find函数-python字符串查找函数的用法详解

    python字符串查找函数的使用 打开Python开发工具IDLE,新建"findstr.py'文件,并写代码如下: s ='/ab/bx,.s' print (s.find('/x')) ...

  2. java二分查找法_java算法之二分查找法的实例详解

    java算法之二分查找法的实例详解 原理 假定查找范围为一个有序数组(如升序排列),要从中查找某一元素,如果该元素在此数组中,则返回其索引,否则返回-1.通过数组长度可取出中间位置元素的索引,将其值与 ...

  3. linux shell 字符串操作(长度,查找,替换)详解 BASH

    linux shell 字符串操作(长度,查找,替换)详解 在做shell批处理程序时候,经常会涉及到字符串相关操作.有很多命令语句,如:awk,sed都可以做字符串各种操作. 其实shell内置一系 ...

  4. c语言实现sha1算法注解,【密码学】SHA1算法实现及详解

    1 SHA1算法简介 安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digit ...

  5. python如何调用文件进行换位加密_python 换位密码算法的实例详解

    python 换位密码算法的实例详解 一前言: 换位密码基本原理:先把明文按照固定长度进行分组,然后对每一组的字符进行换位操作,从而实现加密.例如,字符串"Error should neve ...

  6. python字符串_Python字符串格式化%s%d%f详解

    关于讨论输出格式化的问题,小编不是一时兴起,之前学习python的时候就经常遇到输出时"%d",一直没有仔细学习,今天又看到了,下面分享一个简单实例,python输出99乘法表: ...

  7. python 字符串格式化%s_Python字符串格式化%s%d%f详解

    关于讨论输出格式化的问题,小编不是一时兴起,之前学习python的时候就经常遇到输出时"%d",一直没有仔细学习,今天又看到了,下面分享一个简单实例,python输出99乘法表: ...

  8. python字符串格式化详解_Python字符串格式化%s%d%f详解

    Python字符串格式化%s%d%f详解 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  Python字符串格式化%s%d%f详解.txt ] (友情提示:右键点上 ...

  9. python bisect_Python实现二分查找与bisect模块详解

    前言 其实Python 的列表(list)内部实现是一个数组,也就是一个线性表.在列表中查找元素可以使用 list.index()方法,其时间复杂度为O(n) .对于大数据量,则可以用二分查找进行优化 ...

最新文章

  1. 有赞分层自动化测试实践
  2. Java程序中Timer的用法
  3. (转)SpringBoot系列—Redis使用
  4. onnxruntime安装
  5. 获取NT的admin权限的方法
  6. 只需 4 步,自己搞个 Spring Boot Starter!
  7. 从html到pug模板,将变量从html-webpack-plugin传递到pug模板
  8. python写软件测试用例_Python单元测试框架unittest:单个测试用例编写步骤及实例...
  9. memcpy的两种实现(转)
  10. VBB Arduino仿真软件的使用
  11. 华为手机更改系统默认字体
  12. PyCharm快捷键
  13. android圆形图片裁剪demo以及实现
  14. UE4_编辑器UMG关闭窗口不能立刻销毁UMG
  15. JSON for modern c++ / nlohmann
  16. 拉卡拉支付率先布局B端市场
  17. 又一大的技术站点域名被ClientHold了
  18. 什么样的项目算是成功的?项目目标有什么特点?
  19. Android~ java.net.BindException: bind failed: EADDRINUSE (Address already in use)
  20. [OHIF-Viewers]医疗数字阅片-医学影像-事件总线管理器

热门文章

  1. HTML期末作业课程设计期末大作业——体育排球5页面带注册HTML+CSS+JS(学生网页设计作业源码)
  2. es6 字符串的扩展
  3. python 在一个py文件中调用另一个py文件中的变量以及一个有趣的问题
  4. 深度特写|那些想破解苹果FaceID的顶级黑客,失败了!
  5. 一文看懂推荐系统:物品冷启02:简单的召回通道
  6. 最近收集的一些图片(第2期)
  7. 实战分享,百家号怎么赚钱?带你百家号快速转正赚钱!
  8. oracle rman 登录方式,oracle rman登陆及连接target数据库的步骤方法
  9. 开源不是天才的甜点,而是勤奋者的盛宴
  10. Ableton Live 11 Suite for Mac(音乐制作软件)