哈希函數和哈希表
Hash函數的性質:輸入無窮大,輸出有限,相同輸入得到相同輸出,不同輸入可能會出現相同輸出,輸入到輸出均勻分布,相差一點的輸入輸出相差很大。哈希函數加上模運算可以進行數據的分流操作。
哈希表:數據存儲和檢索當中使用哈希表的作用是將一個非常大的空間映射到一個可以接受的存儲空間當中,在檢索一個值的時候時間復雜度為O(1),並且存儲空間可接受。假如要存儲一個長度為10的字符串,它可能的情況為26^10 = 1.4 * 10^14種,假如一一映射的話,需要很大的存儲空間,這顯然是不合適的。
設計哈希表要考慮兩塊內容,一塊內容是如何設計映射函數,另一塊內容是當出現沖突的時候如何解決這個沖突(因為從大到小映射,沖突是必然的),叫做沖突的消解機制。圍繞這兩個問題,可以設計出來實際可用的哈希算法。
散列函數:對於整數有:數字分析法、折疊法、中平均法。 常用散列函數:除余法,基數轉換法。
沖突消解機制:內消解方法(開放地址法+探查序列)。外消解技術主要有:溢出區方法,桶散列方法。
設計RandomPool結構
【題目】 設計一種結構, 在該結構中有如下三個功能:insert(key): 將某個key加入到該結構, 做到不重復加入。delete(key): 將原本在結構中的某個key移除。 getRandom():等概率隨機返回結構中的任何一個key。
【要求】 Insert、 delete和getRandom方法的時間復雜度都是O(1)
【思路】用兩個hash表來實現,一個表存入{key:size},另外一個表存入{size:key}。這樣隨機獲得size的大小來隨機獲得一個key。這里的稍微有點繞的地方是刪除一個數據的時候操作過程。
import random class random_dict(object): def __init__(self): self.key_dict = {} self.value_dict = {} self.size = 0 def insert(self, key): if not key in self.key_dict: self.key_dict[key] = self.size self.value_dict[self.size] = key self.size += 1 def get_random(self): if self.key_dict: random_num = random.randint(0, self.size-1) return self.value_dict[random_num] def delete(self, drop_key): """ a -> 1 1->a b -> 2 2->b c -> 3 3->c 如果想要刪除b,那么如何進行 根據b,得到2 | 根據2 得到b' | b'用最后一個元素代替 | c指向2 | 刪除b和3 """ if drop_key in self.key_dict: self.size -= 1 drop_size_index = self.key_dict[drop_key] last_value = self.value_dict[self.size] self.value_dict[drop_size_index] = last_value self.key_dict[last_value] = drop_size_index del self.key_dict[drop_key] del self.value_dict[self.size]
布隆過濾器
布隆過濾器是解決:在一個數據量很大的范圍內檢索一個數值是不是存在。
優點: 使用內存小,查找為O(1)的時間操作。
缺點:會出現誤報的情況(假如一個數據不在里面,可能會查出來說它在里面,但假如一個數據真的在里面,不會出現漏掉的情況,它一定會查找出來。)
布隆過濾器使用了多個哈希表還有bit位來進行存儲。
布隆過濾器(Bloom Filter)詳解 介紹了布隆過濾器還有三個公式。
一致性hash
一致性hash和虛擬節點都是為了解決:均衡負載而設計的。
傳統的hash然后求模的分流方式在進行增加和刪除的時候需要大規模的移動數據,一致性hash在增加和刪除節點時只需要移動少量數據。虛擬節點是為了解決各個節點負載不均衡的問題而設計的。
每天進步一點點——五分鍾理解一致性哈希算法(consistent hashing)
並查表
島問題
一個矩陣中只有0和1兩種值, 每個位置都可以和自己的上、 下、 左、 右四個位置相連, 如果有一片1連在一起, 這個部分叫做一個島, 求一個矩陣中有多少個島?
【思路】訪問過的島標記為2
【分布式島問題】假如要使用分布式的方式來進行解決,那么可以使用並查表來實現,但是這里的難點在於如何將單步得到的並查表何在一起。單步可以得到島的數目還有並查表的信息,比較邊界並查表的信息,假如兩個節點不在一個並查表,那么將他們合並,並且島的數目減1。
def get_island_num(island): col = len(island) row = len(island[0]) island_number = 0 for i in range(col): for j in range(row): if island[i][j] == 1: island_number += 1 find_same_island(island, i, j, col, row) return island_number def find_same_island(island, i, j, col, row): if(i< 0 or i >=col or j <0 or j >=row or island[i][j]!=1): return island[i][j] = 2 find_same_island(island, i+1, j, col, row) find_same_island(island, i-1, j, col, row) find_same_island(island, i, j+1, col, row) find_same_island(island, i, j-1, col, row) if __name__ == '__main__': map1 = [[ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 1, 1, 1, 0, 1, 1, 1, 0 ], [ 0, 1, 1, 1, 0, 0, 0, 1, 0 ], [ 0, 1, 1, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 1, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ]] map2 = [ [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 1, 1, 1, 1, 1, 1, 1, 0 ], [ 0, 1, 1, 1, 0, 0, 0, 1, 0 ], [ 0, 1, 1, 0, 0, 0, 1, 1, 0 ], [ 0, 0, 0, 0, 0, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 1, 1, 1, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ]]; print(get_island_num(map1)) print(get_island_num(map2))