zoukankan      html  css  js  c++  java
  • Shift And/Or字符串匹配算法

      Shift-And算法是一种基于前缀的单字符串匹配算法,采用位运算。其算法思想比KMP简单得多。

    在最简单的brute force算法中,在文本串的每个位置都要进行m(模式串长度)次比较,而SHIFT AND算法则是利用位运算提高这个过程。现在计算机的字长一般为3264位也开始流行了。一次比较的值为true or false,只需要一位即可存储,所以计算机可以在一次运算里完成位长次的比较。通过此思路可以把brute force的速度提高位长倍。

    Shift-And算法思想:设模式字符串为P,文本为text。它主要通过维护一个字符串集合DD中记录了P中所有与当前已读text的某个后缀相匹配的前缀),集合D中的每个字符串既是模式串p的前缀,同时也是已读入文本的后缀,每当从text中读入一个新的字符,算法立即利用位并行机制来更新集合D

     我们可以这么具体理解:

    •  P长度为m,则集合D可表示为D = dmd1 而用D[j]代表dj
    • D[j]=1,当且仅当p1pj t1ti 的某个后缀;
    • D[m]=1时,就认为P已经于text匹配;
    • 当读入下一个字符 ti+1, 需要计算新的集合 D′;
    • 当且仅当D[j]=1并且  ti+1等于pj+1D'[j+1]=1。这是因为D[j]=1时有 p1pj t1ti 的一个后缀,而当ti+1 等于 pj+1可推出p1pj +1 t1ti+1 的一个后缀。这个集合可通过位运算来更新。

    Shift-and算法首先建立一个数组B, 数组长度为字符集长度,B的第j位为1,表示则表示源串的i+1位与模式串的j位相同。设集合为D,则作位运算,((D<<1) + 1) & B即可得到新的D。

     1 int ShiftAndMatch(byte* pSrc, int nSrcSize, byte* pSubSrc, int nSubSrcSize)
     2 {
     3     long skip[256];
     4     memset(skip, 0, sizeof(skip));
     5     for (int i = 0; i < nSubSrcSize; i++)
     6     {
     7         skip[ pSubSrc[i] ] |= (0x01 << i);
     8     }
     9 
    10     long mask = 0x01<<(nSubSrcSize-1);
    11     long d = 0;
    12     int nPos = 0;
    13     while(nPos <= nSrcSize - nSubSrcSize)
    14     {
    15         d = ((d<<1)|0x01) & skip[pSrc[nPos]];
    16         if (d & mask)
    17         {
    18             break;
    19         }
    20         nPos++;
    21     }
    22     return nPos - (nSubSrcSize - 1); 
    23 }
    

       Shift-Or算法是Shift-And的一种技巧性的改进实现,其算法思想跟Shift-And类似,只是在通过对位取反以去掉公式中的掩码0m-11,这样减少了位运算的次数,从而实现加速。Shift-Or作的修改是,使用反码表示B中的位掩码和位向量,即用0表示一个数在集合里,1表示不在,所以将

    D = ((D<<1) | 1) & B[s[i]];

    修改为

    D=D<<1 | B[s[i]];

    这样就省了一次位运算,当然BD的初始化的时候,也要作相应的修改

     1 int ShiftOrMatch(byte* pSrc, int nSrcSize, byte* pSubSrc, int nSubSrcSize)
     2 {
     3     long skip[256];
     4     memset(skip, -1, sizeof(skip));
     5     for (int i = 0; i < nSubSrcSize; i++)
     6     {
     7         skip[pSubSrc[i]] ^= (0x01 << i);
     8     }
     9 
    10     long mask = ~(0x01 << (nSubSrcSize - 1 ));
    11     long d = -1;
    12     int nPos = 0;
    13     while(nPos <= nSrcSize - nSubSrcSize)
    14     {
    15         d = (d<<0x01) | skip[pSrc[nPos]];
    16         if (~(d|mask))
    17         {
    18             break;
    19         }
    20         nPos++;
    21     }
    22     return nPos - (nSubSrcSize - 1);
    23 
    24 }
  • 相关阅读:
    【RabbitMQ】3、win7下安装RabbitMQ
    【协议】4、http状态码
    【协议】3、HTTP 协议入门
    【协议】2、TCP/IP协议三次握手与四次握手流程解析
    【Dubbo&&Zookeeper】5、dubbo总结和学习资料汇总
    【Dubbo&&Zookeeper】6、 给dubbo接口添加白名单——dubbo Filter的使用
    【Spring】27、JPA 实现乐观锁@Version注解的使用
    HBase 常用Shell命令
    Java操作XML的JAXB工具
    JAXB--@XmlType注解标注xml生成顺序
  • 原文地址:https://www.cnblogs.com/dsky/p/2470882.html
Copyright © 2011-2022 走看看