zoukankan      html  css  js  c++  java
  • JavaScript数据结构 --- 散列

    JavaScript数据结构 --- 散列

    散列是一种常用的数据存储技术,散列后的数据可以快速地插入或取用,但查找操作却效率低下,这是可以依靠其他数据结构(例如二叉查找树)。

    散列使用的数据结构叫散列表,这里的散列表是基于数组进行设计的。所有元素根据该元素对应的(类型字典中的键),保存在数组的特定位置。使用散列表存储数据时,通过一个散列函数 将键映射为一个长度为 0 到散列表长度的数字。

    一般来说,数组的长度是有限的,所以我们让散列函数尽量将键均匀地映射到数组中。
    HashTable


    1. HashTable 类
    使用一个类来表示散列表。

    
    function HashTable() {
       this.table = new Array(137); // 构建一个新数组用来存储 散列表
       this.simpleHash = simpleHash; // 一个简单的散列函数
       this.showDistro = showDistro; // 显示散列表中的数据
       this.put = put; // 将数据插入散列表
    }
    

    1.1 选择散列函数
    散列函数的选择依赖键值的数据类型。如果键是整形,最简单的散列函数就是以数组的长度对键取余。当很多键值是数组的长度的倍数时,这种方式会导致大规模碰撞(散列值一样)。所以一般将数组的长度设为质数。

    针对字符串类型的散列函数比较困难,要更加小心选择。

    我们定义的 smpleHash 函数是将每个字符的 ASCII 码相加。如此散列值就是 ASCII 码值之和除以数组长度得到的余数。

    function simpleHash(data) {
       var total = 0;
       for (var i = 0; i < data.length; i++) {
          total += data.charCodeAt(i);
       }
       return total % this.table.length;
    }
    

    再定义用来将数据存入散列表的方法 put() 和用来显示散列表中的数据的方法 showDistro() 。

    function showDistro() {
       var n = 0;
       for (var i = 0; i < this.table.length; i++) {
          if (this.table[i] != undefined) {
             console.log(i + " : " + this.table[i]);
          }
       }
    }
    

    测试用例
    HashTable1
    程序结果:

     35: Cynthia
     45: Clayton
     57: Donnie
     77: David
     95: Danny
     116: Mike
     132: Jennifer
     134: Jonathan
    

    根据结果来看,数据没有均匀分布,有时候还会出现碰撞(散列值一样)的情况,我们需要改善散列函数。


    1.2 更好的散列函数

    使用 霍纳德算法 得到更好的散列函数。

    function betterHash(string, arr) {
       const H = 37; // 通过一个常数值声明一个块范围变量
       var total = 0;
       for (var i = 0; i < string.length; ++i) {
          total += H * total + string.charCodeAt(i);
       }    
       total = total % arr.length;
       return parseInt(total);
    }
    

    测试用例:
    betterHash

    结果为:

    12: Jennifer
    22: Raymond
    55: Donnie
    58: Clayton
    80: Jonathan
    82: Mike
    103: Cynthia
    110: Danny
    

    1.3 散列化整型键

    这里使用的数据集是学生的成绩,随机产生一个9位数的键,用来识别学生身份和一门成绩。

    function getRandomInt (min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }
    
    function genStuData(arr) {
       for (var i = 0; i < arr.length; ++i) {
          var num = "";
          for (var j = 1; j <= 9; ++j) {
             num += Math.floor(Math.random() * 10);
          }
          num += getRandomInt(50,100); //可以指定随机数的最大值和最小值
          arr[i] = num;
       }
    }
    
    

    genStuDate() 函数生成学生的数据。里层的循环生成 ID,后面的循环代码生成一个随机的成绩,并把成绩添加在ID后面。主程序会分离ID和成绩,散列函数将学生ID里的数字相加,使用 simpleHash() 函数计算出散列值。
    示例程序:
    HashTable2

    运行结果为:

     Student data:
    
     04437992 89
     35054068 96
     34780034 52
     34103157 91
     29752520 74
     96057108 80
     55413450 57
     33664847 61
     33179680 71
     91022430 51
    
    
     Data distribution:
    
     9: 91022430251
     16: 34103157291
     18: 34780034252
     26: 29752520374
     27: 55413450857
     28: 33664847061
     30: 96057108680
     32: 33179680771
     35: 35054068996
     44: 04437992989
    

    使用更好的 散列函数 betterHash(),得到的输出。
    示例程序:
    betterTable2.sj

     Student data:
    
     90605894 100
     41483254 96
     42802463 86
     25395996 90
     39102248 97
     52528869 68
     53083791 94
     01904985 63
     51172821 61
     84746600 82
    
    
     Data distribution:
    
     19: 84746600382
     40: 39102248697
     45: 01904985263
     61: 53083791894
     64: 42802463486
     70: 25395996790
     93: 52528869068
     105: 41483254496
     112: 906058948100
     127: 51172821561
    

    通过对比,可以发现无论是字符串还是整型, betterHash() 的散列效果都更胜一筹。

  • 相关阅读:
    团队工作第四次推进之——软件设计规格说明书
    失物找寻APP软件需求规格说明书——第三次团队作业
    你还在为校园内丢失东西无处可寻而发愁吗?速戳进来
    十分有趣却有些遗憾的结对编程——两位女程序员的挣扎
    结对编程初涉猎——结对伙伴的代码复审
    个人实战演练全过程——No.1 最大连续子数组求和
    小白出品 单元测试相关——入门级说明书
    写着写着停不下来的普通女程序员的总结
    vs2010 和vs2012的区别 副标题--Loaded事件走两次
    汽车防撞软件引发的一套软件系统思路
  • 原文地址:https://www.cnblogs.com/zhoufulin/p/5008928.html
Copyright © 2011-2022 走看看