Golang源碼剖析——字串尋找演算法

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

發現好多筆試題,都問的是庫函數。往簡單的做,有效率不太高的演算法,往複雜的做,就得看源碼了。

寫一個在一個字串(n)中尋找一個子串(m)第一個位置的函數

暴力字串匹配方法(Brute forceing matching)。這個寫法不難,複雜度O(n*m)。

func IndexFuck(s, sep string) int {for i := 0; i < len(s); i++ {if s[i] == sep[0] {is := truej := 0for ; j < len(sep); j++ {if sep[j] != s[i] {is = falsebreak}}if is {return i}}}return -1}

Rabin-Karp演算法,能把複雜度最小減到O(n)。設要匹配的子串為sep,尋找的字串為s。通過一個雜湊演算法,把sep雜湊成一個數字,以sep的長度,依次遍曆s中長度和sep相同的串,直到計算出的值是相等的。

計算雜湊的方法是,把原本的字串看作是一種E進位的編碼,然後將該編碼轉成10進位用數字表示。Golang用16777619作為該進位數。(這是我的理解,至於為什麼選擇這個整數,我也不是很清楚,只不過發現很多雜湊演算法都用過這個神奇的數字16777619 = (2^24 + 403))。

舉個例子,原始串s是12345,匹配串sep是45。第一次用12和45比較計算出串的雜湊值,1*E+2 != 4*E+5。然後計算23和45的值。

這裡有一個問題,如果要匹配的字串長度比較長,是1000位,那麼,每一次匹配都得對這1000位進行計算。這時的複雜度就是O(n*m)了,而且還需要計算,這比暴力判斷演算法還要複雜。仔細觀察,發現每次計算的長度的都一樣,而且是依次進行的,前後兩個串12和23有共同部分2,如果子串sep長度是1000,那麼前後兩次子串的共同部分就是999的長度了。所以,只需要保留共同部分,把前面的頭去掉,後面的尾補上,就能夠完成新串的計算。

上面的例子,(1*E+2)*E+3-1*E*E = 2*E+3。如此一來,一個簡單的運算,就能夠得到新串的雜湊值。Golang裡面strings包的實現:

const primeRK = 16777619// hashstr returns the hash and the appropriate multiplicative// factor for use in Rabin-Karp algorithm.func hashstr(sep string) (uint32, uint32) {hash := uint32(0)for i := 0; i < len(sep); i++ {hash = hash*primeRK + uint32(sep[i])}var pow, sq uint32 = 1, primeRKfor i := len(sep); i > 0; i >>= 1 {if i&1 != 0 {pow *= sq}// 只有32位,超出範圍的會被丟掉sq *= sq}return hash, pow}func Index(s, sep string) int {n := len(sep)// Hash sep.hashsep, pow := hashstr(sep)var h uint32for i := 0; i < n; i++ {h = h*primeRK + uint32(s[i])}if h == hashsep && s[:n] == sep {return 0}for i := n; i < len(s); {h *= primeRKh += uint32(s[i])h -= pow * uint32(s[i-n])i++if h == hashsep && s[i-n:i] == sep {return i - n}}return -1}

最後面的for迴圈,i表示計算新串新加的字元,也就是例子裡面的3。所以,i-n+1就是新串的頭地址。

一般,按照這種演算法算出的值都會超過整形的範圍。上面的16777619,計算一下平方就超unit32的範圍了。常用的做法,是再取一個比較大的質數,求餘,用餘數作為雜湊值。這樣就能保證高位不會被截取丟棄了。而Golang包裡的代碼是不操作,直接丟棄,太霸氣了。

本文所涉及到的完整源碼請參考。

參考文獻
  • 【1】圖說Rabin-Karp字串尋找演算法 - 圖靈社區
  • 【2】字串匹配之Rabin-Karp演算法 - lmx077
  • 【3】Rabin-Karp 字串搜尋演算法 - 貔貅
  • 【4】Source file src/pkg/strings/strings.go - The Go Programming Language

原文連結:Golang源碼剖析——字串尋找演算法,轉載請註明來源!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.