散列表 HashTable
通過鍵值對儲存的一種數據結構(key,value),通過鍵值(key)查找(value)。只查找一次,不需要n次遍歷。查找時間爲一個常量,即數據量的大小不會影響查找速度。
平均查找時間爲O(1),對比二分法的查找時間爲O(logn),線性查找爲O(n)要快很多。
最壞情況查找時間情況下查找時間爲線性時間O(n)。
數據增減和查找性能一致。也爲O(1),O(n)。
性能受到以下因素影響:
- 裝填因子:已裝填的數據/總容量,也就是空餘位置越多,發生衝突可能性越小,性能越好。
- 良好的散列函數 : 讓數組中的值成均勻分佈。儘量不要扎堆。
JS中的散列表
直接創建
最快的實現方式是直接創建對應格式
var a = new Array(); // or just []
a[0] = 0;
a['one'] = 1;
a['two'] = 2;
a['three'] = 3;
for (var k in a) {
if (a.hasOwnProperty(k)) {
console.log('key is: ' + k + ', value is: ' + a[k]);
<!-- key is: 0, value is: 0
key is: one, value is: 1 ... -->
}
}
console.log(a.length); //1
但是這樣有一問題,通過a.length
可發現只有對數字的key有效,對string的key無效。
就是說a.length
只計算了a[0]。因爲js會在創建對象時,把key分爲數字number a[0]
或成員 memeber a['one']
。
而在計算長度時也就是indexed key,會忽略string的key。
自建HashTable
創建數組保存 var tabe = []
利用transHashCode
把key轉換成數字=每個字母的ASCII碼值相加的除以37的餘數
假設目標key是Jack,那麼transHashCode(Jack)
=5,增刪查(put,get,remove)的目標就是table[5]
默認基本散列,但是沒有考慮hash值重複。
function HashTable() {
var table = [];
var transHashCode = function (key) {
var hash = 0;
for (var i = 0; i < key.length; i++) {
hash += key.charCodeAt(i);
}
return hash % 37;
};
this.put = function(key, value) {
var position = loseloseHashCode(key);
table[position] = value;
};
this.get = function (key) {
return table[loseloseHashCode(key)];
};
this.remove = function(key) {
table[loseloseHashCode(key)] = undefined;
};
}
當兩個key的HASH值相等時,需要解決衝突。目前常用有 連接:
- 分離連接:在散列表每一個位置創建鏈表,也就是多個HASH值相等的key在同一個散列表位置下的不同鏈表。這樣的問題是長度很難保持均衡。
- 分離連接:出現重複後,通過位置+1的方式,排到後面位置。
- 增加transHashCode的複雜度,來減少出現相同的情況。
比如:
var djb2HashCode = function (key) {
var hash = 5381; // 一個較大的素數基準值
for (var i = 0; i < key.length; i++) {
hash = hash * 33 + key.charCodeAt(i); // 基準值乘以33再加ASCII碼值
}
return hash % 1013; //除以1013取餘
};