Horspool 字符串快速查找算法

Horspool算法是后缀搜索算法,对于每个文本搜索窗口,将窗口内的最后一个字符与模式串(needle)的最后一个字符进行比较。如果相等,则继续从后向前验证其他字符,直到完全相等或者某个字符不匹配。当遇到字符不匹配的情况时就需要将搜索窗口往后移动,计算移动的距离可以有不同方法,Wikipedia中给出的C语言实现版本是基于窗口的最后一个字符(haystack上的)。

 

C语言版代码分析:

 1 // 在 haystack 中查找 needle 子字符串

 2 const unsigned char *horspool_memmem(const unsigned char *haystack, size_t hlen,

 3                                      const unsigned char *needle, size_t nlen)

 4 {

 5   size_t scan = 0;

 6   

 7   // 单个字符的位移对照表

 8   size_t bad_char_skip[UCHAR_MAX + 1];

 9 

10   // 参数检查

11   if (nlen <= 0 || !haystack || !needle)

12     return NULL;

13 

14   // 初始化位移对照表,缺省值是 needle 的长度,即遇到不匹配时将搜索窗口往后移动 needle 长度

15   // 比如:如果遇到 needle 中没有的字符时,就可以将搜索窗口后移 needle 长度,以跳过该字符

16   for (scan = 0; scan <= UCHAR_MAX; scan = scan + 1)

17     bad_char_skip[scan] = nlen;

18 

19   // needle 最后一个字符的下标

20   size_t last = nlen - 1;

21 

22   // 遍历 needle 的字符(排除最后一个字符),计算该字符到最后一个字符的位移。

23   // 此处遍历需要从头开始,因为 needle 中可能会出现重复字符,同一个字符必须使用其最后出现位置的位移。

24   // 

25   // 排除 needle 最后一个字符的原因是:如果 needle 的最后一个字符在 needle 中是唯一的,那么其位移对照表中的值是 nlen,

26   // 只要当次搜索匹配失败,并且搜索窗口上 haystack 的最后一个字符就是 needle 的最后一个字符,那么就应该将搜索窗口后移 nlen,

27   // 因为该字符没有重复出现 needle 的其它位置上,就可以安全的跳过当前窗口。

28   for (scan = 0; scan < last; scan = scan + 1)

29     bad_char_skip[needle[scan]] = last - scan;

30 

31   // 开始搜索匹配

32   // 由于搜索窗口不断往后移动,即 haystack 指针值向后移动,hlen 保存 haystack 的剩余字符串长度。

33   // 当 hlen 的长度小于 nlen 时,查找失败。

34   while (hlen >= nlen) {

35     // 从搜索窗口的尾部向前匹配

36     for (scan = last; haystack[scan] == needle[scan]; scan = scan - 1) {

37       if (scan == 0)  // 头部字符匹配则查找成功,返回子字符串位置

38         return haystack;

39     }

40     

41     // 如果匹配失败则基于搜索窗口上 haystack 的最后一个字符 haystack[last] 后移搜索窗口

42     hlen     -= bad_char_skip[haystack[last]];

43     haystack += bad_char_skip[haystack[last]];

44   }

45 

46   // 到达此处说明查找失败

47   return NULL;

48 }

 

查找过程示例:

原始串

haystack: efaboxcbcabcdsdxzcxx

needle:   abcd



初始化

last: 3

bad_char_skip['a'] = 3

bad_char_skip['b'] = 2

bad_char_skip['c'] = 1

bad_char_skip['d'] = 1



循环1

last: 3

haystack[last]: b

bad_char_skip[haystack[last]]: 2

haystack: aboxcbcabcdsdxzcxx

needle:   abcd



循环2

last: 3

haystack[last]: x

bad_char_skip[haystack[last]]: 4

haystack: cbcabcdsdxzcxx

needle:   abcd



循环3

last: 3

haystack[last]: a

bad_char_skip[haystack[last]]: 3

haystack: abcdsdxzcxx

needle:   abcd



循环4

匹配成功

 

参考文档

  1. Boyer–Moore–Horspool algorithm - Wikipedia
  2. Horspool字符串匹配算法

  

你可能感兴趣的:(字符串)