给定两个字符串S和T,在主串S中查找子串T的过程称为串匹配(string
matching,也称模式匹配),T称为模式。这里将介绍处理串匹配问题的两种算法,BF算法和KMP算法。

BF算法

(暴力匹配算法)

BF算法简介

F(Brute Force)算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符;若不相等,则比较S的第二个字符和T的第一个字符,依次比较下去,直到得出最后的匹配结果。

BF算法原理

首先,给定 “主串” 和 “模式串” 如下:

BF算法使用简单粗暴的方式,对主串和模式串进行逐个字符的比较:




检测到字符不匹配,模式串向后挪动一位,和主串的第二个等长子串比较。

检测到字符不匹配,模式串继续向后挪动一位,和主串的第三个等长子串比较

···········不断循环上面步骤,直到匹配成功或者匹配失败(即到主串末尾结束)。

算法

int BF(char* S, char* T)
{int sLen = strlen(S);        //文本串长度int tLen = strlen(T);        //模式串长度int i = 0;int j = 0;while (i < sLen && j < tLen){if (S[i] == T[j]){//①如果当前字符匹配成功(即S[i] == T[j]),则i++,j++i++;j++;}else{//②如果失配(即S[i]! = T[j]),令i = i - (j - 1),j = 0i = i - j + 1;j = 0;}}//匹配成功,返回模式串t在文本串s中的位置,否则返回-1if (j == tLen)return i - j;elsereturn -1;
}

测试

#include<stdio.h>
#include <stdlib.h>
#include <string.h>int BF(char* S, char* T)
{int sLen = strlen(S);        //文本串长度int tLen = strlen(T);        //模式串长度int i = 0;int j = 0;while (i < sLen && j < tLen){if (S[i] == T[j]){//①如果当前字符匹配成功(即S[i] == T[j]),则i++,j++i++;j++;}else{//②如果失配(即S[i]! = T[j]),令i = i - (j - 1),j = 0i = i - j + 1;j = 0;}}//匹配成功,返回模式串t在文本串s中的位置,否则返回-1if (j == tLen)return i - j;elsereturn -1;
}int main()
{char S[] = "ABC ABCDAB ABCDABCDABDW";char T[] = "ABCDABD";int num;char *ch = T;num = BF(S,T);if (num >= 0){printf("matched @: %s\n", ch);}else{printf("matched fail!\n");}return 0;
}

执行结果:

matched @: ABCDABD

总结:BF算法比较直接,是一种蛮力法,该算法最坏情况下要进行m*(n-m+1)次比较,时间复杂度为O(m*n),下面来看一个效率非常高的字符串匹配算法,即KMP算法。

KMP算法

KMP算法简介

之所以叫做KMP,是因为这个算法是由Knuth、Morris、Pratt三个提出来的,取了这三个人的名字的头一个字母。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

简单理解就是:KMP算法是拿来处理字符串匹配的。换句话说,给你两个字符串,你需要回答,B串是否是A串的子串(A串是否包含B串)。

KMP算法原理

(参考自:看,未来的博客)
首先,给定 “主串” 和 “模式串” 如下:

第一轮,模式串和主串的第一个等长子串比较,发现前5个字符都是匹配的,第6个字符不匹配,是一个“坏字符”:

这时候,我们可以有效利用已匹配的前缀 “GTGTG” 。通过观察我们可以发现,在前缀“GTGTG”当中,后三个字符“GTG”和前三位字符“GTG”是相同的:

在下一轮的比较时,只有把这两个相同的片段对齐,才有可能出现匹配。这两个字符串片段,分别叫做最长可匹配后缀子串和最长可匹配前缀子串。

第二轮,我们直接把模式串向后移动两位,让两个“GTG”对齐,继续从刚才主串的坏字符A开始进行比较:

显然,主串的字符A仍然是坏字符,这时候的匹配前缀缩短成了GTG:

按照第一轮的思路,我们来重新确定最长可匹配后缀子串和最长可匹配前缀子串:

第三轮,我们再次把模式串向后移动两位,让两个“G”对齐,继续从刚才主串的坏字符A开始进行比较:

·········接下来还是重复步骤,就不往写了。

next数组

什么是next数组?next数组用来干什么?
next数组是决定kmp算法快速移动的核心。

next数组的生成示例

说白了就是把子串拆分,然后看尾部有多少个字符重复,没有写-1,有一个就写0,有两个写1,依次类推(你也可以写0,1,2,具体想写啥看个人吧,我这里只是全部减1了,当然在代码里也要记得修改)。

有了next数组,我们就可以通过已匹配前缀的下一个位置(坏字符位置),快速寻找到最长可匹配前缀的下一个位置,然后把这两个位置对齐。

算法

void compute_prefix(const char *pattern, int next[])
{int i;     //前缀int j = -1;   //前缀尾巴const int m = strlen(pattern);next[0] = j;for (i = 1; i < m; i++){while (j > -1 && pattern[j + 1] != pattern[i])  //前后缀不相等{j = next[j];}if (pattern[i] == pattern[j + 1])  //前后缀相等{j++;}next[i] = j;}
}int kmp(const char *text, const char *pattern)
{int i;int j = -1;const int n = strlen(text);const int m = strlen(pattern);if (n == 0 && m == 0) return 0;if (m == 0) return 0;int *next = (int*)malloc(sizeof(int) * m);compute_prefix(pattern, next);for (i = 0; i < n; i++){while (j > -1 && pattern[j + 1] != text[i]) j = next[j];if (text[i] == pattern[j + 1]) j++;if (j == m - 1){free(next);return i-j;}}free(next);return -1;
}

测试

#include<stdio.h>
#include <stdlib.h>
#include <string.h>void compute_prefix(const char *pattern, int next[])
{int i;     //前缀int j = -1;   //前缀尾巴const int m = strlen(pattern);next[0] = j;for (i = 1; i < m; i++){while (j > -1 && pattern[j + 1] != pattern[i])  //前后缀不相等{j = next[j];}if (pattern[i] == pattern[j + 1])  //前后缀相等{j++;}next[i] = j;}
}
int kmp(const char *text, const char *pattern)
{int i;int j = -1;const int n = strlen(text);const int m = strlen(pattern);if (n == 0 && m == 0) return 0;if (m == 0) return 0;int *next = (int*)malloc(sizeof(int) * m);compute_prefix(pattern, next);for (i = 0; i < n; i++){while (j > -1 && pattern[j + 1] != text[i]) j = next[j];if (text[i] == pattern[j + 1]) j++;if (j == m - 1){free(next);return i-j;}}free(next);return -1;
}
int main()
{char text[] = "ABC ABCDAB ABCDABCDABDE";char pattern[] = "ABCDABD";char *ch = pattern;int i = kmp(text, pattern);if (i >= 0){printf("matched @: %s\n", ch);}else{printf("matched fail!\n");}return 0;
}

执行结果:

matched @: ABCDABD

BF算法和KMP算法相关推荐

  1. Algorithm:C++语言实现之字符串相关算法(字符串的循环左移、字符串的全排列、带有同个字符的全排列、串匹配问题的BF算法和KMP算法)

    Algorithm:C++语言实现之字符串相关算法(字符串的循环左移.字符串的全排列.带有同个字符的全排列.串匹配问题的BF算法和KMP算法) 目录 一.字符串的算法 1.字符串的循环左移 2.字符串 ...

  2. 若S作主串,P作模式串,试分别写出利用BF算法和KMP算法的匹配过程。

    目   录 题目: 百度文库-答案: (1) (2) MOOC标准答案: (1) (2) mooc答案-截图: 数据结构(C语言版)-严蔚敏2007 题目: 设字符串S='aabaabaabaac', ...

  3. 【算法篇-字符串匹配算法】BF算法和KMP算法

    目录 前言 1. BF算法 1.1 画图分析 1.3 BF 算法的时间复杂度 2. KMP 算法 2.1 KMP 算法和 BF 算法 的区别 2.1.1 为什么主串不回退? 2. 2 next 数组 ...

  4. 数据结构之字符串匹配算法(BF算法和KMP算法)

    字符串匹配算法: 就是给定两个串,主串(s)和子串(sub), 查找子串是否在主串里面,如果找到便返回子串在主串中第一个元素的位置下标,否贼返回-1,. 在这里我 们讨论的时候主要用字符串来举例实现. ...

  5. 模式串匹配的BF算法和KMP算法

    KMP是三位大牛:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的.为了解决模式匹配问题,也即寻找模式串(子串)在主串中第一次出现的位置,若模式串在主串中不存在则返回-1. 简单 ...

  6. 字符串匹配—BF算法和KMP算法

    BF算法 本章重点是是KMP算法,但是由于其较难理解,先从更简单朴素的BF算法开始. 其思路非常简单 也就是,对这样两个字符串(称短的为模式串,长的为主串): 让主串和模式串的每个字符逐个匹配,如果从 ...

  7. 串的BF算法和KMP算法个人总结

    子串(模式串)的定位操作通常称作串的模式匹配 其中包含最初始的BF算法(Brute-Force)即简单匹配算法或者称作朴素的模式匹配算法,利用穷举法的思路 另一种就是改进后的KMP算法,还有对KMP算 ...

  8. BF算法和KMP算法实现

    https://blog.csdn.net/xxibgdrgn_liqian_a_/article/details/80690593

  9. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

最新文章

  1. 那个14岁上大学、17岁读博、24岁成教授的天才神童,如今怎样了?
  2. 今日工作总结 2022-02-08
  3. redis相关知识记录整理
  4. 检查文件上传完成_“我的数据上传NCBI又报错了...” “攻略拿去!”
  5. 自定义控件——轮播广告条
  6. CodeForces 901D Weighting a Tree(结论)
  7. ie 调用java的时候报错,调用javabean的非常郁闷的异常。
  8. LockSupport实现线程通信
  9. js charCodeAt() charAt()
  10. npoi操作word书签_word进阶小教程,小研全部都给你!
  11. 2016.10.26
  12. 后天就是七夕节,你准备好了吗?送上几个七夕代码,展示你技能的时候到了!
  13. windows密钥查看器ProduKey1.82汉化
  14. 【笔记】斜线(slash)和反斜线“\”(backslash)的区别总结
  15. org.eclipse.core.runtime.IPath报错
  16. n阶方阵求逆c语言报告,n阶方阵求逆
  17. 《致我们终将逝去的青春》
  18. 【uni-app】基于uni-app的Android离线打包,wifi物联网
  19. ace布置小作业: 制作一个简单的电话号码归属地查询软件:JSON解析和Volly发送get请求...
  20. 类与类之间的关系之——继承

热门文章

  1. 递归神经网络预测股票好文章
  2. c语言数据储存系统,编的学生成绩管理系统 从文件中读取保存数据总会多读入一组乱码数据...
  3. Leetcode 面试题 01.01. 判定字符是否唯一 (每日一题 20211012)
  4. 只有2GB内存在20亿个整数中找到出现次数最多的数
  5. 强化学习笔记2:序列决策(Sequential Decision Making)过程
  6. 3万字长文记录Docker 最全学习笔记,手把手带你入个门
  7. 深度学习核心技术精讲100篇(四十)-微信“看一看“内容理解与推荐,背后深层次的技术知多少?
  8. MATLAB对函数做评估
  9. 数据挖掘学习笔记--决策树C4.5
  10. Matplotlib实例教程(七)密度图