1. 程式人生 > >Horspool(字串匹配)演算法

Horspool(字串匹配)演算法

Horsepool演算法是Boyer-Moore演算法的簡化版本,這也是一個空間換時間的典型例子。演算法把模式P和文字T的開頭字元對齊,從模式的最後一個字元開始比較,如果嘗試比較失敗了,它把模式向後移。每次嘗試過程中比較是從右到左的。

假設文字中,對齊模式最後一個字元的元素是c,Horspool演算法根據c的不同情況來確定移動距離,無論c是否和模式的最後一個字元相匹配。

一般來說,會存在下面四種情況。

這裡寫圖片描述

情況1:看第一行,模式中不存在c(此時c就是字母A),模式的移動長度就是它的全部長度,移到第二行所示的位置。

情況2:看第二行,c(此時c就是字元O)正好是模式的最後一個字元,但是從右向左比較時,有字元不匹配,比如此時的A

E不匹配。而且模式中的其他m-1個字元也不包含c。移動的情況類似情況1,移動的幅度等於模式的全部長度,移到第三行所示的位置。

這裡寫圖片描述
情況3:看第一行,模式中存在c(此時c就是字元L),但是它不是模式的最後一個字元,移動時應該把模式中最右邊的c和文字中的c對齊,移到第二行所示的位置。
情況4:看第二行,c(此時c就是字元O)正好是模式的最後一個字元,但是從右向左比較時,有字元不匹配,比如此時的AE不匹配。而此時模式中的其他m-1個字元包含c。移動的情況類似情況3,移動時應該把前m-1個字元中最右邊的c和文字中的c對齊,移到第三行所示的位置。



這說明,比起蠻力演算法每次總是移動一個位置,從右到左的字元比較使模式模式移動得更遠。然而,如果在每次嘗試時都必須檢查模式中的每個字元,它的優勢也會喪失殆盡。我們可以預先算出遇到某個字元要移動的距離,並把它存在一個表中。具體來說,對於每一個字元c,可以通過以下公式算出移動距離:

t(c)={mm1ccm-1

如對於模式BARBER,移動距離如下表所示:

字元c A B E R 其它字元(包括空格,標點符號,下劃線和其它一些特殊字元)
移動距離t(c) 4 2 1 3 6

c++實現

int Horspool(vector<char> & T,vector<char> & P)
{
    int n = T.size();
    int m = P.size();   
    vector
<int>
table(96,m);//以字母表中可列印字元為索引的陣列 for(int i = 0;i < m - 1;i++) { table[P[i] - 32] = m - 1 - i;//模式串中每個字元的移動距離,從左至右掃描模式,相同字元的最後一次改寫恰好是該字元在模式串的最右邊 } int i = m - 1; while(i <= n - 1) { int k = 0; while(k <= m - 1 && P[m - 1 - k] == T[i - k]) k++; if(k == m) return i - m + 1;//匹配成功,返回索引 else i += table[T[i] - 32];//模式串向右移動 } return -1;//匹配失敗 }