Horspool 算法

  利用一些时间把近期所看所写的总结起来,对加深自己理解很有帮助,同时也可以分享交流等。

  前几天研究了一下Horspool算法,感谢《柔性字符串匹配》这本书。说了这么多废话,还是回到主题。

  要想深刻了解Horspool算法还需要了解BM算法,因为前者是后者的改进。BM算法是基于后缀的匹配算法。它是用移动窗口的方式来匹配的。对于BM算法,在理论上效果比Horspool好,但是实际不是如此。但是还是简单介绍一下,有助于对Horspool的理解。

  BM算法思想:

    对于匹配中的需要三种情况来移动窗口,需要三个函数表:

    第一种:从后向前,当后缀u在模式串p中的另一位置出现。设在最右出现的位置为j(除去模式串末尾的出现)即(u=pj-u+1...pj)其中j表示尾串,这是可以将窗口(模式串的长度的大小)安全移动m-j字符(将模式串中和后缀相匹配的子串与目标串u匹配)。见《柔性字符串匹配》这本书的图,对于每个后缀都要计算它到下一个出现之间的距离(就是上面所说的m-j)设用d1(u)表示。如果模式串的所有后缀u不在p中出现,d1(u)为模式串的长度。

   

    第二种情况:后缀u不出现在模式串中的任何位置时,这不是表示可以安全移动整个窗口位置。可能发生u自己的后缀v也有可能是模式串的一个前缀。必须处理这个情况。为了处理这个情况,需要计算模式串所有后缀的第二函数d2。同样对于模式串中的每个后缀u,d2(u)表示模式串的前缀,也表示u的后缀的最长字符串v的长度(相当u的最长后缀v(同时v也是模式串的前缀)的长度)。这种情况如下图,借鉴了书中的图:

  

    第三种情况:因为搜索是从后向前匹配,,在文本字符 σ处不能匹配成功。则用d1移动窗口时,如果对应的模式串字符不是σ,那么就没必要进行验证匹配了,可以借助下图来理解。这样引用另一个d3函数表。用来保证下次验证时文本字符一定与模式串中一个字符σ匹配。故对于字母表(整个字母表系统)中每一个字符σ,d3(σ)表示σ在模式串中的最右出现位置到模式串末尾的距离。如果σ不出现在p中,则d3(σ)被置为m。

 

 

BM算法中的窗口移动距离还需要两次比较:

第一次:取d3(σ)和d1(u)中较大的。

第二次:取第一次的结果和m-d2(u)中较小的。

这就是移动窗口的大小。理解上面的BM思想其实还是挺麻烦的。但是有助于理解以后的字符串匹配。对于Horspool算法,其主要是摒弃了这么复杂的过程,只用d3,并且对于d3有了一些改进。使其能产生最大的跳跃。思想如下:

 对于每一个搜索窗口,该算法将窗口内的文本的最后的一个字符(β)和模式串的最后一个字符比较,相等就继续搜索直到不相等(σ)的出现。然后根据β在模式串下一个出现的位置将窗口向右移动(就是d3(β))前面已经叙说了这些。用书上的图来加深理解:

 

理解思想后,给出书上的伪代码:

 

最后自己根据伪代码所写的c++源代码:

  1 #include<iostream>
  2 #include<map>
  3 
  4 bool matchString(const char* vSrcStr, int vSrcStrLen, const char* vSearchStr, int vSearchStrLen, int *voPos);
  5 
  6 
  7 int main(void)
  8 {
  9     char *SrcStr = NULL;
 10     char *SearchStr = NULL;
 11     
 12     int SrcStrLen;
 13     int SearchStrLen;
 14     int *Pos;
 15 
 16     std::cout<<"input the source string length:";
 17     std::cin>>SrcStrLen;
 18     if(std::cin.fail())
 19     {
 20         std::cout<<"输入非法数据!";
 21         exit(0);
 22     }
 23     SrcStr = new char[SrcStrLen+1];
 24     std::cout<<"input the source string:"<<std::endl;
 25     for(int count=0; count<SrcStrLen; count++)
 26     {
 27         std::cin>>SrcStr[count];
 28         if(std::cin.fail())
 29         {
 30             std::cout<<"输入非法数据!";
 31             exit(0);
 32         }
 33     }
 34     
 35     std::cout<<"input the target string length:";
 36     std::cin>>SearchStrLen;
 37     if(std::cin.fail())
 38     {
 39         std::cout<<"输入非法数据!";
 40         exit(0);
 41     }
 42 
 43     SearchStr = new char[SearchStrLen+1];
 44     std::cout<<"input the target string:"<<std::endl;
 45     for(int count=0; count<SearchStrLen; count++)
 46     {
 47         std::cin>>SearchStr[count];
 48         if(std::cin.fail())
 49         {
 50             std::cout<<"输入非法数据!";
 51             exit(0);
 52         }
 53     }
 54 
 55     Pos = new int[SrcStrLen+1];
 56     matchString(SrcStr, SrcStrLen, SearchStr, SearchStrLen, Pos);
 57 
 58     int i = 0;
 59     while(i < (SrcStrLen+1) && Pos[i] != -1)
 60     {
 61         std::cout<<"the pos of the string are:  "<<Pos[i]<<"    "<<std::endl;
 62         i++;
 63     }
 64 
 65     delete[] Pos;
 66     delete[] SrcStr;
 67     delete[] SearchStr;
 68     system("pause");
 69     return 0;
 70 }
 71 
 72 
 73 std::map<char,int> buildStep(const char *vString, int vLength)
 74 {
 75     std::map<char,int> StepArray;
 76     int StrPos = vLength-1;
 77     for(int i=StrPos-1; i>=0; i--)
 78     {
 79         std::map<char,int>::iterator Iter = StepArray.find(vString[i]);
 80         if(Iter == StepArray.end())
 81         {
 82             StepArray.insert(std::make_pair(vString[i], (StrPos-i)));
 83         }
 84     }
 85     return StepArray;
 86 }
 87 
 88 
 89 bool matchString(const char* vSrcStr, int vSrcStrLen, const char* vSearchStr, int vSearchStrLen, int *voPos)
 90 {
 91     for(int n=0; n<=vSrcStrLen; n++)
 92     {
 93         voPos[n]=-1;
 94     }
 95     
 96     std::map<char,int> moveStep = buildStep(vSearchStr, vSearchStrLen);
 97     int SearchPos = 0;
 98     int MatchPos;
 99 
100     while(SearchPos <= (vSrcStrLen-vSearchStrLen))
101     {
102         MatchPos = vSearchStrLen-1;
103         while(MatchPos >= 0 && vSrcStr[SearchPos+MatchPos] == vSearchStr[MatchPos])
104             MatchPos--;
105         if(MatchPos == -1) 
106         {
107             int OcurrencePos = 0;
108             while(OcurrencePos < vSrcStrLen && voPos[OcurrencePos] != -1)
109             {
110                 OcurrencePos++;
111             }
112             voPos[OcurrencePos] = SearchPos;
113         }
114 
115         int k = 0;
116         std::map<char,int>::iterator Iter = moveStep.find(vSrcStr[SearchPos+vSearchStrLen-1]);
117         if(Iter != moveStep.end())
118         {
119             SearchPos = SearchPos+(*Iter).second;
120         }
121         else
122         {
123             SearchPos = SearchPos+vSearchStrLen;
124         }
125     }
126 
127     if(voPos[0] == -1)
128     {
129         return false;
130     }
131 
132     return true;
133 }
View Code

 

posted @ 2014-08-22 16:09  simple boy  阅读(1780)  评论(0编辑  收藏  举报