字符串查找算法總結(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)

字符串匹配是字符串的一種基本操做:給定一個長度爲 M 的文本和一個長度爲 N 的模式串,在文本中找到一個和該模式相符的子字符串,並返回該字字符串在文本中的位置。java

KMP 算法,全稱是 Knuth-Morris-Pratt 算法,以三個發明者命名,開頭的那個K就是著名科學家 Donald Knuth 。KMP 算法的關鍵是求 next 數組。next 數組的長度爲模式串的長度。next 數組中每一個值表明模式串中當前字符前面的字符串中,有多大長度的相同前綴後綴。linux

Boyer-Moore 算法在實際應用中比 KMP 算法效率高,聽說各類文本編輯器的"查找"功能(Ctrl+F),包括 linux 裏的 grep 命令,都是採用 Boyer-Moore 算法。該算法有「壞字符」和「好後綴」兩個概念。主要特色是字符串從後往前匹配。算法

Sunday 算法跟 KMP 算法同樣,是從前日後匹配。在匹配失敗時,關注文本串中參加匹配的最末位字符的下一位字符,若是該字符不在模式串中,則整個模式串移動到該字符以後。若是該字符在模式串中,將模式串右移使對應的字符對齊。數組

關於這幾種算法的詳細介紹,可參考該博客編輯器

下面分別給出暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法的 Java 實現。.net

暴力匹配:

public static int forceSearch(String txt, String pat) {
    int M = txt.length();
    int N = pat.length();
    for (int i = 0; i <= M - N; i++) {
        int j;
        for (j = 0; j < N; j++) {
            if (txt.charAt(i + j) != pat.charAt(j))
                break;
        }
        if (j == N)
            return i;
    }
    return -1;
}

KMP 算法:

public class KMP {
    public static int KMPSearch(String txt, String pat, int[] next) {
        int M = txt.length();
        int N = pat.length();
        int i = 0;
        int j = 0;
        while (i < M && j < N) {
            if (j == -1 || txt.charAt(i) == pat.charAt(j)) {
                i++;
                j++;
            } else {
                j = next[j];
            }
        }
        if (j == N)
            return i - j;
        else
            return -1;
    }

    public static void getNext(String pat, int[] next) {
        int N = pat.length();
        next[0] = -1;
        int k = -1;
        int j = 0;
        while (j < N - 1) {
            if (k == -1 || pat.charAt(j) == pat.charAt(k)) {
                ++k;
                ++j;
                next[j] = k;
            } else
                k = next[k];
        }
    }


    public static void main(String[] args) {
        String txt = "BBC ABCDAB CDABABCDABCDABDE";
        String pat = "ABCDABD";
        int[] next = new int[pat.length()];
        getNext(pat, next);
        System.out.println(KMPSearch(txt, pat, next));
    }
}

Boyer-Moore 算法

public class BoyerMoore {
    public static void getRight(String pat, int[] right) {
        for (int i = 0; i < 256; i++){
            right[i] = -1;
        }
        for (int i = 0; i < pat.length(); i++) {
            right[pat.charAt(i)] = i;
        }
    }

    public static int BoyerMooreSearch(String txt, String pat, int[] right) {
        int M = txt.length();
        int N = pat.length();
        int skip;
        for (int i = 0; i <= M - N; i += skip) {
            skip = 0;
            for (int j = N - 1; j >= 0; j--) {
                if (pat.charAt(j) != txt.charAt(i + j)) {
                    skip = j - right[txt.charAt(i + j)];
                    if (skip < 1){
                        skip = 1;
                    }
                    break;
                }
            }
            if (skip == 0)
                return i;
        }
        return -1;
    }

    public static void main(String[] args) {
        String txt = "BBC ABCDAB AACDABABCDABCDABDE";
        String pat = "ABCDABD";
        int[] right = new int[256];
        getRight(pat,right);
        System.out.println(BoyerMooreSearch(txt, pat, right));
    }
}

Sunday算法

public class Sunday {
    public static int getIndex(String pat, Character c) {
        for (int i = pat.length() - 1; i >= 0; i--) {
            if (pat.charAt(i) == c)
                return i;
        }
        return -1;
    }

    public static int SundaySearch(String txt, String pat) {
        int M = txt.length();
        int N = pat.length();
        int i, j;
        int skip = -1;
        for (i = 0; i <= M - N; i += skip) {
            for (j = 0; j < N; j++) {
                if (txt.charAt(i + j) != pat.charAt(j)){
                    if (i == M - N)
                        break;
                    skip = N - getIndex(pat, txt.charAt(i + N));
                    break;
                }
            }
            if (j == N)
                return i;
        }
        return -1;
    }
    public static void main(String[] args) {
        String txt = "BBC ABCDAB AACDABABCDABCDABD";
        String pat = "ABCDABD";
        System.out.println(SundaySearch(txt, pat));
    }
}
相關文章
相關標籤/搜索