/*
* 算法——散列
* 散列表是基于数组进行设计的。数组的长度是预先设定的
* 所有元素根据和该元素对应的键,保存在数组的特定位置,该键和我们前面讲到的字典中的键是类似的概念
* 使用散列表存储数据时,通过一个散列函数将键映射为一个数字,这个数字的范围是 0 到散列表的长度。
*
* 这里所说的键 应该就是数组的索引 只不过 数组既然长度确定了,那么索引的个数也是确定了
* 每个元素是无限的,每个元素的键值映射出来的索引也许就会发生重复或说碰撞。 这个叫有效碰撞。
*
* 键值映射到数组的索引 这个过程是由散列函数来完成。 散列函数的选择 要保证键值映射出来的索引是尽量不重复的
*
* simpleHash: 散列函数
*
* put: 在散列中增加元素
*
* showDistro: 展示散列中的元素
* */
function simpleHash(data) {
var total = 0;
for(var i = 0 ; i < data.length; i++) {
total += data.charCodeAt(i);
}
return total % this.table.length;
}
function put(data) {
var pos = this.simpleHash(data);
this.table[pos] = data;
}
function showDistro() {
for(var i = 0 ; i < this.table.length;i++) {
if (this.table[i] !== undefined) {
console.log(i + ":" +this.table[i])
}
}
}
function HashTable() {
this.table = new Array(137);
this.buildChains = buildChains;
this.simpleHash = simpleHash;
this.put = put;
this.showDistro = showDistro;
}
var someNames = ["David", "Jennifer", "Donnie", "Raymond",
"Cynthia", "Mike", "Clayton", "Danny", "Jonathan"],
h = new HashTable();
// h.buildChains(); //测试线性探测法 注释掉
for (var i = 0; i< someNames.length;i++) {
h.put(someNames[i]);
}
h.showDistro(); // 输出:35: Cynthia 45: Clayton 57: Donnie 77: David 95: Danny 116: Mike 132: Jennifer 134: Jonathan
//是输出了8位少了一位? 记得上面的说明 散列函数可能会映射相同的索引出来 出现了有效碰撞。
//更好的散列函数 数组长度是质数 计算过程中再乘以一个质数
//为什么要选择一个质数呢? 质数特点:只有1 和 本身两个因数 而合数 有两个以上因数 如果除余合数 那么造成重复机会大
//因为合数有多个因子 比如 20 50%20 70%20 是一样的
//感觉这个质数不是特别靠谱 ^^ 下面有其它方法解决
function simpleHash(data) {
const H = 5;
var total = 0;
for (var i = 0; i < data.length; ++i) {
total += H * total + data.charCodeAt(i);
}
return total % this.table.length;
}
/*碰撞处理
* 1、开链法:开链法是指实现散列表的底层数组中,每个数组元素又是一个新的数据结构,比如另一个数组,这样就能存储多个键了
* 2、线性探测法 线性探测法检查散列表中的下一个位置是否为空。如果为空,就将数据存入该位置;如果不为空,则继续检查下一个位置,直到找到一个空的位置为止
* */
/*
* 两个方法该如何选择?
* 当存储数据使用的数组特别大时,选择线性探测法要比开链法好。这里有一个公式,常常
可以帮助我们选择使用哪种碰撞解决办法:如果数组的大小是待存储数据个数的 1.5 倍,
那么使用开链法;如果数组的大小是待存储数据的两倍及两倍以上时,那么使用线性探
测法。
* */
/*下面这些方法是对上面的方法重新或新增*/
/*开链法*/
function buildChains() {
for(var i = 0; i < this.table.length;i++) {
this.table[i] = new Array();
}
}
// function showDistro() {
// for(var i = 0 ; i < this.table.length;i++) {
// if (this.table[i][0] !== undefined) {
// console.log(i + ":" +this.table[i])
// }
// }
// }
// function put(data) {
// var pos = this.simpleHash(data);
// this.table[pos].push(data);
// }
/*线性探测法*/
function put(data) {
var pos = this.simpleHash(data);
while (this.table[pos] !== undefined) {
pos++;
}
this.table[pos] = data;
}