/* * 算法——散列 * 散列表是基於數組進行設計的。數組的長度是預先設定的 * 全部元素根據和該元素對應的鍵,保存在數組的特定位置,該鍵和咱們前面講到的字典中的鍵是相似的概念 * 使用散列表存儲數據時,經過一個散列函數將鍵映射爲一個數字,這個數字的範圍是 0 到散列表的長度。 * * 這裏所說的鍵 應該就是數組的索引 只不過 數組既然長度肯定了,那麼索引的個數也是肯定了 * 每一個元素是無限的,每一個元素的鍵值映射出來的索引也許就會發生重複或說碰撞。 這個叫有效碰撞。 * * 鍵值映射到數組的索引 這個過程是由散列函數來完成。 散列函數的選擇 要保證鍵值映射出來的索引是儘可能不重複的 * * simpleHash: 散列函數 * * put: 在散列中增長元素 * * showDistro: 展現散列中的元素 * */ function simpleHash(data) { var total = 0; for(var i = 0 ; i < data.length; i++) { total += data.charCodeAt(i); } return total % this.table.length; } function put(data) { var pos = this.simpleHash(data); this.table[pos] = data; } function showDistro() { for(var i = 0 ; i < this.table.length;i++) { if (this.table[i] !== undefined) { console.log(i + ":" +this.table[i]) } } } function HashTable() { this.table = new Array(137); this.buildChains = buildChains; this.simpleHash = simpleHash; this.put = put; this.showDistro = showDistro; } var someNames = ["David", "Jennifer", "Donnie", "Raymond", "Cynthia", "Mike", "Clayton", "Danny", "Jonathan"], h = new HashTable(); // h.buildChains(); //測試線性探測法 註釋掉 for (var i = 0; i< someNames.length;i++) { h.put(someNames[i]); } h.showDistro(); // 輸出:35: Cynthia 45: Clayton 57: Donnie 77: David 95: Danny 116: Mike 132: Jennifer 134: Jonathan //是輸出了8位少了一位? 記得上面的說明 散列函數可能會映射相同的索引出來 出現了有效碰撞。 //更好的散列函數 數組長度是質數 計算過程當中再乘以一個質數 //爲何要選擇一個質數呢? 質數特色:只有1 和 自己兩個因數 而合數 有兩個以上因數 若是除餘合數 那麼形成重複機會大 //由於合數有多個因子 好比 20 50%20 70%20 是同樣的 //感受這個質數不是特別靠譜 ^^ 下面有其它方法解決 function simpleHash(data) { const H = 5; var total = 0; for (var i = 0; i < data.length; ++i) { total += H * total + data.charCodeAt(i); } return total % this.table.length; } /*碰撞處理 * 一、開鏈法:開鏈法是指實現散列表的底層數組中,每一個數組元素又是一個新的數據結構,好比另外一個數組,這樣就能存儲多個鍵了 * 二、線性探測法 線性探測法檢查散列表中的下一個位置是否爲空。若是爲空,就將數據存入該位置;若是不爲空,則繼續檢查下一個位置,直到找到一個空的位置爲止 * */ /* * 兩個方法該如何選擇? * 當存儲數據使用的數組特別大時,選擇線性探測法要比開鏈法好。這裏有一個公式,經常 能夠幫助咱們選擇使用哪一種碰撞解決辦法:若是數組的大小是待存儲數據個數的 1.5 倍, 那麼使用開鏈法;若是數組的大小是待存儲數據的兩倍及兩倍以上時,那麼使用線性探 測法。 * */ /*下面這些方法是對上面的方法從新或新增*/ /*開鏈法*/ function buildChains() { for(var i = 0; i < this.table.length;i++) { this.table[i] = new Array(); } } // function showDistro() { // for(var i = 0 ; i < this.table.length;i++) { // if (this.table[i][0] !== undefined) { // console.log(i + ":" +this.table[i]) // } // } // } // function put(data) { // var pos = this.simpleHash(data); // this.table[pos].push(data); // } /*線性探測法*/ function put(data) { var pos = this.simpleHash(data); while (this.table[pos] !== undefined) { pos++; } this.table[pos] = data; }