22 常用演算法 字串查詢演算法

2021-12-30 05:40:58 字數 3622 閱讀 7569

kmp字串模式匹配通俗點說就是一種在乙個字串中定位另乙個串的高效演算法。簡單匹配演算法的時間複雜度為o(m*n);而kmp演算法,可以證明它的時間複雜度為o(m+n)。

在字串o中尋找f,當匹配到位置i時兩個字串不相等,這時我們需要將字串f向前移動。常規方法是每次向前移動一位,但是它沒有考慮前i-1位已經比較過這個事實,所以效率不高。事實上,如果我們提前計算某些資訊,就有可能一次前移多位。

22.1.1.1公共字首與字尾

kmp演算法的核心即是計算字串f每乙個位置之前的字串的字首和字尾公共部分的最大長度

以」abcdabd」為例:

「a」的字首和字尾都為空集,共有元素的長度為0; 「ab」的字首為[a],字尾為[b],共有元素的長度為0; 「abc」的字首為[a, ab],字尾為[bc, c],共有元素的長度0; 「abcd」的字首為[a, ab, abc],字尾為[bcd, cd, d],共有元素的長度為0; 「abcda」的字首為[a, ab, abc, abcd],字尾為[bcda, cda, da, a],共有元素為」a」,長度為1; 「abcdab」的字首為[a, ab, abc, abcd, abcda],字尾為[bcdab, cdab, dab, ab, b],共有元素為」ab」,長度為2; 「abcdabd」的字首為[a, ab, abc, abcd, abcda, abcdab],字尾為[bcdabd, cdabd, dabd, abd, bd, d],共有元素的長度為0。

22.1.1.2 next陣列

「部分匹配」的實質是,有時候字串頭部和尾部會有重複。比如,」abcdab」之中有兩個」ab」,那麼它的」部分匹配值」(最大公共長度)就是2。搜尋詞移動的時候,第乙個」ab」向後移動4位(字串長度-部分匹配值),就可以來到第二個」ab」的位置。

理解了kmp演算法的基本原理,下一步就是要獲得字串f每乙個位置的最大公共長度。這個最大公共長度在演算法導論裡面被記為next陣列。

22.1.1.3 計算next陣列的方法

假設我們現在已經求得原字串的next[1]、next[2]、……next[i],分別表示長度為1到i的字串的字首和字尾最大公共長度,現在要求next[i+1]。

如果位置i和位置next[i]處的兩個字元相同(下標從零開始),則next[i+1]等於next[i]加1。 如果兩個位置的字元不相同,我們可以將長度為next[i]的字串繼續分割,獲得其最大公共長度next[next[i]],然後再和位置i的字元比較。這是因為長度為next[i]字首和字尾都可以分割成上部的構造,如果位置next[next[i]]和位置i的字元相同,則next[i+1]就等於next[next[i]]加1。如果不相等,就可以繼續分割長度為next[next[i]]的字串,直到字串長度為0為止。

boyer-moore字串搜尋演算法是一種非常高效的字串搜尋演算法。它由boyer和moore設計於2023年。此演算法僅對搜尋目標字串(關鍵字)進行預處理,而非被搜尋的字串。雖然boyer-moore演算法的執行時間同樣線性依賴於被搜尋字串的大小,但是通常僅為其它演算法的一小部分:它不需要對被搜尋的字串中的字元進行逐一比較,而會跳過其中某些部分。通常搜尋關鍵字越長,演算法速度越快。它的效率來自於這樣的事實:對於每一次失敗的匹配嘗試,演算法都能夠使用這些資訊來排除盡可能多的無法匹配的位置。

kmp演算法和bm演算法在最壞情況下均具有線性的查詢時間。但是在實用上,kmp演算法並不比最簡單的c庫函式strstr()快多少,而bm演算法則往往比kmp演算法快上3-5倍。

22.2.1.1 壞字元規則:即不匹配的字元

如果t中的這個不匹配的字元出現在對應p中當前位置的左側,那麼p移動位置將這兩個在字元對齊。 如果t中這個不匹配字元不在p中當前位置的左側,那麼將當前位置左側的所有字元均移到該不匹配字元後(壞字元)。

「壞字元規則」:

後移位數 = 壞字元的位置 - 搜尋詞中的上一次出現位置 如果」壞字元」不包含在搜尋詞之中,則上一次出現位置為-1。

22.2.1.2 好字尾規則:即所有尾部匹配的字串

後移位數 = 好字尾的位置 - 搜尋詞中的上一次出現位置

好字尾的位置以最後乙個字元為準。假定」abcdef」的」ef」是好字尾,則它的位置以」f」為準,即5(從0開始計算)。 如果」好字尾」在搜尋詞中只出現一次,則它的上一次出現位置為 -1。比如,」ef」在」abcdef」之中只出現一次,則它的上一次出現位置為-1(即未出現)。 如果」好字尾」有多個,則除了最長的那個」好字尾」,其他」好字尾」的上一次出現位置必須在頭部。

比如:在所有的」好字尾」(mple、ple、le、e)之中,只有」e」在」example」還出現在頭部,所以後移 6 - 0 = 6位。

22.2.1.3 實際移動:通過這兩條規則計算出的最大移動個數

這兩個規則的移動位數,只與搜尋詞有關,與原字串無關。因此,可以預先計算生成《壞字元規則表》和《好字尾規則表》。使用時,只要查表比較一下就可以了。所以要查詢的字串長度越長,bm演算法的效率也越好!

首先我們看看《演算法導論》裡的乙個例子:

圖a描述的是匹配模式串ababaca的狀態轉換圖,圖b描述的是匹配模式串ababaca的狀態轉換表,圖c描述的是搜尋文字串abababacaba中匹配模式串過程的狀態變換過程。

圖b中狀態轉換表的含義:比如狀態為0,輸入為a的項為1,表示轉換函式δ(0,a)=1,即當狀態為0時,輸入為a將轉移到狀態1。

rk演算法的原理:兩個數如果其關於某數的取模相等,則其這兩個數可能相等。我們通過將字串視為一串數字(某種進製),然後比較這些數字的取模值,取模值相同的數作為偽命中點,之後在偽命中點集再去匹配字串。

這麼做的原因是:相鄰字串的取模值有非常快速計算迭代公式:

t[s+1]=((t[s]-h*w mod q)+d )mod q

字串查詢演算法 bm演算法

今天有空,認真的對比了一下經典的字串查詢演算法bm演算法和c庫查詢函式 strstr 的區別,兩者各有優缺點,總結一下 bm演算法的應用場合 適合海量資料搜尋,比如資料庫,磁碟檔案等,總之是資料量越大,效能越高 strstr,資料量較少時,比較適合,尤其是在乙個幾千位元組的字串中查詢不同的字串,這時...

KMP 演算法 字串查詢演算法

knuth morris pratt algorithm 克努斯 莫里斯 普拉特 演算法 克努斯 莫里斯 普拉特演算法 部分匹配表 字首 指除了最後乙個字元以外,乙個字串的全部頭部組合 字尾 指除了第乙個字元以外,乙個字串的全部尾部組合 部分匹配值 就是 字首 和 字尾 的最長的共有元素的長度。以 ...

字串查詢 1 暴力字串查詢演算法

virtual int findstr const string haystack,const string needle override if j patsize return i return 1 最差情況下,haystack可能是 aaa.aaa needle是 a.ab 在這種情況下,需要...