BNDM 算法

  最近在研究一些字符串匹配算法,也是由于工作上的需要,强力推荐一本书《柔性字符串匹配》,一本很好的书。网上可以随时搜索到。还是说正题吧。

BNDM算法的思想来源于BDM算法思想,类似于shitf-and和kmp之间的区别吧(也不知道是不是准确,有错望大家多指点)。前者都是用位运算模拟后者。好了,那就先介绍一下BDM算法吧!

  BDM是基于子串搜索方法,其难点在于怎么搜索子串,书中引入了后缀自动机。对于后缀自动机,我其实没有足够的把握理解它,姑且就当它为一个工具就是了,提供一些状态跳转罢了。现在简单介绍一下它的功能和怎么识别子串。对于这个自动机的实现书上说用一种叫compact suffix tree结构,这些由于时间关系同时这也不是我的重点,故没有去理解。

书中提到后缀自动机的三个性质如下:

  第一:字符串u是p(模式串)的一个子串当且仅当p的后缀自动机中存在一条初始状态开始的标号为u的路径。(理解这句话)。

  第二:自动机可以识别模式串的所有后缀,从初始状态到某个终止状态的路径上的字符组成的字符串是模式串p的一个后缀。

  第三:模式串p=p1p2...pm对应的后缀自动机【用SA(p1p2...pm)表示】可以通过在线的方法在o(0)时间内构建完成,即依次将pj添加到SA(p1p2...pj-1)上,构造SA(p1p2...pj)。

搜索算法:先构建p的反串即pmpm-1...p1的后缀自动机,因为我们是从后向前匹配,搜索模式串的子串。在搜索过程中如果到达了一个终止状态,并且对应的串不是整串p,会得到pmpm-1...p1后缀,即p1p2...pm的前缀,我们将它在窗口中的位置保存在last中,根据性质2,是当前(可不可以更新?不可以!)最长前缀(这是重点)。它是从位置last开始,到窗口末端结束。这种反向搜索有两种结束方式:

  第一种:识别子串失败,读入的字符σ,在这后缀自动机的当前状态没有σ的转移。这个窗口向右移动,使它起始位置和last对齐。这样移动窗口不会遗漏任何可能的匹配,(因为我们识别的已经是最长的前缀,不然σ定匹配,因为由于性质2得到的)。

  第二种:抵达窗口的起始位置,模式串成功匹配,报告成功,并且像第一种方式移动窗口,使它起始位置和last对齐,因为last最长前缀。

见书本上的图:

理解了BMD算法,现在理解BNDM算法,

  BNDM算法和Shift-And算法类似,维护一个集合,这个集合用一个向量D来表示。如果pj...pj+u-1等于u,那么D的第m-j+1位是1,表示p的位置j是一个活动状态。书上的表示这种关系。

表的更新时

当读入新字符σ时,D要更新到D´,D´的一个活动状态j对应于σu在模式串的一个起始位置,也就是说

u出现在模式串的位置j+1,即D的j+1位是活动的,σ在模式串j处出现,从而可以得到表D更新

D´=(D<<1)&B[σ]。

还要注意初始化,因为为了表示空串和模式串的任何位置都匹配,这样D=1m,不然会丢失第一个子串。也可将D大小初始化 为m+1。也可以拆分公式:第一部分D´=D&B[σ],然后在移位D´=D´<<1.其中表B和上面的shift-and类似,可以参考我文章中的shift-and。来理解表B的构建。

见书上伪代码:

自己根据伪代码写的源代码:

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 #include <cmath>
 5
 6 using namespace std;
 7
 8 void matchString(const string& vSrcStr, const string& vPatternStr, vector<int>& voMatchPosVec)
 9 {
10     //preprocessing
11     int SrcStrLen = vSrcStr.size();
12     int PatternStrLen = vPatternStr.size();
13     unsigned int BitMask[256] = {0};
14
15     for (int i=0; i<PatternStrLen; i++)
16     {
17         BitMask[vPatternStr[i]] |= 1<<(PatternStrLen-i-1);
18     }
19
20     //searching
21     int Pos = 0;
22     while(Pos <= SrcStrLen-PatternStrLen)
23     {
24         int JPos = PatternStrLen;
25         int LastPos = PatternStrLen;
26         unsigned int DMask = (unsigned int) pow(2.0,PatternStrLen)-1;
27         unsigned int MonitorPos = (unsigned int) pow(2.0,PatternStrLen)-1;        //设置防止左移时,高位对判断的影响
28         while (DMask&MonitorPos)
29         {
30             DMask = DMask&BitMask[vSrcStr[Pos+JPos-1]];
31             JPos = JPos-1;
32             if (DMask&(1<<(PatternStrLen-1)))
33             {
34                 if(JPos>0)
35                 {
36                     LastPos = JPos;
37                 }
38                 else
39                 {
40                     voMatchPosVec.push_back(Pos);
41                 }
42             }
43             DMask = DMask<<1;
44         }
45         Pos = Pos+LastPos;
46     }
47 }
48
49 int main()
50 {
51     string SrcStr = "aaaaabaaa";
52     string PatternStr = "a";
53
54     vector<int> MatchPosVec;
55
56     matchString(SrcStr, PatternStr, MatchPosVec);
57
58     for(vector<int>::iterator Ix=MatchPosVec.begin(); Ix!=MatchPosVec.end(); Ix++)
59     {
60         cout<<*Ix<<endl;
61     }
62
63     system("pause");
64     return 0;
65 }

如果有错误希望大家指出。

时间: 2024-08-25 10:55:17

BNDM 算法的相关文章

典型字符串匹配算法实现 - 单字符串匹配算法

博客源址:http://www.jimye.com/dian-xing-zi-fu-chuang-pi-pei-suan-fa-shi-xian/ 提示:要继续向下看 相信大家对快捷键ctrl+F是做什么用的都应该很熟悉了,无论是文本编辑.网页浏览等程序上它都意味着字符串搜索,我们提供一个关键字,它将找到当前页面上的所有该关键字所在的位置.关键字称为模式串,在文本T中寻找模式串P出现的所有出现的位置,解决这种问题的算法叫做字符串匹配算法.字符串匹配算法可以说是计算机科学中最古老.研究最广泛的问题

经典排序算法 - 冒泡排序Bubble sort

 原文出自于 http://www.cnblogs.com/kkun/archive/2011/11/23/bubble_sort.html 经典排序算法 - 冒泡排序Bubble sort 原理是临近的数字两两进行比较,按照从小到大或者从大到小的顺序进行交换, 这样一趟过去后,最大或最小的数字被交换到了最后一位, 然后再从头开始进行两两比较交换,直到倒数第二位时结束,其余类似看例子 例子为从小到大排序, 原始待排序数组| 6 | 2 | 4 | 1 | 5 | 9 | 第一趟排序(外循环) 第

转载:DenseNet算法详解

原文连接:http://blog.csdn.net/u014380165/article/details/75142664 参考连接:http://blog.csdn.net/u012938704/article/details/53468483 本文这里仅当学习笔记使用,具体细节建议前往原文细度. 论文:Densely Connected Convolutional Networks 论文链接:https://arxiv.org/pdf/1608.06993.pdf 代码的github链接:h

基于位置信息的聚类算法介绍及模型选择

百度百科 聚类:将物理或抽象对象的集合分成由类似的对象组成的多个类的过程被称为聚类.由聚类所生成的簇是一组数据对象的集合,这些对象与同一个簇中的对象彼此相似,与其他簇中的对象相异."物以类聚,人以群分",在自然科学和社会科学中,存在着大量的分类问题.聚类分析又称群分析,它是研究(样品或指标)分类问题的一种统计分析方法.聚类分析起源于分类学,但是聚类不等于分类.聚类与分类的不同在于,聚类所要求划分的类是未知的. 分类和聚类算法一直以来都是数据挖掘,机器学习领域的热门课题,因此产生了众多的

密码算法详解——AES

0 AES简介 美国国家标准技术研究所在2001年发布了高级加密标准(AES).AES是一个对称分组密码算法,旨在取代DES成为广泛使用的标准. 根据使用的密码长度,AES最常见的有3种方案,用以适应不同的场景要求,分别是AES-128.AES-192和AES-256.本文主要对AES-128进行介绍,另外两种的思路基本一样,只是轮数会适当增加. 1 算法流程 AES加解密的流程图如下: AES加密过程涉及到4种操作:字节替代(SubBytes).行移位(ShiftRows).列混淆(MixCo

矩阵乘法的Strassen算法详解

题目描述 请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法. 思路分析 根据wikipedia上的介绍:两个矩阵的乘法仅当第一个矩阵B的列数和另一个矩阵A的行数相等时才能定义.如A是m×n矩阵和B是n×p矩阵,它们的乘积AB是一个m×p矩阵,它的一个元素其中 1 ≤ i ≤ m, 1 ≤ j ≤ p. 值得一提的是,矩阵乘法满足结合律和分配率,但并不满足交换律,如下图所示的这个例子,两个矩阵交换相乘后,结果变了: 下面咱们来具体解决这个矩阵相乘的问题. 解法一.暴力解法 其实,通过前面的分析

关于SVM数学细节逻辑的个人理解(三) :SMO算法理解

第三部分:SMO算法的个人理解 接下来的这部分我觉得是最难理解的?而且计算也是最难得,就是SMO算法. SMO算法就是帮助我们求解: s.t.   这个优化问题的. 虽然这个优化问题只剩下了α这一个变量,但是别忘了α是一个向量,有m个αi等着我们去优化,所以还是很麻烦,所以大神提出了SMO算法来解决这个优化问题. 关于SMO最好的资料还是论文<Sequential Minimal Optimization A Fast Algorithm for Training Support Vector

基于Spark MLlib平台的协同过滤算法---电影推荐系统

基于Spark MLlib平台的协同过滤算法---电影推荐系统 又好一阵子没有写文章了,阿弥陀佛...最近项目中要做理财推荐,所以,回过头来回顾一下协同过滤算法在推荐系统中的应用. 说到推荐系统,大家可能立马会想到协同过滤算法.本文基于Spark MLlib平台实现一个向用户推荐电影的简单应用.其中,主要包括三部分内容: 协同过滤算法概述 基于模型的协同过滤应用---电影推荐 实时推荐架构分析     一.协同过滤算法概述 本人对算法的研究,目前还不是很深入,这里简单的介绍下其工作原理. 通常,

算法 希尔排序

希尔排序 Shell Sort 介绍: 希尔排序(Shell Sort)也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个"增量"的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序.因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率比直接插入排序有较大提高. 执行流程: 首先