文章目录

  • 1. BF(Brute Force)暴力匹配
    • BF代码
  • 2. RK(Rabin-Karp)算法
    • RK代码
  • 3. 思考题:(二维匹配)

1. BF(Brute Force)暴力匹配

BF算法的思想,在主串中,检查起始位置分别是0、1、2…n-m且长度为m的n-m+1个子串,看有没有跟模式串匹配的。最坏情况下每次都要对比m个字符,对比次数n-m+1次,复杂度O(m*n),适用小规模字符串匹配

BF代码

/*** @description: BF暴力匹配* @author: michael ming* @date: 2019/6/17 20:11* @modified by: */
#include <string>
#include <iostream>
using namespace std;
int str_BFM(string s, int pos, string t)
{if(s.length()== 0 || t.length() == 0)return 0;int i = pos - 1, j = 0;while(i < s.length() && j < t.length()){if(s[i] == t[j]){i++;j++;}else//字符串匹配失败,主串查找开始位置i+1,模式串从头开始{i = i - j + 1;j = 0;}}if(j >= t.length())return i-j+1;elsereturn 0;
}
int main()
{string a = "ababcabcacbab", b = "abcac";cout << a << "中第一次出现" << b << "的位置是:" << str_BFM(a,1,b) << endl;return 0;
}

2. RK(Rabin-Karp)算法

  • 上面BF算法,每次检查主串与子串是否匹配,需要逐次对比每个字符
  • 引入哈希,降低复杂度
  • RK算法思路:对n-m+1个子串分别求哈希值,然后与模式串的哈希值比较;如果某个子串的哈希值和模式串的哈希值匹配(需要考虑哈希冲突),比较数字是否相等是非常快的,所以效率比BF效率高
  • But, 计算子串的哈希值的时候,需要遍历每个字符;虽然比较效率高了,但是整体效率没有提高
  • 哈希算法设计技巧:K进制数表示子串(无冲突)(K为字符集内字符种数)
  • K进制法,相邻子串的哈希值计算公式有一定的关系:

  • 26(m-1)可以提前算好存放在数组中,指数就是数组的下标,计算26的x次方时,直接去数组下标x位置读取
  • 复杂度,计算子串哈希值需要扫描一遍主串O(n);比较n-m+1个子串哈希值O(n);所以整体复杂度O(n)(取决于哈希函数冲突概率)
  • 问题:如果模式串很长,子串的哈希值很大,超过计算机可表示的范围,怎么办?
    针对哈希值范围溢出,改造哈希函数:
    (1) 将a对应1,以此类推z对应26,将字符串每个字符对应数字相加作为哈希值,值的范围小了 (但是冲突概率有点大)
    (2) 将每个字符对应一个质数(冲突概率降低)
  • 存在冲突的情况下,如果模式串和子串哈希值相等,再比较一下它两真的相等否。
  • 哈希算法冲突概率要比较低,否则RK算法复杂度退化,效率下降

RK代码

/*** @description:RK匹配算法,计算子串哈希值,进行对比* @author: michael ming* @date: 2019/6/17 22:40* @modified by: */
#include <string>
#include <iostream>
using namespace std;
bool same(char* a, char* b, int m)
{for(int i = 0; i < m; ++i){if(a[i] != b[i])return false;}return true;
}
int str_RK(string s, string t)//s是主串,t是模式串
{int n = s.length(), m = t.length();int table[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};//质数表对应a-zint i, j, hash_val, value = 0;for(i = 0; i < m; ++i) //计算模式串的hash值value{value += table[t[i]-'a'];}for(i = 0; i < n-m+1; ++i)//最多n-m+1次比较{hash_val = 0;for(j = i; j < m+i; ++j)//计算第i个子串的哈希值{hash_val += table[s[j]-'a'];}if(hash_val == value && same(&s[i],&t[0],m)){//如果子串哈希值等于模式串的,且"真的"字符串匹配(避免冲突带来的假匹配)return i+1;//返回匹配位置,第i位开始,i从1开始}}return 0;
}
int main()
{string a = "ababcabcacbab", b = "abcac";cout << a << "中第一次出现" << b << "的位置是:" << str_RK(a,b) << endl;return 0;
}


如果不检查冲突,删除以下条件,匹配会出错

same(&s[i],&t[0],m)

3. 思考题:(二维匹配)


对RK算法进行改造得到答案
nr 主串行数
nc 主串列数
mr 模式串行数
mc 模式串列数
复杂度则为O((nr-mr+1)*(nc-mc+1)),简写为O(nr * nc)

/*** @description: 2维字符串匹配* @author: michael ming* @date: 2019/6/18 0:07* @modified by: */
#include <iostream>
#define nr 5    //主串行数
#define nc 5    //主串列数
#define mr 2    //模式串行数
#define mc 2    //模式串列数
int cal_hash_t(int* table, int r, int c, char ch[][mc])
{int i, j, value = 0;for (i = 0; i < r; ++i) //计算2d模式串的hash值value{for(j = 0; j < c; ++j)value += table[ch[i][j]-'a'];}return value;
}
int cal_hash_s_child(int* table, int i0, int j0, int r, int c, char ch[][nc])
{int i, j, hash_value = 0;for (i = i0; i < r; ++i) //计算2d子串的hash值value{for(j = j0; j < c; ++j)hash_value += table[ch[i][j]-'a'];}return hash_value;
}
bool same(char s[][nc], char t[][mc], int i0, int j0)
{int x = i0, y = j0, i, j;for(i = 0; i < mr; ++i,++x){for(j = 0, y = j0; j < mc; ++j,++y)//记得写y=j0,换行后y复位{if(s[x][y] != t[i][j])return false;}}return true;
}
bool str_RK_2d(char s[][nc], char t[][mc])//s是主串,t是模式串
{int table[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};//质数表对应a-zint i, j, hash_val, value;value = cal_hash_t(table,mr,mc,t);//计算2d模式串哈希值for(i = 0; i < nr-mr+1; ++i)//行最多nr-mr+1次比较{for(j = 0; j < nc-mc+1; ++j)//列最多nc-mc+1次比较{hash_val = cal_hash_s_child(table,i,j,mr+i,mc+j,s);//计算2d子串哈希值if(hash_val == value && same(s,t,i,j)){//如果2d子串哈希值等于模式串的,且"真的"字符串匹配(避免冲突带来的假匹配)std::cout << "找到模式矩阵,其左上角在 " << i+1 << " 行," << j+1 << " 列." << std::endl;return true;}}}return false;
}int main()
{char s[  ][nc] = {{ 'a', 'b', 'a', 'b', 'a' },{ 'a', 'b', 'a', 'b', 'a' },{ 'a', 'b', 'b', 'a', 'a' },{ 'a', 'b', 'a', 'a', 'b' },{ 'b', 'b', 'a', 'b', 'a' }};char t[  ][mc] = {{ 'a', 'b' },{ 'b', 'a' }};str_RK_2d(s,t);char a[  ][nc] = {{ 'd', 'a', 'b', 'c' },{ 'e', 'f', 'a', 'd' },{ 'c', 'c', 'a', 'f' },{ 'd', 'e', 'f', 'c' },{ 'b', 'b', 'a', 'b' }};char b[  ][mc] = {{ 'c', 'a' },{ 'e', 'f' }};str_RK_2d(a,b);return 0;
}



字符串匹配算法(BF RK)相关推荐

  1. Go 语言实现字符串匹配算法 -- BF(Brute Force) 和 RK(Rabin Karp)

    今天介绍两种基础的字符串匹配算法,当然核心还是熟悉一下Go的语法,巩固一下基础知识 BF(Brute Force) RK(Rabin Karp) 源字符串:src, 目标字符串:dest: 确认des ...

  2. python实现字符串匹配算法BF,BF改,KMP

    包含:BF,BF改进版本,KMP BF:暴力搜索 BF改:当判断匹配失败的字符串是不是与首字母相同 若不同,继续BF算法: 若相同,直接将首字母移到当前位置 KMP:通过前缀与后缀发现待匹配字符串本身 ...

  3. 一看就懂的字符串匹配算法 之 RK算法

    RK算法是对BF算法的进一步优化,很巧妙的使用了哈希算法,让匹配的效率有了很大的提升. BF算法  这是关于BF暴力匹配算法的博客,大家可以先去看看. RK算法的原理和实现 之前在讨论BF算法的时候, ...

  4. 字符串匹配算法---BF及KMP

    字符串匹配的一般算法(BF)     以 ABSABABCEF 与 ABCE 为例,求串2与串1匹配的第一个位置的下标(这里即输出 5),一般的,我们可以从串1的起始位置开始与串2比较,若相同则两串都 ...

  5. 字符串匹配算法BF,BM,KMP

    字符串匹配bf算法:(暴力穷举算法) 在一个字符串中寻找另一字符串,最容易想到的,也是最简单的办法是:取主串和模式串/搜索串中的每一位依次比较,如果匹配则同时后移一位继续比较,直至匹配到模式串的最后一 ...

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

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

  7. 数据结构与算法分析(十六)--- 如何设计更高效的字符串匹配算法?(BF + RK + KMP + BMH)

    文章目录 一.Brute Force 匹配算法 二.Rabin–Karp 匹配算法 三.Knuth–Morris–Pratt 匹配算法 四.Boyer-Moore-Horspool 匹配算法 五.字符 ...

  8. BF,KMP,BM三种字符串匹配算法性能比较

    三种最基本的字符串匹配算法是BF,KMP以及BM,BF算法是最简单直接的匹配算法,就是逐个比较,一旦匹配不上,就往后移动一位,继续比较,所以比较次数很都. 关于KMP和BM的详细介绍可以参考下面的两个 ...

  9. 字符串处理 —— 单模式匹配 —— 朴素的字符串匹配算法(BF 算法)

    [算法流程] 朴素的字符串匹配算法即暴力匹配算法(BF,Brute Force),其本质是暴力枚举,主要特点有: 没有预处理阶段: 滑动窗口总是后移 1 位: 对模式中的字符的比较顺序不限定,可以从前 ...

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

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

最新文章

  1. 【Netty】从 BIO、NIO 聊到 Netty
  2. 适用于Android的OpenSL ES指南-OpenSL ES的Android扩展
  3. 机械制图中外螺纹的画法_机械制图中图纸上的各种符号代表什么意思?
  4. 简单c语言图形界面,求个用最简单的的代码来实现图形界面…
  5. SQL SERVER 2008如何卸载干净
  6. Python入门学习---第四天
  7. 计算机用并行传输还是串行,网线RJ45是并行传输还是串行
  8. MATLAB中disp的用法
  9. Flutter AspectRatio 宽高比设定
  10. 不同Costa环鉴相器鉴别特性
  11. 四、快速搭建一套现代化的个人独立博客系统,给爱写博客的你(part2 正文)
  12. 服务式办公室,价格影响选择
  13. `Supimo` 历史,人文,哲学,人物,摘录
  14. Adobe Acrobat Reader DC 2019 (19.8)
  15. 借助向 Dev Channel 內部人員提供的最新預覽版本,Microsoft 已將舊版本地管理員密碼解決方案(也稱為 LAPS)直接集成到 Windows 11 中
  16. 亚马逊AWS Kinesis Video Streams with IOT mqtt的demo示例
  17. 菜鸟教程PHP学习笔记(不定期更新)
  18. 0Ω电阻到底能过多大电流?
  19. TCP 连接的“ 三次握手 ”与“ 四次挥手 ”
  20. 交流充电桩电路图_一种新能源汽车交流充电桩控制电路的制作方法

热门文章

  1. S5PV210的启动过程:三星推荐的启动方式和uboot的实现方式不同
  2. frp对http协议应用
  3. vbox虚拟机配置Redhat6.4本地yum源
  4. 获取Spring容器管理的Bean工具类
  5. VBA学习_5:流程控制
  6. [转]版本二写代码的小女孩
  7. EasyUI_datagrid
  8. 初识设计模式(装饰者模式)
  9. 最长公共子序列及其引申问题
  10. Spring中RedirectAttributes对象重定向传参