Horspool算法是一种基于后缀的匹配方法,它的主要难点在于如何安全地移动窗口,以避免遗漏可能的成功匹配。
1,Horspool的基本思想
horspool算法将主串中匹配窗口的最后一个字符跟模式串中的最后一个字符比较。如果相等,继续从后向前对主串和模式串进行比较,直到完全相等或者在某个字符处不匹配为止(如下图中的α与σ失配) 。如果不匹配,则根据主串匹配窗口中的最后一个字符β在模式串中的下一个出现位置将窗口向右移动。
2,Horspool的求解过程
此处选择参考文献[1]中的一个例子来详细介绍下Horspool的求解过程
在序列AGATACGATATATAC中搜索字符串ATATA。
首先,要构造失配时模式串中元素的移动距离数组d:
然后开始逐次匹配:
1)A G A T A C G A T A T A T A C
A T A T A
在主串的G处失配,此时模式串向右移动的距离是d[A]=2
2)A G A T A C G A T A T A T A C
A T A T A
又在主串G处失配,此时模式串向右移动的距离是d[G]=5
3)A G A T A C G A T A T A T A C
A T A T A
此处发现了一个匹配,我们可以继续往下找,此时模式串向右移动的距离是d[A]=2
4)A G A T A C G A T A T A T A C
A T A T A
呃。。。又发现了一个匹配,再继续往下找吧,此时模式串向右移动的距离依然是d[A]=2
5)A G A T A C G A T A T A T A C
A T A T A
移动后,主串指针pos>n-m了,搜索过程结束。
3,Horspool算法实现
这里我提供了一个第2小节中提到的DNA子串查找的horspool算法实现。
1 /*
2 * implementation of Horspool
3 * Author:Horspool
4 * Coder: Cobbliu
5 */
6 #define WORD 26
7 int horspool(char *T, int lenT, char *P, int lenP)
8 {
9 int d[WORD];
10 int i, pos, j;
11
12 for(i = 0; i != WORD; i++)
13 d[i] = lenP;
14 for(i = 0; i != (lenP-1); i++)
15 d[P[i]-'A'] = lenP-i-1;
16
17 pos = 0;
18 while(pos < (lenT-lenP)){
19 j = lenP-1;
20 while(j >= 0 && T[pos+j]==P[j]) //matching
21 j--;
22 if(j == -1)
23 return pos;
24 else //not matched
25 pos += d[T[pos+lenP-1]-'A'];
26 }
27
28 return -1;
29 }
4,Horspool算法复杂度
假设主串的长度为n,模式串的长度为m,那么Horspool算法最坏情况下的时间复杂度是O(mn),但平均情况下它的时间复杂度是O(n)。