散列表的实现 -- 数据结构与算法的javascript描述 第八章
散列表(哈希表
散列是一种常用的数据存储技术,散列后的数据可以快速地插入或取用。
散列表需要一个散列值(key)来存储指定数据,取数据也是依靠此。
散列值可以依靠计算数据的 ASCII码来获得,但是这会有一个问题,若干数据的散列值可能会相同,这样存储就会发生碰撞。
方案:
开链法, 对Hash表中每个Hash值建立一个冲突表,即将冲突的几个记录以表的形式存储在其中
开放寻址散列,当发生碰撞时,线性探测法检查散列表中的下一个位置是否为空。如果为空,就将数据存入该位置;如果不为空,则继续检查下一个位置,直到找到一个空的位置为止。
第一版code
//版本一 (字符串类型的键
//因其对散列值处理中 有碰撞的可能。
//不具备处理碰撞数据的能力(有可能散列值相同,会把上一个值覆盖掉)
function HashTable(){
var me = this;
me.table = new Array(137);
me.simpleHash = simpleHash;
me.showDistro = showDistro;
me.showPutLength = showPutLength;
//统计有多少数据进入散列表
me.putLength = 0;
me.put = put;
/**
* 取散列值 *取每个字符的ASCII码值之和
* @param s
* @returns {number}
*/
function simpleHash(s){
var total = 0;
for (var i = 0; i < s.length; ++i) {
total += s.charCodeAt(i);
}
return total % me.table.length;
}
function put(data){
me.putLength++;
var pos = me.simpleHash(data);
me.table[pos] = data;
}
function showDistro(){
var s = '',i=0;
for(;i<me.table.length;i++){
if (me.table[i] != undefined) {
s+=" key: "+ i+" , value:"+me.table[i] +" \n";
}
}
console.log(s)
}
function showPutLength(){
console.log("共有 "+me.putLength+" 次插入散列表行为");
return me.putLength;
}
}
第一版测试
//版本一测试
var someNames = [
"David",
"Jennifer",
"Donnie",
"Raymond",
"Cynthia",
"Mike",
"Clayton",
"Danny",
"Jonathan"
];
var hTable = new HashTable();
for (var i = 0; i < someNames.length; ++i) {
hTable.put(someNames[i]);
}
hTable.showPutLength();
hTable.showDistro();
版本一的数据碰撞处理有问题。我们修改一个版本来优化这个地方。
新的散列值计算方式用了 霍纳算法的思想,乘以一个质数来尽量避免碰撞。
function HashTable2(){
var me = this;
me.table = new Array(137);
me.simpleHash = simpleHash;
me.showDistro = showDistro;
me.showPutLength = showPutLength;
me.put = put;
//统计有多少数据进入散列表
me.putLength = 0;
//质数,当该数字式37时候 也会碰撞 +_+
me.H = 31;
//第二版 修正碰撞问题(只能说 尽可能减少碰撞 霍纳算法
//为了避免碰撞,首先要确保散列表中用来存储数据的数组其大小是个质数
//新的散列函数仍然先计算字符串中各字符的ASCII码值,不过求和时每次要乘以一个质数。
/**
* 取散列值 *取每个字符的ASCII码值之和
* @param s
* @returns {number}
*/
function simpleHash(s){
var total = 0;
for (var i = 0; i < s.length; ++i) {
total += me.H * total + s.charCodeAt(i);
}
total = total % me.table.length;
if (total < 0) {
total += me.table.length-1;
}
return parseInt(total);
}
function put(data){
me.putLength++;
var pos = me.simpleHash(data);
me.table[pos] = data;
}
function showDistro(){
var s = '',i=0;
for(;i<me.table.length;i++){
if (me.table[i] != undefined) {
s+=" key: "+ i+" , value: "+me.table[i] +" \n";
}
}
console.log(s)
}
function showPutLength(){
console.log("共有 "+me.putLength+" 次插入散列表行为");
return me.putLength;
}
}
散列表总结
实现一个散列表存储最主要的问题就是解决 碰撞问题。
碰撞原因:
我们要将一个字符或者整型键进行存储,需要对其进行计算散列值(计算方式为每个字符的ASCII码值相加,尽管计算方法升级优化了 仍会有碰撞的可能),但是不同的字符或者整形可能计算出同一个散列值,这样就会发生碰撞,后面插入的值会覆盖前面的值。
比如 “Clayton”与 “Raymond” 计算后的散列值一样。
为了尽量避免碰撞,我们对计算散列值的方法进行了优化,新的散列函数仍然先计算字符串中各字符的ASCII码值,不过求和时每次要乘以一个质数。具体可以搜索:[霍纳算法],注: 这一版本 虽然优化了计算方法,仍然有碰撞的可能
碰撞处理:
开链法:
是指实现散列表的底层数组中,每个数组元素又是一个新的数据结构,比如另一个数组,这样就能存储多个键了。使用这种技术,即使两个键散列后的值相同,依然被保存在同样的位置,只不过它们在第二个数组中的位置不一样罢了
开链法的可能存储结构:
[ [1],
[2],
[3,3,3,3] //多个数据 散列值一样,但是存储在同一位置不同下标中。
]
实现开链法的方法是:在创建存储散列过的键值的数组时,通过调用一个函数创建一个新的空数组,然后将该数组赋给散列表里的每个数组元素。这样就创建了一个二维数组
线性探测法:
当发生碰撞时,线性探测法检查散列表中的下一个位置是否为空。如果为空,就将数据存入该位置;如果不为空,则继续检查下一个位置,直到找到一个空的位置为止。该技术是基于这样一个事实:每个散列表都会有很多空的单元格,可以使用它们来存储数据
到此为止,只是了解了如何实现不碰撞的方法,但碍于水平有限,并未实现完整的代码,所以就不贴出来了。希望能对看到的人有所帮助~。
散列表的实现 -- 数据结构与算法的javascript描述 第八章的更多相关文章
- 检索算法 -- 数据结构与算法的javascript描述 第13章
检索算法-如何在列表中查找特定的值. 顺序查找 从列表的第一个元素开始对列表元素逐个进行判断,直到找到了想要的结果,它属于暴力查找技巧的一种,在执行查找时可能会访问到数据结构里的所有元素. 代码: / ...
- 排序算法 -- 数据结构与算法的javascript描述 第12章
排序是常见的功能,给定一组数据,对其进行排序. 在此之前,我们需要准备个基础工作--自动生成数组,并可以对该组数据做任何处理. /** * 测试类 ,数组 * @param numElements * ...
- 二叉树的实现 -- 数据结构与算法的javascript描述 第十章
/** * 树,一种非线性的数据结构. 以分层的方式存储数据. * 一棵树最上面的节点成为根节点,如果一个节点下面有多个节点,这个节点称为父节点,下面的节点称为子节点 * 没有任何子节点的节点,陈宝国 ...
- 集合的实现 -- 数据结构与算法的javascript描述 第九章
集合 集合(set)是一种包含不同元素的数据结构. 集合中的元素称为成员. 集合的两个最重要特性是:首先,集合中的成员是无序的:其次,集合中不允许相同成员存在. code function Set() ...
- 字典 -- 数据结构与算法的javascript描述 第七章
字典 字典是一种以键-值对形式存储数据的数据结构 最基本功能规划 add 添加数据到字典 remove 从字典中移除数据 get 从字典中取出数据 count 统计字典数据量 find 查找数据在字典 ...
- 队列的实现 -- 数据结构与算法的javascript描述 第五章
队列也是列表的一种,有不同于列表的规则. 先进先出 入队方法 出队方法 可以找到队首 可以找到队尾 可以查看队列有多长 可以查看队列是否为空 这是一个基本的需求,围绕他来实现,当然我们可以自己扩展列表 ...
- 链表的实现 -- 数据结构与算法的javascript描述 第六章
链表 链表是由一组节点组成的集合.每个节点都使用一个对象的引用指向它的后继.指向另一个节点的引用叫做链 结构示意图 : 链表头需要我们标识 head { element:head,next:obj1 ...
- 栈的实现 -- 数据结构与算法的javascript描述 第四章
栈 :last-in-first-out 栈有自己特殊的规则,只能 后进入的元素 ,最先被推出来,我们只需要模拟这个规则,实现这个规则就好. peek是返回栈顶元素(最后一个进入的). /** * 栈 ...
- 列表的实现-----数据结构与算法JavaScript描述 第三章
实现一个列表 script var booklist = new List(); booklist.append('jsbook'); booklist.append('cssbook'); book ...
随机推荐
- MAC 下使用ipv6、ipv4观看电视、网络电视
换了mac book,ipv6电视却看不了了,为了看电视,只要自己动手了. 关于ipv6是啥和哪里有ipv6这里就不说了,找度娘吧. 我们观看IPv6视频直播信号有两种,一种是mms协议,另外一种 ...
- Balls Rearrangement(HDU)
Problem Description Bob has N balls and A boxes. He numbers the balls from 0 to N-1, and numbers the ...
- Network()
Network Time Limit : 2000/1000ms (Java/Other) Memory Limit : 60000/30000K (Java/Other) Total Submi ...
- LA - 5031 - Graph and Queries
题意:一个N个点(编号从1开始),M条边的无向图(编号从1开始),有3种操作: D X:把编号为X的边删了: Q X K:查询编号为X的结点所在连通分量第K大的元素: C X V:将编号为X的结点的权 ...
- 联想A208T ROOT
前几天,一直陪伴我的海信T89电池挂掉...胀胀的肚子...真可怜 一时之间找不到配套的电池,就借了个手机先用着,就是这 联想A208T ROOT... 话说的配置一般般,勉强够我这样的不怎么玩手机的 ...
- SQL函数介绍
http://www.cnblogs.com/moss_tan_jun/archive/2010/08/23/1806861.html 一旦成功地从表中检索出数据,就需要进一步操纵这些数据,以获得有用 ...
- R 语言学习笔记
data() 调用内置数据集 help(women) 查看数据集women的帮助文档 当忘记函数名称时可以按关键字搜索:help.search(),简写为??“” str(var) 查看R对象内部结 ...
- ORACLE函数TO_CHAR以及数字转换格式[Z]
本来这是很简单的函数,但在屡次忘记格式之后,决定还是翻译一遍以铭记在心. 参考<<Oracle Database SQL Reference>>. 关于nl ...
- 使用PowerDesigner创建数据库表图文并茂版
使用PowerDesigner创建数据库表图文并茂版 使用PowerDesigner 建数据库表. 一直很忙,没有时间写东西.这次搞点会声会色的,嘿嘿 此技能为项目经理必备技能. 本次主角: 1.在w ...
- ftp上来显示的时间和系统时间不一致
ftp上来显示的时间和系统时间不一致,是因为默认情况下,vsftpd 是用GMT做为他的时间的,所以和系统的时间可能会不一致 修改也非常简单: vi /etc/vsftpd/vsftpd.conf 在 ...