JavaScript数据结构 --- 散列
2015-12-01 00:22
309 查看
JavaScript数据结构 --- 散列
散列是一种常用的数据存储技术,散列后的数据可以快速地插入或取用,但查找操作却效率低下,这是可以依靠其他数据结构(例如二叉查找树)。散列使用的数据结构叫散列表,这里的散列表是基于数组进行设计的。所有元素根据该元素对应的键(类型字典中的键),保存在数组的特定位置。使用散列表存储数据时,通过一个散列函数 将键映射为一个长度为 0 到散列表长度的数字。
一般来说,数组的长度是有限的,所以我们让散列函数尽量将键均匀地映射到数组中。
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() 的散列效果都更胜一筹。
相关文章推荐
- 数据结构之栈
- 分治算法
- 数据结构例程——基数排序
- 数据结构例程——简单的计数排序
- 数据结构例程——归并排序
- 数据结构例程——选择排序之堆排序
- 枚举法的简单心得
- 【数据结构】栈结构操作示例
- 【数据结构】链表操作示例
- 【Educational Codeforces Round 2E】【STL-map 启发式合并 or 线段树动态开节点 】Lomsat gelral 一棵树每点一个颜色问每个节点子树的颜色众数之和
- 数据结构与算法-----队列-使用链表(链式结构)实现
- 第十二周--数据结构--非连通图的遍历之三
- 第九周 数据结构实践项目——数组和广义表【项目3.2-- 稀疏矩阵相加】
- 第十二周--数据结构--非连通图的遍历之二
- 【第14周-查找项目1-1——验证折半查找算法】
- 第9周SHH数据结构-【项目1--猴子选大王(数组版)】 .
- 第8周SHH数据结构-【项目5-计数的模式匹配 . 】
- 第十二周--数据结构--非连通图的遍历之一
- leetcode之Remove Duplicates from Sorted Array II
- 数据结构例程——哈希表及其运算的实现