散列表 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取余
};