數據結構與算法-----12.字符串匹配:

在軟件工程中,我們用到字符串匹配的地方非常多,比如:文本編輯軟件中的查找功能,判斷兩個字符串是否相等。字符串匹配分爲兩種情況:(1)字符串一對一的匹配,(2)在一個字符串中同時查找多個子串。

1.對於一對一的匹配,有經典的BF算法(Brute Force)暴力匹配算法:

核心思想:字符串匹配算法中有兩個核心詞:(1)基礎字符串(主串)(2)模式串

(例如:在字符串A中查找字符串B,那麼A就是主串,B就是模式串)

假如主串長度爲m,模式串長度爲n,根據模式串的長度,可以將主串分解成m-n+1個子串。然後拿着模式串與主串逐一進行匹配,時間複雜度爲O(m*n)

主串:abcbdef     子串:bcd 

可以將主串分解爲:abc   bcd   cbd  bde   def 

public class StringMatch {

    public static void main(String[] args) {
        String basic = "zhangsanlisi";
        String pattern = "lisi";
        StringMatch match = new StringMatch();
        int i = match.bf(basic,pattern);
        System.out.println("在基礎字符串中第一次出現的位置:"+i);
    }
    /*暴力匹配算法:
    * 將基礎字符串按照模式串分解成a-b+1個,然後逐個與模式串進行匹配
    * 時間複雜度爲O(n*m) n爲基礎字符串的長度,m爲模式串的長度*/
    public int bf(String basic,String pattern) {
        int a = basic.length();
        int b = pattern.length();
        int k;
        char[] bas = basic.toCharArray();
        char[] pat = pattern.toCharArray();
        /*判斷參數是否有效*/
        if(a == 0 || b == 0 || a-b<0) return -1;
        /*當前for循環的意思是:基礎串與模式串比較的次數,一個基礎串可以分解成a-b+1個模式串*/
        for(int i=0;i<=a-b;i++) {
            k = 0;
            /*拿模式串與當前分解的基礎串進行逐個字符的匹配,參數k用來記錄匹配到的字符串的個數*/
            for(int j=0;j<b;j++) {
                if(bas[i+j] == pat[j]) {
                    k++;
                }else {
                    break;
                }
            }
           /*如果k與模式串的長度b相等的話,那麼證明兩個字符串就是相等的*/
            if(k == b) return i;
        }
        return -2;
    }
}

在實際的軟件開發中,主串和模式串的長度可能相對比較短,並且在匹配的過程中,如果遇到不相等的字符,就會停止當前的匹配操作,最壞的情況下時間複雜度爲O(m*n),但是實際情況都比這個值低,並且暴力匹配算法思想簡單,容易實現,所以在條件允許的情況下是首選。

2.Trie樹(字典樹):

像是Google,百度這樣的搜索引擎,當我們在搜索欄中鍵入某一些文字的時候,它就會在下拉欄中自動提示出一些相應的關鍵詞。這種搜索引擎的自動提示功能就可以使用Trie樹來實現。

Trie數的本質就是利用字符串之間的公共前綴,將重複的前綴合並在一起,構成一個(字符串集合)一顆字典樹。

Trie樹的結構大致如下:

在Trie數中,根節點不包含任何信息,其它每一個節點都包含某一字符串中的一個字符。在Trie中有兩個重要的操作:

(1)通過字符串集合來構建一顆Trie樹:因爲構建Trie樹需要遍歷所有的字符串,所以時間複雜度爲O(n)

(2)在Trie中查詢某一個字符串:假設需要查詢的字符串長度爲k,那麼我們只需比對大約k個節點,所以查找的時間複雜度爲 O(k)。

3.Trie樹和散列表,紅黑樹的比較:

字符串的匹配問題,歸根結底就是數據的查找問題,對於動態高效數據操作的數據結構,其實也可以實現字符串的匹配功能。例如,散列表,紅黑樹,跳錶等。他們各自的優缺點如下:

利用Trie樹進行字符串匹配,其實對數據的要求比較苛刻:

(1)首先字符集不能太大,因爲Trie樹在存儲數據時,不僅要存儲數據本身,還要存儲指針的引用,所以會浪費更多的空間。

(2)同時需要字符串前綴重合的比較多,不然同樣會消耗更多的空間。

(3)Tried樹中的數據是通過指針串起來的,所以在內存中的分佈是不連續的,對CPU緩存不友好。

(4)如果要使用Trie樹來實現字符串匹配,需要從0到1來構建,增加了工程的複雜度。

實際上,Tried樹只是不適合精確查找,如果進行精確查找,那麼可以使用其它動態操作數據的容器。Trie樹適合匹配查找這種應用場景

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章