1.散列函数的作用:
尽可能快的在一个数据结构中找到一个值
2.常见的散列函数:
loselose 函数:简单的将每个键值中的每个字母的ASII码相加,然后再对37取余
简单实现:
// 未解决hash冲突的hash表
var HashTable = function () {
var items = [];
this.has = function (key) {
return key in items;
},
//获取元素的hash地址、
this.loseloseHashCode = function (key) {
var hash = 0,
i = 0;
for(;i< key.length;i++){
hash += key[i].charCodeAt();
}
return hash%37;
},
//加入元素
this.put = function (key,value) {
var position = this.loseloseHashCode(key);
if(!this.has(key)){
items[position] = value;
return true;
}
return false;
},
//获得元素
this.get = function (key) {
var position = this.loseloseHashCode(key);
return items[position];
},
this.values = function () {
return items;
}
this.clear = function () {
items = [];
}
}
2.1.解决哈希冲突
哈希冲突不同的值再散列表中对应相同的位置
2.1.1分离链接解决哈希冲突
思想:它为在散列表相同位置的元素创建一个链表,将元素存储在里面,因此还需要一个辅助的数据结构---链表
代码实现:
//分离链接解决hash冲突
/*
* 分离链接法主要思想:将hash冲突的数据用链表链接起来
* */
//链表结构:
var LinkList = function () {
var items = [];
var Node = function (element) {
this.element = element;
this.next = null;
};
var length = 0;
var head = null;
this.append = function (element) {
var node = new Node(element),
cur = head;
if(cur === null){
head = node;
}else{
while(cur.next!= null){
cur=cur.next;
}
cur.next = node;
}
length++;
},
//删除某个位置下的元素,下标从1开始
this.removeAt = function (position) {
var cur = head,
pre=null,
index = 1;
if(position ===1){
head = cur.next;
length--;
return cur.element;
}
if(position>1&&position<length){
while(index < position&&cur.next!=null){
pre = cur;
cur = cur.next;
index++;
}
pre.next = cur.next;
length--;
return cur.element;
}
return false;
},
this.remove = function (element) {
return this.removeAt(this.indexOf(element));
},
this.insert = function (element,position) {
var index = 0,
cur = head,
pre = null,
node = new Node(element);
if(position ===1){
head = node;
head.next = cur;
length++;
return true;
}
if(position>1 && position<=length){
while(cur.next!=null&&index<=position){
pre = cur;
cur = cur.next;
index++;
}
pre.next = node;
node.next =cur;
length++;
return true;
}
return false;
},
this.indexOf = function (elememt) {
var cur = head,
index = 1;
while(cur.next!=null){
if(cur.element === elememt){
return index;
}
index++;
cur=cur.next;
}
return index;
},
this.getHead = function () {
return head;
},
this.size = function () {
return length;
},
this.isEmpty = function () {
return items.length?true:false;
}
};
var HashTable_L = function () {
var tables = [];
var Node1 = function (key,val) {
this.key = key;
this.val = val;
};
//找到元素的hash地址
this.loseloseHashCode = function (key) {
var hash = 0,
i = 0,
l = key.length;
for(; i< l; i++){
hash += key[i].charCodeAt();
}
return hash%37;
}
this.has = function (key) {
return key in tables;
}
//放入元素
this.put = function (key,val) {
var position = this.loseloseHashCode(key);
if(tables[position] === undefined){
tables[position] = new LinkList();
}
tables[position].append(new Node1(key,val));
// console.log(tables[position].getHead());
}
//获取元素
this.get =function (key) {
var position = this.loseloseHashCode(key);
if (tables[position] !== undefined){
var cur = tables[position].getHead();
while (cur.next!=null) {
if (cur.element.key === key){
return cur.element.val;
}
cur = cur.next;
}
//对于第一项和最后一项的判断
if (cur.element.key === key){
return cur.element.val;
}
}
return false;
}
//删除元素
this.remove = function (key) {
var position = this.loseloseHashCode(key);
if(tables[position]!==undefined){
var cur = tables[position].getHead();
while (cur.next!=null){
if(cur.element.key === key){
tables[position].remove(cur.element);
if(tables[position].isEmpty()){
tables[position] = undefined;
}
return true;
}
cur = cur.next;
}
//判断最后一个和第一个元素
if(cur.element.key === key){
tables[position].remove(cur.element);
return true;
}
}
return false;
}
this.values = function () {
return tables;
}
};
2.1.2线性探测法解决哈希冲突
主要思想:当想往散列表中加入一个元素时,如果该位置被占了就放入它的下一个位置,如果它的下一个位置也被占了,就放入下下一个。
代码实现:
//线性探查法解决hash冲突
var HashTable_X = function () {
//数据的存储结构
var Node = function (key,val) {
this.key = key;
this.val = val;
this.toString = function () {
return this.key+', '+this.val;
}
}
var tables = [];//线性表;
this.loseloseHashCode = function (key) {
var hash = 0,
i = 0,
l = key.length;
for(; i<l; i++){
hash += key[i].charCodeAt();
}
return hash%37;
}
//put方法
this.put = function (key,val) {
var position = this.loseloseHashCode(key);
console.log('为解决冲突的hash地址',position);
// if(tables[position] === undefined){
// tables[position] = new Node(key,val);
// }else{
// while(tables[position] !== undefined){
// position++;
// }
// tables[position] = new Node(key,val);
// }
if(tables[position] !== undefined){
while(tables[position]!==undefined){
position++;
}
}
console.log(key,position);
tables[position] = new Node(key,val);
}
//get方法思想:首先找到需要查询元素的位置,通过比较key,然后返回查找的元素的val
this.get = function (key) {
var position = this.loseloseHashCode(key);
if(tables[position]!== undefined){
if(tables[position].key === key){
return tables[position].val;
}else {
var index = ++position;
while(tables[index].key!==key || tables[index]===undefined){
index++;
}
if(tables[index].key === key){
return tables[index].val;
}
}
}
return undefined;
}
//思想与get一样,只是找到之后将这个位置的元素设置为undefined
this.remove = function (key) {
var position = this.loseloseHashCode(key);
if(tables[position]!== undefined){
if(tables[position].key === key){
tables[position] = undefined;
}else{
var index = ++position;
while(tables[index].key !== key || tables[index] === undefined){
index++;
}
if(tables[index].key === key){
tables[index] = undefined;
}
}
}
}
this.values = function () {
return tables;
}
}
3.djb2HashCode解决哈希冲突
djb2:一个简单产生简单随机分布的哈希函数
1.为什么选择33:
1)乘法易于移位或相加
2) 从移位和加法实现中可以看到,使用33可以复制散列累加器中的大多数输入位,
然后将这些位相对地分散开来。这有助于形成好的雪崩现象。使用较大的移位将复制更少的位,
使用较小的移位将使位交互更局部,并使交互扩展所需的时间更长。
3) 32 = 2^5,32 与移 5 位相关,有助于将每一个字符串的每一位比特都作用到最终的哈希值当中
4) 在考虑ASCII字符数据时,5的移位是一个很好的移位量。ASCII字符可以看作是4位字符类型选择器和4位字符
类型选择器。前4位的数字都是0x3。因此,8位移位将导致具有特定含义的位与具有相同含义的其他位相互作用。
4位或2位的移位同样会在相似的位之间产生强烈的交互作用。5位的移位使得一个字符的4个低阶位中的许多位与
同一字符的4个上位中的许多强相互作用
选择5381并不太重要,很多其他的大的质数数也可以运行地很好。
代码实现:
var HashTable = function () {
var tables = [];
this.has = function (key) {
return key in tables;
}
this.djb2HashCode =function (key) {
var hash = 5381,//选择5381并不太重要,很多其他的大的质数数也可以运行地很好。
i = 0,
l = key.length;
for(;i<l;i++){
hash = hash*33+key[i].charCodeAt();
}
return hash%1013;
}
this.put = function (key,val) {
var position = this.djb2HashCode(key);
tables[position] = val;
}
this.remove = function (key) {
var position = this.djb2HashCode(key);
tables[position] = undefined;
}
this.get = function (key) {
var position = this.djb2HashCode(key);
return tables[position];
}
this.values = function () {
return tables;
}
}