算法----散列

Posted yunnex-xw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法----散列相关的知识,希望对你有一定的参考价值。

/*
* 算法——散列
* 散列表是基于数组进行设计的。数组的长度是预先设定的
* 所有元素根据和该元素对应的键,保存在数组的特定位置,该键和我们前面讲到的字典中的键是类似的概念
* 使用散列表存储数据时,通过一个散列函数将键映射为一个数字,这个数字的范围是 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;
}

 

以上是关于算法----散列的主要内容,如果未能解决你的问题,请参考以下文章

单向散列算法的常见算法

挑战程序设计竞赛(算法和数据结构)——5.4 散列法习题Java代码实现

了解散列算法的位和字节

什么是安全散列算法SHA256

hash算法散列算法

MD5散列算法原理及实现