对JS散列表的简朴进修
HashTable类也叫HashMap类,是Dictionary类的一种散列表完成体式格局。
散列算法的作用是尽量快的在数据结构中找到一个值。
在之前的进修中,假如你想要取得数据结构中的一个值,须要遍历全部数据结构来找到它。假如运用散列函数,就可以晓得详细位置,也就可以够疾速找到该值。
运用最常见的散列函数–‘lose lose’散列函数,简朴的将每一个键值中的每一个字母的ASCII码值相加,将获得的散列值作为地点。
(键值)John (散列函数)74+111+104+110 (散列值)399 构成散列表
地点 | 数据键值对 |
---|---|
[399] | john/john@email.com |
… | |
[685] | gandalf/@email.com |
相干操作要领
建立一个散列表
function HashTable() {
var table = [];
}
完成一个散列函数,行将ASCII码值相加的要领。
var loseloseHashTable = function(key) {
var hash = 0;
for(var i = 0; i < key.length; i++) {
hash += key.charCodeAt(i);
}
return hash % 37; //这里只是为了获得比较小的数值,随意除了一个数
}
完成put(key, value)
要领,向散列表中增添一个新的项。
this.put = function (key, value) {
var position = loseloseHashTable(key); //获得散列值,即位置
table[position] = value;
};
完成get(key)
要领,返回依据键值检索到的特定的值。
this.get = function(key) {
var position = loseloseHashTable(key);
return table[position];
};
完成remove()
要领,从散列中移除键值对应的数据值。
this.remove = function(key) {
table[loseloseHashTable(key)] = undefined; //没有数据占有的位置默认值为undefined
};
详细运用要领这里就不赘述了,就是要领的挪用。
争执怎样办?
假如有多个键值获得的散列值相称,那末背面的元素会掩盖前面前面雷同散列值的元素,
怎样处理呢?
星散链接
星散链接法为散列表的每一个位置建立一个链表并将元素存储在里面。
地点 | 链表存储数据 |
---|---|
[5] | [no1/no1.com]指针-> [no2/no2.com]指针-> [X]null |
在地点5上,链表实例上有两个元素no1.com和no2.com。
须要增添一个valuePair类,来示意将要到场链表的实例的元素。
var valuePair = function(key, value) {
this.key = key;
this.value = value;
this.toString = function() {
return `[${this.key} - ${this.value}]`;
}
}
重写一个put()
要领
this.put = function(key, value) {
var position = loseloseHashTable(key);
if(table[position] == undefined) {
table[position] = new LinkedList(); //假如这个位置是第一次被到场元素,那末就初始化一个LinkedList实例
}
table[position].append(new valuePair(key, value)); //链表完成的append要领增添一个valuePair实例。
};
重写一个get(key)
要领
this.get = function(key) {
var position = loseloseHashTable(key);
if(table[position] !== undefined) { //位置上有元素存在
//遍历链表来寻觅键/值
var current = table[position].getHead();
while (current.next) { //这里遍历不到链表末了一个位置
if(current.element.key === key) {
return current.element.value; //element属性是valuePair的实例,包括key和value属性
}
current = current.next;
}
//搜检元素在链表第一个或许末了一个的状况
if(current.element.key === key) {
return current.element.value;
}
}
return undefined; //位置上没有值
};
重写remove(key)
要领
this.remove = function(key) {
var position = loseloseHashTable(key);
if(table[position] !== undefined) {
var current = table[position].getHead();
while (current.next) {
if(current.element.key === key) {
table[position].remove(current.element); //链表完成的remove要领
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;
}
线性探查
假如索引为index的位置已被占有了,就尝试index+1的位置,以此类推。
5的位置被占有,就寻觅6的位置,6的位置被占有,就找7,7没被占有就赋值(本应该在位置5上,然则线性探查变成了位置7)
完成put(key, value)
要领
this.put = function(key, value) {
var position = loseloseHashTable(key);
if(table[position] === undefined) { //这个位置没有被占有
table[position] = new valuePair(key, value);
} else {
var index = ++position; //寻觅下一个位置
while(table[index] !== undefined) { //被占有继承寻觅下一个位置
index ++;
}
table[index] = new valuePair(key, value);
}
};
完成get()
要领
this.get = function(key) {
var position = loseloseHashTable(key);
if(table[position] !== undefined) {
if(table[position].key === key) { //举例位置5
return table[position].value; //暗号1
} else {
var index = ++position;
while(table[index] !== undefined && (table[index] && table[index].key !== key)) { //该位置有元素然则不是要寻觅的元素
index ++; //索引增添
}
if(table[index] && table[index].key === key) { //确认正确性
return table[index].value; //找到7 //暗号2
}
}
}
return undefined;
};
完成remove()
要领
只须要转变get要领的暗号1和暗号2的位置代码即可
改成table[index] = undefined
;
更好的散列函数
var djb2HashCode = function(key) {
var hash = 5381; //初始化一个hash变量并赋值为一个质数5381
for(var i = 0; i < key.length; i++) { //遍历
hash = hash * 33 + key.charCodeAt(i);
}
return hash % 1013;
}
比拟来讲,争执会变少许多~