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 }

 

 

posted on 2012-04-26 09:15  梦想Sky  阅读(3281)  评论(0编辑  收藏  举报

导航