js數據結構和算法(五)字典和散列(hash)

什麼是字典結構?

字典是以鍵值對形式存儲數據的數據結構,就像電話號碼薄裏的名字和電話號碼那樣的一一對應的關係。javascript

javascriptObject類就是以這樣的一種字典形式設計的。java

鍵值對在字典中以這樣的方式標記:d = {key1 : value1, key2 : value2 }。字典中的鍵/值對是沒有順序的。若是你想要一個特定的順序,那麼你應該在使用前本身對它們排序。算法

Dictionary類

Dictionary類的基礎是Array類,而不是Object類。咱們想對字典中的鍵排序,而在js中是不能對 對象 的屬性進行排序的。話雖如此,但在js中一切皆對象,數組也是對象。如下面的代碼開始定義Dictionary類:編程

<script type="text/javascript">
     function Dictionary(){
         this.datastore = new Array();
     }
</script>

先來定義add()方法。該方法接受兩個參數:鍵和值。鍵是值在字典中的索引,代碼以下:數組

function add(key,value){
        this.datastore[key] = value;
}

接下來定義find()方法,該方法以 作爲參數,返回和其關聯的值。代碼以下:數據結構

function find(key){
         return this.datastore[key];
     }

從字典中刪除鍵-值對 須要使用js中的delete函數。該函數是Object類的一部分,該函數同時刪掉鍵和與其關聯的值:dom

function remove(key){
         delete  this.datastore[key];
     }

最後,咱們但願能夠顯示字典中全部的鍵-值對,可使用以下的方法:函數

function showAll(){
         for(var key in Object.keys(this.datastore)){
             print(key + "->" + this.datastore[key]);
         }
     }

Dictionary類的輔助方法

咱們能夠定義一些在特定狀況下有用的輔助方法。好比要知道字典中的元素個數能夠定義一個count()方法,代碼以下:性能

function count(){
         var n=0;
         for(var key in Object.keys(this.datastore)){
             ++n;
         }
         return n;
     }

爲何不使用length屬性?這是由於當鍵的類型爲字符串時,length屬性就無論用了this

還能夠定義一個clear清除方法:

function clear(){
         for each(var key in Object.keys(this.datastore)){
             delete  this.datastore[key];
         }
     }

備註:

for each in(IE6,7,8不支持)沒法得到對象的屬性名,只能獲取到屬性值。
另外,遍歷對象也儘可能使用for in 而不是for each,而遍歷數組的話仍是使用for循環吧

for each in沒法得到對象的屬性名,只能獲取到屬性值。

散列(hash)

什麼是哈希表?

哈希表(Hash table,也叫散列表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它經過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫作散列函數,存放記錄的數組叫作散列表。

  哈希表的作法其實很簡單,就是把Key經過一個固定的算法函數既所謂的哈希函數轉換成一個整型數字,而後就將該數字對數組長度進行取餘,取餘結果就看成數組的下標,將value存儲在以該數字爲下標的數組空間裏。

  而當使用哈希表進行查詢的時候,就是再次使用哈希函數將key轉換爲對應的數組下標,並定位到該空間獲取value,如此一來,就能夠充分利用到數組的定位性能進行數據定位

散列表的查找步驟

當存儲記錄時,經過散列函數計算出記錄的散列地址

當查找記錄時,咱們經過一樣的是散列函數計算記錄的散列地址,並按此散列地址訪問該記錄

js中,散列函數會將每一個鍵值映射爲一個惟一的數組索引。然而,鍵的數量是無限的,數組的長度是有限的,因此,應該讓散列函數儘可能將鍵均勻地映射到數組中。

哈希表也是種數據結構,它能夠提供快速的插入操做和查找操做。哈希表運算速度極快,哈希表的速度明顯比樹快,樹的操做一般須要O(N)的時間級。哈希表不只速度快,編程實現也相對容易。

哈希表算法

哈希表最多見的例子是以學生學號爲關鍵字的成績表,1號學生的記錄位置在第一條,10號學生的記錄位置在第10條...

若是咱們以學生姓名爲關鍵字,如何創建查找表,使得根據姓名能夠直接找到相應記錄呢?

哈希表算法

用上述獲得的數值做爲對應記錄在表中的位置,獲得下表:
圖片描述
上面這張表即哈希表。

若是未來要查李秋梅的成績,能夠用上述方法求出該記錄所在位置:

李秋梅:lqm 12+17+13=42 取表中第42條記錄便可。

HashTable類

咱們使用一個類來表示散列表,該類包含計算散列值的方法、向散列中插入數據的方法、從散列表中讀取數據的方法、顯示散列表中數據分佈的方法等。
HashTable類的構造函數定義以下:

function HashTable(){
         this.table = new Array(137);//設定數組長度爲137,質數
         this.simpleHash = simpleHash;
         this.showDistro = showDistro;
         this.put = put;
     }

散列函數的選擇依賴於鍵值的數據類型。若是鍵是整形,最簡單的散列函數就是以數組的長度對鍵取餘。

使用一個簡單的散列函數作散列:

load("HashTable.js");
    var someNames = ['David','Jennifer','Donnie','Raymond','Cynthia','Mike','Clayton','Danny','Jonathan'];
    var hTable = new HashTable();
    for(var i = 0;i < someNames.length;i++){
        hTable.put(someNames[i]);
    }
    hTable.showDistro();

輸出以下:

35:Cynthia
45:Clayton
57:Donnie
77:David
95:Danny
116:Mike
132:Jennifer
134:Jonathan

simpleHash()函數經過使用jscharCodeAt()函數,返回每一個字符的ASCII碼值,而後再將它們相加獲得散列值。put方法經過調用simpleHash()函數獲得數組的索引,而後將數據存儲到該索引對應的位置上。

一個更好的散列函數

爲了不碰撞,首先要確保散列表中用來存儲數據的數組其大小是個質數,這和計算散列值時使用的取餘運算有關。數組的長度應該在100以上,這是爲了讓數據在散列表中分佈得更均勻

散列化整型鍵

這裏咱們使用一個展現學生成績的數據集,將隨機產生一個9位數的鍵,用以識別學生身份和一門成績,下面是產生學生數據(包含ID和成績)的函數:

function getRandomInt(min,max){
    return Math.floor(Math.random()*(max-min+1))+min;
}
function genStuData(arr){
    for(var i = 0;i<arr.length;++i){
        var num = '';
        for(var j = 1;j<=9;++j){
            num += Math.floor(Math.random()*10);
        }
        num += getRandomInt(50,100);
        arr[i] = num;
    }
}

使用getRandomInt()函數時,能夠指定隨機數的最值。genStuData()函數生成學生的數據。裏層的循環用來生成學生的ID,緊跟在循環後面的代碼生成一個隨機的成績,並把成績弄在ID的後面。主程序會把ID和成績分離。散列函數將學生ID裏的數字相加,使用simpleHash()函數計算出散列值。

對散列表排序

put方法同時接受鍵和數據做爲參數,對鍵值散列後,將數據存儲到散列表中:

function put(key,data){
    var pos = this.betterHash(key);
    this.table[pos] = data;
}

put方法將鍵值散列化後,將數據存儲到散列化後的鍵值對應在數組中的位置上。

從散列表中取值

定義get()方法,用以讀取存儲在散列表中的數據。該方法一樣須要對鍵值進行散列化,而後才能知道數據存儲在數組的什麼位置,代碼以下:

function get(key){
    return this.table[this.betterHash(key)];
}
相關文章
相關標籤/搜索