shift-And Algorithm
最近在研究一些字符串匹配算法,也是由于工作上的需要,强力推荐一本书《柔性字符串匹配》,一本很好的书。网上可以随时搜索到。还是说正题吧。
Shift-And Algorithm 匹配源于KMP算法,但是比KMP算法简单的多。至于KMP如果不懂可以去参造数据结构这本书(严蔚敏版的)。为什么Shift-And Algorithm很简单呢?因为它用一个表,用位并行来模拟匹配。算法思想:
设掩码D=dm....d1来表示集合。现在介绍它的功能:D的第j位被置为1当且仅当p1...pj是t1...ti的后缀(如果dm是1的时候,表示匹配成功)。其匹配过程:
当读入ti+1时,需要计算新的掩码D、(这个相当于D,见伪代码)。D、的第j+1位是1的当且仅当D的第j位为1(p1...pj是t1...ti的后缀)并且ti+1与pj+1相等。利用位的并行可用公式得出:
D、=((D<<1)|0m-11)&B[ti+1](D的初始状态为0m)。
(D<<1)是将D、置为D的第i位。(相当于将p串第j位移一位,和B[ti+1]匹配。这样会发现如果D中的第j位为1了,且B[ti+1]的第j+1位也为1(指的是t中的ti+1字符在模式串p中和pj+1相等),这就匹配成功。反之不成功)。因为字符串为空串也是文本的后缀,所以要与0m-11位或操作(这个我自己也不太懂为什么,希望大神指点一下)。
举一个书上的例子模式串“announce”,构建B表。
a |
00000001 |
c |
01000000 |
e |
10000000 |
n |
00100110 |
o |
00001000 |
u |
00010000 |
* |
00000000 |
对于a在B表中,表项是表示它的位置,其他字符类似。
ecnuonna |
00000001 |
伪代码:
根据伪代码写的C++代码如下:
1 #include <iostream> 2 #include <string> 3 #include <cmath> 4 #include <vector> 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 int B[256]; 14 for (int i=0; i<PatternStrLen; i++) 15 { 16 B[vPatternStr[i]] |= 1<<(PatternStrLen-1-i); 17 } 18 19 //searching 20 21 int D = 0; 22 23 for (int Pos=0; Pos<SrcStrLen; Pos++) 24 { 25 D = ((D<<1)|1)&B[vSrcStr[Pos]]; 26 27 if (D&(1<<(PatternStrLen-1))) 28 { 29 voMatchPosVec.push_back(Pos-PatternStrLen+1); 30 } 31 } 32 } 33 34 int main(void) 35 { 36 string SrcStr = "aaaba"; 37 string PatternStr = "aa"; 38 39 vector<int> MatchPosVec; 40 41 matchString(SrcStr, PatternStr, MatchPosVec); 42 43 for(vector<int>::iterator Ix=MatchPosVec.begin(); Ix!=MatchPosVec.end(); Ix++) 44 { 45 cout<<*Ix<<endl; 46 } 47 48 system("pause"); 49 return 0; 50 }