版权声明:本文为作者的原创文章,未经允许不得转载。 https://blog.csdn.net/lin5165352/article/details/81565664
散列表(哈希表)
散列算法的作用是尽可能快的在数据结构中找到指定的值。
通常情况下我们需要遍历整个数据结构才能找到它。如果使用散列函数,就可以通过索引快速找到该值。类似于中华字典的目录一样。
最常见的散列函数就是将每个键值名的每个字母的ASCII值相加,当然汉字也有ASCII值,也适用该方法。
但是得到的值是一个非常大的数字(成千上万的数字),这样将导致生成一个非常大的数组。浪费大量的资源。
所以为了得到一个较小的数字,会使用hash值和一个任意数字做余运算。
hash = hash%number; 这会产生一个新的问题。导致很多数据的哈希值都一样。如number = 5,当输入任意6个数据的时候必定有两个值是重复的。而且这种冲突是该方法无法避免的。
解决散列表中的冲突
处理冲突有几种方式:
- 分离链接:该方法为每一个位置创建了一个链表。冲突的值会依次存储在链表中。
- 线性探索:如果该位置被占用则尝试下一个位置。
- 双散列法:
下面实现一下分离链接方法。方法中用到了前面的链表:LinkedList()类。
function HashTable() {
let table = [];
let ValuePair = function (key,value) {
this.key = key;
this.value = value;
this.toString = function () {
return '['+this.key+'-'+this.value+']';
}
};
let loseloseHashCode = function (key) {
let hash = 0;
for(let i=0;i<key.length;i++){
hash += key.charCodeAt(i);
}
return hash%5;
};
this.put = function (key, value) {
let position = loseloseHashCode(key);
//console.log(position+'-'+key+'-'+value);
if(table[position] === undefined){
table[position] = new LinkedList();
}
table[position].append(new ValuePair(key,value));
};
this.get = function (key) {
let position = loseloseHashCode(key);
if(table[position] !== undefined){
let current = table[position].getHead();
while (current.next){
if(current.element.key === key){
return current.element.value;
}
current = current.next;
}
if(current.element.key === key){
return current.element.value;
}
}
return undefined;
};
this.remove = function (key) {
let position = loseloseHashCode(key);
if(table[position] !== undefined){
let current = table[position].getHead();
while(current.next){
if(current.element.key === key){
table[position].remove(current.element);
if(table[position].isEmpty()){
table[position] = undefined;
}
return true;
}
current = current.next;
}
if(current.element.key === key){
table[position].remove(current.element);
if(table[position].isEmpty()){
table[position] = undefined;
}
return true;
}
}
return false;
};
this.print = function () {
for(let i = 0;i<table.length;++i){
if(table[i] !== undefined){
console.log(i+':'+table[i]);
}
}
};
this.clear = function () {
table = [];
}
}
let hash1 = new HashTable();
hash1.clear();
hash1.put('1','天安门广场');hash1.put('7','上地');
hash1.put('2','菜市口');hash1.put('12','昌平');
hash1.put('4','西街');hash1.put('8','王府井');
hash1.put('17','西二旗');
hash1.print();
console.log('查找1:'+hash1.get('1'));
console.log('删除1:'+hash1.remove('1'));
hash1.print();
console.log('----clear----');
hash1.clear();
hash1.put('2','西直门');
hash1.print();
打印结果:
线性探查
在很多语言中数组的大小是制定的,会出现数组用完的情况,所以该方法会有BUG,但在JavaScript中数组的大小是自动改变。不存在这个问题。
暂时不演示该方法。
网上有许多散列函数的方法,可以参考。