字串匹配之Sunday演算法

看風景就發表於2017-05-29

Sunday演算法不像KMP演算法那麼複雜,但是效率又比較高,在KMP之上,下面簡單介紹Sunday演算法及其實現。

Sunday 演算法由 Daniel M.Sunday 在 1990 年提出,它的思想跟 BM 演算法很相似:

只不過 Sunday 演算法是從前往後匹配,在匹配失敗時關注的是文字串中參加匹配的最末位字元的下一位字元。


如果該字元沒有在模式串中出現則直接跳過,即移動位數 = 匹配串長度 + 1;
否則,其移動位數 = 模式串中最右端的該字元到末尾的距離 +1,使得下一位字元與模式串中與其相等的字元對齊。


下面舉個例子說明下 Sunday 演算法。假定現在要在文字串"substring searching algorithm"中查詢模式串"search"。

1.剛開始時,把模式串與文字串左邊對齊:

 

2.結果發現在第 2 個字元處發現不匹配,不匹配時關注文字串中參加匹配的最末位字元的下一位字元,即標粗的字元 i,因為模式串 search 中並不存在 i,
所以模式串直接跳過一大片,向右移動位數 = 匹配串長度 + 1 = 6 + 1 = 7,從 i 之後的那個字元(即字元 n)開始下一步的匹配,如下圖:

3.結果第一個字元就不匹配,再看文字串中參加匹配的最末位字元的下一位字元,是'r',它出現在模式串中的倒數第3位,於是把模式串向右移動 3 位(r 到模式串末尾的距離 + 1 = 2 + 1 =3),使兩個'r'對齊,如下:

 

4.匹配成功。

下面是Sunday演算法的javascript實現

function sunday(source, pattern) {
    var sLen = source.length,
        pLen = pattern.length;
    var sIndex = 0,
        pIndex = 0,
        loc = 0;
    while (sIndex < sLen && pIndex < pLen) {
        //索引相等,向後繼續比對
        if (source[sIndex] == pattern[pIndex]) {
            sIndex++;
            pIndex++;
        } 
        else {
            //not equal,jump
            var aimChar = source[sIndex + pLen],
                pAim = pLen - 1;
            //找索引,與參與匹配的串的下一位的值相等的字元在模式串中的索引
            while (pAim > 0) {
                if (aimChar == pattern[pAim]) {
                    break;
                }
                pAim--;
            }
            //jump,pLen - pAim就是sIndex應該前進的值,sIndex從0算起
            sIndex += pLen - pAim;
            //record location
            loc = sIndex;
            //reset to zero
            pIndex = 0;
        }
    }
    if (pIndex < pLen) {
        return -1;
    }
    return loc;
}

由於Sunday演算法每一步的移動量都比較大,因此效率很高。

 

 

參考:http://wiki.jikexueyuan.com/project/kmp-algorithm/sunday.html

   http://blog.csdn.net/silver_sail/article/details/8137782

相關文章