【JS数据结构与算法】实现哈希函数

目录

一、优秀的哈希函数

1、幂的连乘

2、霍纳法则(秦九韶算法)

3、如何做到均匀分布。

二、实现哈希函数


一、优秀的哈希函数

在构造哈希表之前,我们需要一个哈希函数对数据进行哈希化。

那这个哈希函数怎么实现呢,根据前面一篇博客【JS数据结构】认识哈希表,我们已经认识了什么是哈希表以及为什么需要设计一个哈希函数。

其实就是要达到两个目的:

  • 能够快速地计算,快速地获取hashCode
  • 让元素在哈希表中分布均匀。

1、幂的连乘

前面谈到的数据存储,一种方法是使用幂的连乘获取hashCode

give = 7 * 27^3 + 9 * 27^2 + 22 * 27 + 5 = 144941

采用这种方式,其实就是一个多项式,可化为:

这里相乘的次数为:n + (n - 1) + ... + 1 = n(n + 1) / 2次

相加的次数为: N次。

得到的时间复杂度为(N^2 + N)/ 2    即O(N^2)

2、霍纳法则(秦九韶算法)

霍纳法则是对多项式的优化,让相乘的次数变少,从而快速获取hashCode,化为以下形式:

以give为例

这里相乘的次数为:N次;

相加的次数为: N次。

得到的时间复杂度为(N + N)   即O(N)

所以使用霍纳法则可以大大地提高效率,减少计算时间。

3、如何做到均匀分布。

在设计哈希表时,我们已经有了两种处理映射到相同下标值的办法,即可以解决冲突,一种是链地址法,另一种是开放地址法。

不管是哪种方法,我们最好让数据在哈希表中分布均匀

所以我们在使用常量的时候,要使用质数

1、哈希表的长度

2、N次幂的底数(常使用37)。

质数很重要,假设表长为10(下标值为0~9)

一个特定的关键字映射到下标值为0的位置,步长为5,那么探索的序列就会是0-5-0-5...一直循环下去。

如果表长为11,那么探索的序列为:0-5-10-4-9-3-8-2-7-1-6,这样的话就不会产生循环并且可以让数据在哈希表中分布均匀。

二、实现哈希函数

 设计一个哈希函数
    1、将字符串转换成一个比较大的数字,即得hashCode。
    2、将这个大的数字hashCode压缩成数组大小的范围之内。

需要传入两个参数,一个是字符串,一个是哈希表的长度。

function hashFunc(str, size){

      //定义一个变量来存储hashCode
      var hashCode = 0;

      // 利用霍纳法则计算出hashCode的值
      // give -> Unicode编码
      for (var i = 0; i < str.length; i++) {
        hashCode = 37 * hashCode + str.charCodeAt(i); 
      }

      // 利用hashCode与哈希表的长度取余得到下标值
      var index = hashCode % size;

      return index;
}

测试代码:

    //测试
    alert(hashFunc('abc', 7)); // 4
    alert(hashFunc('cla', 7)); // 2
    alert(hashFunc('nbr', 7)); // 1
    alert(hashFunc('kba', 7)); // 0

总结:优秀的哈希函数是尽可能地快速将数据映射到不同的位置上。

猜你喜欢

转载自blog.csdn.net/weixin_42339197/article/details/99544523