最近在寫乙個搜尋字串的用例,剛好使用到這個演算法,在網路上學習了多篇文章,在這裡記錄一下自己的理解。
首先理清楚演算法的原理:
1.演算法是從尾部開始比較字串的,如果最後乙個字元不匹配,且不匹配的字元不在模式串中,那麼可以直接忽略這段比較內容, 這種情況下效率最高。如下所示:
abbdd
ccggxabbddtuuy
d != x 因此可以直接將指標移動到
----------abbdd
ccggxabbddtuuy。
如果不匹配的字元在模式串中,如下:
axbdd
ccggxabbddtuuy 則移動如下:
------axbdd
ccggxabbddtuuy
這些就是演算法中所謂的「壞字元「的情況。
2.當演算法匹配一部分,但是遇到不等的情況時,如下所示:
abbdd
cxbddabbdd
b != x ,這時有兩種方式移動指標。第一種就是按照「壞字元」的方式,忽略cx,即指標向後移動兩位。但是這樣,效率好像不太高,因為我們知道bdd這三個字元是比較過的,如何運用這些已知資訊呢。
這就是演算法的精髓所在了。我們假設abbdd能與cx之後的字串匹配上,那麼ab必須等於bd。但這明顯是錯誤的,因此如果我們能事先對模式串進行預處理,即記錄它自身的字串的匹配資訊,那麼我們就可以利用這些資訊,判斷是否需要進一步比較的必要性了。
怎麼理解呢,如在abbdd中以bdd為字尾的串,僅僅出現了一次,這樣我們就知道,如果某個字串如cxbdd中與bdd部分匹配,如果僅僅把模式串移動兩位那就會導致ab需要和bdd比較,但是我們已經預先知道bdd之出現一次,這樣就冗餘了,因此我們可以把指標向後移動5個位元組,效率就比「壞字元」高多了。這也被稱為「好字尾」。
再比如
addbbdd 與
cafbaddbbdd
a!=b 但是dd在模式串**現兩次,我們把指標移動到最近乙個上就變成,
--------addbbdd
cafbaddbbdd
為什麼要這麼移動呢?就是因為dd是匹配的,那麼移動到這個位置上,就有可能匹配上。當然例子中是故意寫出可以找到的,實際情況不一定能馬上匹配上。但是這樣做,確實可以大大提公升查詢的效率。
明白了演算法的出發點,那麼**理解起來就容易了。具體實現不在贅述。
下面是官方**經過包裝,變為c++的風格,自寫自測可用,效果不錯哦!
#ifndef bm_search_h
#define bm_search_h
#include#include#include#includeusing namespace std;
class cbmsearch
;#endif
#include"cbmsearch.h"
cbmsearch::cbmsearch(const char* pszpattern):m_strpattern(pszpattern),
m_vecsuff(m_strpattern.length()),
m_vecgoodsuff(m_strpattern.length()),
m_vecbadcode(256)
void cbmsearch::calsuffixes()
}}void cbmsearch::pregoodsuffixes()
else
}return 0;
}
使用方式如下:
vectorovecresult;//記錄找到的位置
cbmsearch otest("abbdd");
otest.searchpattern("cafbaddbbdd",strlen("cafbaddbbdd"),ovecresult);
Boyer Moore 投票演算法
刷題過程中遇到的乙個非常巧妙的演算法。是出現在 求陣列 現超過一半的數字 這道題中。陣列中有乙個數字出現的次數超過陣列長度的一半,請找出這個數字。你可以假設陣列是非空的,並且給定的陣列總是存在多數元素。例項1輸入 1,2,3,2,2,2,5,4,2 輸出 2 1 陣列長度 50000 思路 如果把陣...
Boyer Moore 投票演算法
有以下問題 給定乙個大小為 n 的陣列,找到其中的多數元素。多數元素是指在陣列 現次數 大於 n 2 的元素。你可以假設陣列是非空的,並且給定的陣列總是存在多數元素。比較容易想到的解法是用雜湊表對每個數出現的次數進行儲存,然後就可以找出次數最多的那個數了。這樣做的時間和空間複雜度都是 o n o n...
KMP演算法和Boyer Moore演算法
kmp演算法是一種改進的字串匹配演算法,由d.e.knuth,j.h.morris和v.r.pratt同時發現,因此人們稱它為克努特 莫里斯 普拉特操作 簡稱kmp演算法 kmp演算法的關鍵是利用匹配失敗後的資訊,儘量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是實現乙個next 函式...