字典
是以鍵值對形式存儲數據的數據結構,就像電話號碼薄裏的名字和電話號碼那樣的一一對應的關係。javascript
javascript
的Object
類就是以這樣的一種字典形式設計的。java
鍵值對在字典中以這樣的方式標記:d = {key1 : value1, key2 : value2 }。
字典中的鍵/值對是沒有順序的。若是你想要一個特定的順序,那麼你應該在使用前本身對它們排序。算法
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]); } }
咱們能夠定義一些在特定狀況下有用的輔助方法。好比要知道字典中的元素個數能夠定義一個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 table,也叫散列表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它經過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫作散列函數,存放記錄的數組叫作散列表。
哈希表的作法其實很簡單,就是把Key
經過一個固定的算法函數既所謂的哈希函數轉換成一個整型數字,而後就將該數字對數組長度進行取餘,取餘結果就看成數組的下標,將value存儲在以該數字爲下標的數組空間裏。
而當使用哈希表進行查詢的時候,就是再次使用哈希函數將key
轉換爲對應的數組下標,並定位到該空間獲取value
,如此一來,就能夠充分利用到數組的定位性能進行數據定位
當存儲記錄時,經過散列函數計算出記錄的散列地址 當查找記錄時,咱們經過一樣的是散列函數計算記錄的散列地址,並按此散列地址訪問該記錄
在js
中,散列函數會將每一個鍵值映射爲一個惟一的數組索引。然而,鍵的數量是無限的,數組的長度是有限的,因此,應該讓散列函數儘可能將鍵均勻地映射到數組中。
哈希表也是種數據結構,它能夠提供快速的插入操做和查找操做。哈希表運算速度極快,哈希表的速度明顯比樹快,樹的操做一般須要O(N)的時間級。哈希表不只速度快,編程實現也相對容易。
哈希表最多見的例子是以學生學號爲關鍵字的成績表,1號學生的記錄位置在第一條,10號學生的記錄位置在第10條...
若是咱們以學生姓名爲關鍵字,如何創建查找表,使得根據姓名能夠直接找到相應記錄呢?
用上述獲得的數值做爲對應記錄在表中的位置,獲得下表:
上面這張表即哈希表。
若是未來要查李秋梅的成績,能夠用上述方法求出該記錄所在位置:
李秋梅:lqm 12+17+13=42
取表中第42條記錄便可。
咱們使用一個類來表示散列表,該類包含計算散列值的方法、向散列中插入數據的方法、從散列表中讀取數據的方法、顯示散列表中數據分佈的方法等。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()
函數經過使用js
的charCodeAt()
函數,返回每一個字符的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)]; }