Input計算哈希值後的結果都很大,可是若是把他們都與m取餘,那麼就在一個0-m-1的這個域(hashmap就是這樣找下標的)。若是在S域上是均勻分佈的,那麼在mod上0~m-1也是均勻分佈的。前端
先將一個hash結果拆分兩個(高8位,低8位,是相互獨立的)獲得兩個h1,h2,而後組合,如h1+i*h2 獲得1000個哈希函數。java
注意每一個下標的鏈表是均勻往下漲的,哈希函數第五點性質
哈希表擴容(能夠認爲擴容代價爲O(1),由於優化技巧不少,實際數學上不是):面試
Java中是怎麼實現的呢?
一個桶,桶裏放的是什麼?不是鏈表而是紅黑樹treemap。是個平衡搜索二叉樹。數組
技巧:哈希函數作分流(利用哈希函數相同輸入相同輸出,不一樣輸入均勻分佈的性質)
題目:假設有一個大文件(好比100T),大文件裏每行是個字符串,可是是無序的,把全部重複的字符串打印出來。
假設有1000臺機器,標號,0-999臺機器。大文件存儲在一個分佈式文件上,按行讀取字符串 計算哈希值,mod1000,而後分到1000臺機器,相同的文本必定會分到一臺機器上(相同hash輸入,獲得的結果必定是同樣的)。服務器
題目:設計randomPool結構
題目內容:設計一種結構,在該結構中有以下三個功能:
insert(key):將某個key加入到該結構,作到不重複加入
delete(key):將本來在結構中的某個key移除,
getRandom():等機率隨機返回結構中的任何一個key
要求:三個方法的時間複雜度都是O(1)負載均衡
解法:準備兩張hash表(一張hash表沒法作到嚴格等機率隨機返回一個)dom
HashMap<String,Integer> keyIndexMap = new HashMap<String, Integer>(); HashMap<Integer,String> indexKeyMap = new HashMap<Integer, String>();
作法:
A 第0個進入hash表 , 表A key A value 0 表B key 0 value A
B 第1個進入hash表 , 表A key B value 1 表B key 1 value B
insert(key)代碼實現:分佈式
public void insert(String key){ if(keyIndexMap.containsKey(key)){ return; }else{ keyIndexMap.put(key,number); indexKeyMap.put(number,key); number++; } }
利用math的random函數,隨機從size取一個數字,在哈希表2取對應數字的key,就是隨機等機率的
getRandom()代碼實現:函數
public String getRandom(){ if(size ==0){ return null; } int index = (int)(Math.random()*size); return map2.get(index); }
若是要remove呢?
直接remove會出現問題:刪除key對應要刪除某個index,那麼就會產生「洞」,調用getRandom就一次調用獲得等機率結果。
那麼該如何去刪呢?
如假設有1000個key,要刪除str17,那麼找到index17, 把str999在keyIndexMap的index變爲17,map2的17改成str999,刪除index999的洞,即產生洞的時候刪除最後一條,再刪除函數須要刪除的key。經過交換最後一行數據保證index是連續的。大數據
public void delete(String key){ if(keyIndexMap.containsKey(key)){ Integer deleteIndex = keyIndexMap.get(key); int lastIndex = --number; String lastKey = indexKeyMap.get(lastIndex); indexKeyMap.put(deleteIndex,lastKey); keyIndexMap.put(lastKey,deleteIndex); keyIndexMap.remove(key); indexKeyMap.remove(number); } }
解決的問題:爬蟲去重問題。
黑名單問題(100億個url,每一個url64字節,當用戶搜索某個url的時候,過濾。屬於黑名單返回true,不屬於返回false;用哈希表hashset作的話那麼至少要6400億字節,實際還不止!640G放到內存耗費巨大代價;也能夠用哈希分流給多個機器作,可是須要的機器較多)
布隆過濾器可能 存在較低失誤率:可能會把清白的判斷爲黑名單,可是隻要是黑名單,必會判斷爲黑名單。
所以,若是面試官問這種問題:能夠先用哈希分流的方法回答,再則問面試官是否容許較低失誤率?若是容許的話,採用布隆過濾器。
布隆過濾器:比特數組
如 int[] arr = new int[1000]; 那麼就有32000比特(int 4個字節 32位)
怎麼給某個位的比特抹黑?
int index = 30000; //要描黑的位置 int intIndex = index/32; //找打數組的下標 int bitIndex = index%32; //下標對應元素的哪一個位置應該被描黑 arr[intIndex] = (arr[intIndex] | (1<<bitIndex)); //描黑操做
黑名單應該怎麼設計?
思路:url -> 計算哈希值,%m,獲得的結果能夠對應到0~m-1的位置,算到的地方描黑;
此時並非布隆過濾器。
準備hash1,hash2,…,hashk 個哈希函數描黑(可能多個hash函數會到同一個位置,url描黑意味着這個url進到這個布隆過濾器)
比特數組應該儘量大一些,否則小了一下就數組全描黑了
利用布隆過濾器判斷:來一個url,就在這k個hash函數獲得K個位置,若是都是黑的,就是在黑名單,若有一個不是,就不在黑名單內。
解釋:若是url曾經進過,確定都是黑的。有一個位置不是黑的,那確定沒進過,就是白的。
失誤緣由:
數組空間越大,失誤率越低。
哈希函數好處:數組空間開多大與單樣本的大小無關,而和url的樣本個數有關。
幾乎集羣都用到這個,須要抗壓服務器(牽扯,服務器設計,負載均衡)
服務器如何進行抗壓的呢?
如前端要存儲
作法:存儲的數據,計算哈希值%後臺服務器數,而後存到對應機器
前端計算分配到後臺服務器的數目會巨均衡。
問題:當想要加機器和減機器就出現問題了,由於%的服務器數目變了。
解決方法:經過一致性哈希就能解決問題,遷移成本低
經過機器的IP或者MAC來計算哈希的位置,劃分哈希值的環(把整個哈希結果想象成一個環)來管理。
存在問題:機器少的時候,不能均分這個哈希的環。有可能只有兩個機器的狀況,兩個機器很近,負載很不均勻!
解決方法:虛擬節點技術
m - 1(分配1000個虛擬節點):m - 1 - 1, m-1-2,m-1-3,m-1-4,.. m - 2:m-2-1,m-2-3,m-2-3,… m - 3… 用這3000個虛擬節點搶這個環。搶到的給對應機器處理。這樣就比較均勻了。幾乎均分這個環。