手寫布隆過濾器 第一場第一鏡

隨着最後一縷春風拂過,空氣中瀰漫起了夏天的味道,又該滾去學習了。 最近在學習Redis,發現了一個好玩的東西叫布隆過濾器。但是個人水平又不足以研究源碼,那我就本身寫一個簡單的玩玩。程序員

原理

請原諒個人班門弄斧。我認爲布隆過濾器就是用來判斷key是否存在的,基於位圖。有一個特色是,若是我說key不存在,那麼您能夠徹底信任我,若是我說key存在,您可能就要掂量一下啦。恩恩,具體說來就是來了一個key,咱們對其進行n次不一樣的hash,生成n個bit的索引,在位圖裏將這幾個bit置成1,再來了另外一個key,對其進行相同的hash,看看生成的索引對應的bit是否都爲1,都爲1即爲(可能)存在,反之(必定)不存在。至於爲何會出現這種不許確的狀況,能夠去google一下,比我講得清楚多了。算法

開工

首先,咱們須要一個位圖,既然決定純手寫,那就從0開始DIY了。 老爺請上碼:學習

type BM int64
//用切片來充當位圖,切片的每一個位與二級制位方向正好相反
type BitMap struct {
	BitSlice []BM
	BitNum uint
}
//求一個BM的bit數,確定有更好的計算方法
var bmBitNum = uint(unsafe.Sizeof(BM(1)) * 8)

//n爲須要的bit數
func NewBitMap(n int) *BitMap {
	//計算須要幾個元素bit纔可以
	bitNum := uint(n) / bmBitNum + 1
	return &BitMap {
		BitSlice : make([]BM,bitNum,bitNum),
		BitNum : uint(n),
	}
}
//n爲位圖的索引
func (bm *BitMap) Set (n uint) {
	if n > bm.BitNum {
		return
	}
	//求出應該是切片的第幾個元素
	byteIndex := n / bmBitNum
	//求出是此元素的第幾個bit
	bitIndex := n % bmBitNum
	//經過位運算將該bit置成1
	bm.BitSlice[byteIndex] |= BM(uint(1) << bitIndex)
}
//一樣的思路去找所在bit是否已經被置成1
func (bm *BitMap) Get (n uint) bool{
	if n > bm.BitNum {
		return false
	}
	byteIndex := n / bmBitNum
	bitIndex := n % bmBitNum
	return (bm.BitSlice[byteIndex] & BM(uint(1) << bitIndex)) != 0
}
複製代碼

OK,就這樣咱們完成了一個簡單的位圖。至於之後的各類優化只能等我水平高一些來再續前緣了。 有了位圖就能夠搞布隆過濾器了。 老弟來了:優化

//這裏的兩個切片是用來hash的,mod裏最大的質數爲101,我準備用3個hash生成3個bit,hash事後生成的最大的bit爲101。
var cap = []uint{7, 11, 13}
var mod = []uint{31, 37, 101}
//剛剛手寫的位圖派上用場了
type BloomFilter struct {
	BitMap   *bitMap.BitMap
}
//n依舊爲須要的位數
func NewBloomFilter(n int) *BloomFilter {
	return &BloomFilter {
		BitMap:bitMap.NewBitMap(n),
	}
}
//通過3次hash
func (bf BloomFilter) Set(value string) {
	for i := 0; i < len(cap); i++ {
		bf.BitMap.Set(hash(value,i))
	}
}

//一樣規則的三次hash判是否存在
func (bf BloomFilter) Exist(value string) bool {
	for i := 0; i < len(cap); i++ {
		if !bf.BitMap.Get(hash(value,i)) {
			return false
		}
	}
	return true
}

//我本身寫的hash算法,濃濃的鄉土氣息。等我再學習一段時間確定能搞一個更好的!
func hash(s string,index int) uint {
	bit := uint(1)
	for i := 0; i < len(s); i++ {
		bit = (bit * cap[index] + (uint(s[i] - 'a') + uint(1))) % mod[index]
	}
	return bit
}
複製代碼

好了,就是這樣。其實我只是想說,學習任何東西,要從原理抓起,要瘋狂地實踐。不要拿半路轉行的碼農不當程序員哦。ui

最後,分享一個公衆號吧,叫作算法夢想家,來跟我一塊兒玩算法,玩音樂,聊聊文學創做,我們一塊兒天馬行空!google

相關文章
相關標籤/搜索