1.BM算法是什么?

BM算法是一种非常高效的字符串搜索算法。此算法仅对搜索目标字符串(关键字)进行预处理,而非被搜索的字符串。虽然Boyer-Moore算法的执行时间同样线性依赖于被搜索字符串的大小,但是通常仅为其它算法的一小部分:它不需要对被搜索的字符串中的字符进行逐一比较,而会跳过其中某些部分。通常搜索关键字越长,算法速度越快。

2.BM算法实现

BM算法实际上是在简单的后缀匹配算法的基础上,添加坏字符(__Bad_Char)和好后缀(__Good_Suffix)原则,实现加速移动字符串的速度。

char *BM(char *text, char *pattern) {if (text == NULL) return NULL;unsigned int text_len = strlen(text);unsigned int pat_len = strlen(pattern);unsigned int shift = pat_len - 1;  // 存储text的当前匹配下标unsigned int i = 0;                // 存储从shift向前匹配的长度while (shift < text_len) {for (i = 0; i < pat_len; i++)if (text[shift - i] != pattern[pat_len - 1 - i]) goto NEXT;return text += shift - (pat_len - 1);
NEXT:shift++;}return NULL;
}

2.坏字符原则(__Bad_Char)

#define ASIZE 256
typedef struct
{unsigned char*pattern;     // 存储适配串unsigned int patlen;        // 存储适配串长度unsigned int bad_shift[ASIZE];unsigned int good_shift[0]; //
} ts_bm;/**  初始化坏字符和好后缀*/
ts_bm *bm_init(const char *pattern, unsigned int len) {ts_bm *bm = NULL;unsigned int prefix_tbl_len = len * sizeof(int); // 好后缀列表长度size_t priv_size = sizeof(*bm) + len + prefix_tbl_len;bm = (ts_bm *)malloc(priv_size);memset(bm, 0, priv_size);bm->patlen = len;bm->pattern = (uint8_t *)bm->good_shift + prefix_tbl_len;memcpy(bm->pattern, pattern, len);compute_prefix_tbl(bm);return bm;
}void compute_prefix_tbl(ts_bm *bm) {// 主串遇到坏字符时,一次性移动的长度for (unsigned int i = 0; i < ASIZE; i++) bm->bad_shift[i] = bm->patlen;// 任意字符从右侧开始的下标(重复字符取最右侧的元素)for (unsigned int i = 0; i < bm->patlen - 1; i++)bm->bad_shift[bm->pattern[i]] = bm->patlen - 1 - i;
}

BM算法添加坏字符(__Bad_Char)规则

  ts_bm *bm = bm_init(pattern, pat_len);/**  text[shift-i]匹配失败, k =  bad_shift[a]*                 ↓ ←   i   →  ↓*  text:・・・・・a・・・・・[shift]*           ↓   ←   k   →    ↓*  patt:・・a・・・・・・・・[0]*  若需将a对齐,则需将text向左平移(k-i)位**/shift += bm->bad_shift[text[shift - i]] - i;

3.好后缀原则(__Good_Suffix)

void compute_prefix_tbl(ts_bm *bm) {// 主串遇到坏字符时,一次性移动的长度for (unsigned int i = 0; i < ASIZE; i++) bm->bad_shift[i] = bm->patlen;// 任意字符从右侧开始的下标(重复字符取最右侧的元素)for (unsigned int i = 0; i < bm->patlen - 1; i++)bm->bad_shift[bm->pattern[i]] = bm->patlen - 1 - i;#ifdef __Good_Suffixint len = bm->patlen;int *suffix = (int *)malloc(len);suffix[len - 1] = len;for (int i = len - 2; i >= 0; i--) {int shift = 0;// 满足P[i - shift, i] = P[len - 1 - shift, len - 1]即好后缀// 为避免过度滑动,从左侧开始寻找while (shift <= i && bm->pattern[i - shift] == bm->pattern[len - 1 - shift])shift++;// i为P[i] = P[len - 1]时的起始下标// suffix[i] = 好后缀/最长前缀长度suffix[i] = shift;}// good_shift[i]存储pattern[i]失配时向右滑动的长度for (int i = 0; i < len; i++) bm->good_shift[i] = len;// 从后向前,保证最长前缀唯一for (int i = len - 1; i >= 0; i--) {if (suffix[i] == i + 1)  // 当suffix是P前缀时{// P中存在一个最长前缀,等于好后缀的后缀// 此时,P[0,i]是P[j, len-1]的最长前缀(k < len - 1 - i)for (int j = 0; j < len - 1 - i; j++) {// 保证短前缀不覆盖长前缀if (bm->good_shift[j] == len) bm->good_shift[j] = len - 1 - i;}}}// 好后缀for (int i = 0; i < len - 1; i++) {// 对长度 k = suffix[i]的好后缀// 满足P[len - 1 - k, len - 1] = P[i - k, i]// 即最大滑动长度 = len - 1 - ibm->good_shift[len - 1 - suffix[i]] = len - 1 - i;}if (suffix != NULL) free(suffix);
#endif
}

BM算法添加坏字符(__Bad_Char)和好后缀(__Good_Suffix)规则

  shift += MAX(shift += MAX(bm->good_shift[pat_len - 1 - i],, bm->bad_shift[text[shift - i]] - i);

4.好后缀原则(__Kernel)

以下代码来自Linux源码 lib/ts_bm.c

int subpattern(uint8_t *pattern, int i, int j, int g) {// x始终指向P[len-1]int x = i + g - 1, y = j + g - 1, ret = 0;while (pattern[x--] ==pattern[y--])  // 将pattern[y]和pattern[n-1]从后向前比较{if (y < 0)  // y向前回溯j个元素回到pattern[0]{ret = 1;  // 指向最长前缀break;}if (--g == 0)  // y向前回溯j个元素{ret = pattern[i - 1] != pattern[j - 1];  // 指向好后缀break;}}return ret;
}void compute_prefix_tbl(ts_bm *bm) {// 主串遇到坏字符时,一次性移动的长度for (unsigned int i = 0; i < ASIZE; i++) bm->bad_shift[i] = bm->patlen;// 任意字符从右侧开始的下标(重复字符取最右侧的元素)for (unsigned int i = 0; i < bm->patlen - 1; i++)bm->bad_shift[bm->pattern[i]] = bm->patlen - 1 - i;#ifdef __Good_Suffix
#ifdef __Kernelunsigned int i, j, g;bm->good_shift[0] = 1;for (i = 1; i < bm->patlen; i++) bm->good_shift[i] = bm->patlen;// i从P[len - 1]开始,表示后缀// j从P[len - 2]开始,表示匹配好后缀或者最大前缀的串// g = [0, len-1], 表示i和j匹配成功的长度for (i = bm->patlen - 1, g = 1; i > 0; g++, i--) {for (j = i - 1; j >= 1 - g; j--) {// 将P[i-1,i+g-1]与P[max(j-1,0), j+g-1]进行匹配if (subpattern(bm->pattern, i, j, g)) {bm->good_shift[g] = bm->patlen - j - g;break;}}}
#endif
#endif
}

BM算法添加坏字符(__Bad_Char)和好后缀(__Good_Suffix)规则

  shift += MAX(shift += MAX(bm->good_shift[i],, bm->bad_shift[text[shift - i]] - i);

字符串匹配——BM算法相关推荐

  1. 分享一下字符串匹配BM算法学习心得。

    字符串匹配BM(Boyer-Moore)算法学习心得 BM算法 是 Boyer-Moore算法 的缩写,是一种基于后缀比较的模式串匹配算法.BM算法在最坏情况下可以做到线性的,平均情况下是亚线性的(即 ...

  2. 【数据结构与算法】字符串匹配 BM算法

    单模式串匹配 BF 算法和 RK 算法 BM 算法和 KMP 算法 多模式串匹配算法 Trie 树和 AC 自动机 BM算法 BM算法的核心思想是通过将模式串沿着主串大踏步的向后滑动,从而大大减少比较 ...

  3. cell数组变为字符串_字符串匹配 ---- BM 算法原理

    关于字符串匹配有很多算法, BF, BK, KMP, 但这些都不是这篇文章的重点. 文章的重点是另外一种更高效的算法 Boyer-Moore 算法, 一般文本编辑器中的查找功能都是基于它实现的. 前置 ...

  4. 字符串匹配-BM算法改进SUNDAY--Boyer-Moore-Horspool-Sunday Aglorithm

    原文:http://blog.csdn.net/zhoubl668/article/details/7321271 BM算法的改进的算法SUNDAY--Boyer-Moore-Horspool-Sun ...

  5. 【超详细图解】字符串匹配Boyer-Moore算法:文本编辑器中的查找功能是如何实现的?

    关于字符串匹配算法有很多,之前我有讲过一篇 KMP 匹配算法:图解字符串匹配 KMP 算法,不懂 kmp 的建议看下,写的还不错,这个算法虽然很牛逼,但在实际中用的并不是特别多.至于选择哪一种字符串匹 ...

  6. 字符串匹配——BMH算法

    字符串匹配--BMH算法 给定主串T和模式串P,返回P在T中首次出现的位置,如果P不存在于T中,返回-1. 这样的问题就是字符串匹配问题,这里给出BMH算法的思想. 设主串T的长度为n,模式串P的长度 ...

  7. 字符串匹配——Sunday算法

    字符串匹配--Sunday算法 基本思想及举例 Sunday算法由Daniel M.Sunday在1990年提出,它的思想跟BM算法很相似:1 只不过Sunday算法是从前往后匹配,在匹配失败时关注的 ...

  8. kmp算法详解php,php中字符串匹配KMP算法实现例子

    KMP算法是一个比较高级的算法了,加了改进了,下面我们来在php中实现KMP算法,希望例子对各位同学会带来帮助哦. kmp算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J. ...

  9. 字符串匹配——RabinKarp算法

    字符串匹配--RabinKarp算法 给定主串T和模式串P,返回P在T中首次出现的位置,如果P不存在于T中,返回-1. 这样的问题就是字符串匹配问题,这里给出RabinKarp算法的思想. 设主串T的 ...

最新文章

  1. linux 进程内存分布及 堆分配和栈分配的特点
  2. STC8G1K单片机软件执行时间物理测量
  3. 为什么你投出去的简历,都石沉大海了?
  4. java有装箱和拆箱吗_Java中装箱和拆箱,你真的都懂么?
  5. 查看队列深度_不为人知的网络编程(十一):从底层入手,深度分析TCP连接耗时的秘密...
  6. 使用消息中间件时,如何保证消息不丢失且仅仅被消费一次
  7. python办公自动化博客_最全总结 | 聊聊 Python 办公自动化之 Word(下)
  8. Firefox 终于对退格键“下手”了!
  9. java map 容器_java容器-map的常用实现及原理
  10. logistic人口模型python代码_人口模型(马尔萨斯vslogistic).ppt
  11. css样式给标签加上小手图标
  12. three.js学习笔记(十五)——着色器图案
  13. Buckhorn跳羚声卡驱动安装设置方法
  14. 奇迹之剑萌新晋升大神辅助攻略 奇迹之剑游戏脚本挂机工具介绍
  15. 主流跨境电商平台有哪些-扬帆牧哲
  16. idea设置静态壁纸步骤
  17. NC 主子表增加页签
  18. Filter过滤器介绍及使用
  19. Android基于腾讯云的视频聊天研究
  20. DDR3 HYPERLYNX SI仿真

热门文章

  1. 计算机程序设计语言教案,高中信息技术VB程序设计教案
  2. CSS进阶(一)背景与边框
  3. 【ESP 保姆级教程】疯狂传感器篇 —— 案例:Mega + ESP8266 + MQ2烟雾 + MQ3酒精 + MQ7一氧化碳+ OLED + 巴法云 + 微信小程序(环境监控)
  4. 欧科传动变频器说明书_欧科变频器说明书文档.doc
  5. 尚学堂Java第四章作业编码题+个人想法
  6. .NET程序的序列号控制
  7. 如何选择适合自己的进销存系统软件?
  8. 移动营业厅称部分SIM卡无法用于iPhone4S
  9. 《ODAY安全:软件漏洞分析技术》学习心得
  10. 局域网断网攻击(arp攻击)