1. 程式人生 > >Horspool算法-字符串匹配

Horspool算法-字符串匹配

相等 計算機實現 name align 計算 查詢 例如 所有 之前

不得不說ACM哪怕是沒有結果,對於算法能力的訓練是毋庸置疑的……

因為老師劃了重點,所以講一下horspool的字符串匹配算法的原理吧。

先聲明幾個概念,被找的字符串稱為匹配串,要找的字符串被稱為模式串,當前和模式串相匹配的匹配串的子串被稱為匹配子串(廢話

在樸素算法中,我們要找一個匹配串是否存在模式串,例如HuangZhi is a genius的匹配串串和ChengJinSen的模式串,那麽我們一開始用的方法是用:

HuangZhi is(11 character)

去匹配:

ChengJinSen(11 character)

如果每個字母都相等,那麽我們就認為這個模式找到了。

但是這個算法的效率是多少呢,假設匹配串的長度為N,模式串的長度為m,那麽易證時間效率為:O(n*m),在很多時候這個效率都是很慢的。

而Horspool算法(在我看來)是有這樣一個基本思想:如果我提前知道了這個步驟是可以跳過的,那我就可以不用去驗證了。

我們拿saber和archer作為模式串和匹配串好了:

archer

saber

很明顯,在初次對齊的時候,其並不相等,而且我們註意到了,此次匹配串對應的子串是:arche,而最後一個字母是e.

那麽很明顯的,假如我們一個個移動下去,直到模式串的下一個e為止,都不可能達到匹配的結果。

這裏e就是下一個,所以我們把saber稍稍的改一下,改成sebar,這時候就會發現,假設你一個個挪,到e之前的所有都不可能和arche裏的e匹配,所以這裏我們完全可以直接把e挪到arche的e的位置,然後在進行匹配計算,這樣就節省了不少的時間。也就是說,跳過e到模式串最後一個字母之間的距離。

以上的情況,可以歸納為情況1,即匹配子串的最後一個在模式串中出現過,且不是模式串的最後一個字母(最後的特殊性會講到)

那麽,假設最後一個字符在模式串裏從來沒有出現過呢?那這樣,假設一個個移,每一個都必然得不到匹配結果,直到該字符不在匹配子串中,如此,則是直接跳過整個子串的長度。

以上情況歸為情況2,匹配子串的最後一個字母沒有在模式串裏出現過,且不是模式串的最後一個字母。

好了,為什麽上面要提到模式串的字母呢?因為這個查詢方法存在一個問題,假設匹配子串的最後一個字母在模式串中出現過,且為模式串的最後一位呢?那這樣就要分成兩種情況來討論,

1,是模式串的最後一位字母在模式串中唯一,那這樣就類似於情況2,直接跳過這個匹配子串最後字母的匹配,即跳過字符長度。這個我們姑且稱為情況3。

2,是該字母在模式串中不唯一,那這樣就仿照情況二,找到離模式串結尾最近的,且同樣是這個字母的字母的位置,並跳轉以後匹配。這個我們稱為情況4

然後是這個算法的計算機實現,總結了下上述規律,我們發現這個模式串跳轉的機制,可以不用每次查找模式串中是否有同樣的值,而用預處理的方式來實現,根據情況一二的總結,我們得出,模式串中存在的字母,向右找到其最貼近模式串結尾的同樣的字母,並把其離結尾的位置存下,方便應用,若不存在,則直接跳轉模式串長度,為了方便,我們也把它存下來,不過跳轉長度設為模式串長度。根據情況3,4的總結,我們得出,最後一個字母不應納入上述的計算。

附帶試驗用算法:

#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<string>
#define INF 0x3f3f3f3f
using namespace std;
int main() {
string M, P;
cin >> M >> P;
map<char, int>NEXT;
for (int i = 0; i < 26; i++)
NEXT[‘a‘ + i] = P.size();
for (int i = 0; i < 26; i++)
NEXT[‘A‘ + i] = P.size();
for (int i = 0; i < P.size() - 1; i++)
NEXT[P[i]] = P.size() - i-1;
int space = 0;
for (int i = 0; i <= M.size()-P.size();)
{
space = i;
cout << M << endl;
for (int i = 0; i < space; i++)
cout << " ";
cout << P << endl << "_________________________________" << endl;
if (M.substr(i, P.size()) == P)
cout << "找到匹配串" << endl;
i += NEXT[M[i + P.size() - 1]];
}


}

Horspool算法-字符串匹配