散列:实现散列表的数据后可以快速地实现插入或者删除。但是对于实现查找操作则效率非常的低。
散列表的底层是数组实现的,长度是预先设定,可以随时根据需求增加。所有的元素根据和该元素对应的键,保存在特定的位置。使用散列表存储数据时,通过一个散列函数将键值映射为一个数字,数字的范围是0-散列表的长度。
碰撞(collision):理想状态下散列函数会将每一个键值映射成一个唯一的数组索引。但是健的数量是无限的,数组的长度是有限的,一个更现实的目标是让散列函数尽量将键均匀地映射到数组中。即使使用一个高效的散列函数,仍然存在两个键映射成同一个值的可能。这就是所谓的碰撞。它产生时我们就要去解决。
散列表中的数组究竟设置多大?
常见设置:数组长度是一个质数。
        function HashTable() {
this.table = new Array(137);
this.simpleHash = simpleHash;//哈希函数
this.betterHash = betterHash;//霍纳哈希函数
this.buildChains = buildChains;//开连法
this.showDistro = showDistro;//显示散列表中的数据
this.showDistro1 = showDistro1;//开连法显示散列表中的数据
this.put = put;//将数据存储到列表中
//this.newPut = newPut;//将数据存储到列表中
this.get = get;
}
//哈希函数:简单的除留余数法
function simpleHash(data) {
var total = 0;
for(var i = 0;i<data.length;i++) {
total += data.charCodeAt(i);//方法可返回指定位置的字符的Unicode 编码。这个返回值是0-65535之间的整数。相加得到散列值。
}
//console.log(total+"======");
return total%this.table.length;//除留余数法返回一个数值
}
function put(data) {
var _pos = this.simpleHash(data);//的到数组的索引
//var _pos = this.betterHash(data);//的到数组的索引
this.table[_pos] = data;//根据返回的值作为键值存储数据。
}
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]);
//document.write(i+": "+this.table[i]+"<br>");
}
}
}
var hash = new HashTable();
var book = ["JavaScript","jQuery","php","java","go","html5","AI"];
for(var i =0;i < book.length;i++) {
hash.put(book[i]);
}
//hash.showDistro();
console.log(book.length);
1: AI
7: java
54: php
56: JavaScript
77: go
79: html5
92: jQuery
上述会有问题:
1.数据呈现向两端分布。
2.有时会出现内容显示不全的问题,(散列函数处理时有了相同的散列值,就产生了碰撞)
散列函数的设计:解决碰撞
确保散列表用来存储数据的数组其大小是一个质数(数学运算对质数取余数时余数重复率低)。数组的长度应该大于100,让其分布更加的均匀。
霍纳算法:
新的散列函数仍然先用计算字符串的ASCII码值,不过在求和时每次乘以一个质数。建议一个较小的,(31,37);
        function betterHash(str) {
var h = 37;
var total = 0;
for(var i = 0;i < str.length;i++) {
total += h*total+str.charCodeAt(i);
}
total = total % this.table.length;
if(total < 0) {
total += this.table.length - 1;
}
return parseInt(total);
}
var hash2 = new HashTable();
var book2 = ["JavaScript","jQuery","php","java","go","html5","AI"];
for(var i = 0;i < book2.length;i++) {
hash2.put(book2[i]);
}
散列化整型键:
上述两个例子都是对于字符串类型的键值进行操作,现在研究整型键的数据操作。
eg:学生的成绩查询,随机生成一个9位数的键(ID),用以识别学生身份和一门成绩。
        //生成学生成绩:
function getRandomGrade(min,max) {
return Math.floor(Math.random()*(max-min+1))+min;
}
//生成ID:
function getStuID(arr) {
for(var i = 0;i < arr.length;i++) {
var num = "";
for(var j = 0;j < 9;j++) {
num +=Math.floor(Math.random()*10);
}
num += getRandomGrade(50,100);
arr[i] = num;
}
}
var stuNum = 10;
var students = new Array(stuNum);
getStuID(students);
for(var i = 0;i < students.length;i++) {
//console.log(students[i]);
console.log(students[i].substring(0,8)+" "+students[i].substring(9));
}
var hTab = new HashTable();
for(var i = 0;i < students.length;i++) {
hTab.put(students[i]);
}
hTab.showDistro();
//如果同样用第一种哈希函数解决会产生碰撞,用较好的哈希函数则不会产生碰撞。
           //散列表的排序,取值:
// 要重新定义put(),get(); //带有键值的添加方法
function newPut(key,data) {
var _pos = this.betterHash(key);
this.table[_pos] = data;
}
//获取方法:
function get(key) {
return this.table[this.betterHash(key)];
}
//test: 输入三个人的姓名和电话号码进行查询,三个输入后输出quit进行查询
var numbers = new HashTable();
var name,number;
for(var i = 0;i < 3;i++) {
//name = prompt("请输入姓名:");
//number = prompt("请输入电话:");
numbers.newPut(name,number);
}
name = "";
prompt("输入quit结束:");
while(name != "quit") {
name = prompt("里面的成员:");
if(name == "quit") {
break;
}
alert(name+"成员的电话是:" + numbers.get(name));
prompt("输入quit结束:");
}
碰撞处理:开链法和线性检测
开链法:将键同样存储到通过散列函数计算的索引位置上,但不可能将多份数据存储到一个数组单元中。在实现散列表的底层数组中的每一个元素又是一个新的数据结构,即使使用两个键三列后的值相同,依然被保存在同样的位置,但是他们在第二个数组的位置不一样。
实现方法:在创建存储散列的键值的数组时通过调用一个函数创建一个空数组,然后将该数组赋值给散列表中的每个数组。这样就创建了一个二维数组。
        function buildChains() {
for(var i = 0;i < this.table.length;i++) {
this.table[i] = new Array();
}
}
//相应的显示元素也要改变
function showDistro1() {
//var num = 0;
for(var i = 0;i < this.table.length;i++) {
if(this.table[i][0] != undefined) {
console.log(i + ":" +this.table[i]);
}
}
}
//put
function put(key,data) {
var pos = this.simpleHash(key);
var index = 0;
if(this.table[pos][index] == undefined) {
this.table[pos][index] = data;
}else {
while(this.table[pos][index] != undefined) {
++index;
}
this.table[pos][index] = data;
}
}
//get
function get(key) {
var index = 0;
var pos = this.simpleHash(key);
if(this.table[pos][index] == key) {
return this.table[pos][index];
}else {
while(this.table[pos][index] != key) {
++index;
}
return this.table[pos][index];
}
return undefined;
}
//test:
var hTable = new HashTable();
hTable.buildChains();
var arrName = ["David","Jennifer","Donnie","Raymond","Cynthia","Mike","Clayton","Danny","Jonathan"];
for(var i = 0;i < arrName.length;i++) {
hTable.put(arrName[i]);
}
hTable.showDistro1();

JavaScript--数据结构与算法之散列的更多相关文章

  1. 数据结构和算法 – 7.散列和 Hashtable 类

    7.1.散列函数 散列是一种常见的存储数据的技术,按照这种方式可以非常迅速地插入和取回数据.散列所采用的数据结构被称为是散列表.尽管散列表提供了快速地插入.删除.以及取回数据的操作,但是诸如查找最大值 ...

  2. javascript数据结构与算法--散列

    一:javascript数据结构与算法--散列  一:什么是哈希表? 哈希表也叫散列表,是根据关键码值(key,value)而直接进行访问的数据结构,它是通过键码值映射到表中一个位置来访问记录的,散列 ...

  3. JavaScript数据结构与算法-散列练习

    散列的实现 // 散列类 - 线性探测法 function HashTable () { this.table = new Array(137); this.values = []; this.sim ...

  4. 为什么我要放弃javaScript数据结构与算法(第七章)—— 字典和散列表

    本章学习使用字典和散列表来存储唯一值(不重复的值)的数据结构. 集合.字典和散列表可以存储不重复的值.在集合中,我们感兴趣的是每个值本身,并把它作为主要元素.而字典和散列表中都是用 [键,值]的形式来 ...

  5. 为什么我要放弃javaScript数据结构与算法(第九章)—— 图

    本章中,将学习另外一种非线性数据结构--图.这是学习的最后一种数据结构,后面将学习排序和搜索算法. 第九章 图 图的相关术语 图是网络结构的抽象模型.图是一组由边连接的节点(或顶点).学习图是重要的, ...

  6. 为什么我要放弃javaScript数据结构与算法(第六章)—— 集合

    前面已经学习了数组(列表).栈.队列和链表等顺序数据结构.这一章,我们要学习集合,这是一种不允许值重复的顺序数据结构. 本章可以学习到,如何添加和移除值,如何搜索值是否存在,也可以学习如何进行并集.交 ...

  7. 为什么我要放弃javaScript数据结构与算法(第二章)—— 数组

    第二章 数组 几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构.JavaScript里也有数组类型,虽然它的第一个版本并没有支持数组.本章将深入学习数组数据结构和它的能力. 为什么 ...

  8. javascript数据结构与算法---栈

    javascript数据结构与算法---栈 在上一遍博客介绍了下列表,列表是最简单的一种结构,但是如果要处理一些比较复杂的结构,列表显得太简陋了,所以我们需要某种和列表类似但是更复杂的数据结构---栈 ...

  9. javascript数据结构与算法---列表

    javascript数据结构与算法---列表 前言:在日常生活中,人们经常要使用列表,比如我们有时候要去购物时,为了购物时东西要买全,我们可以在去之前,列下要买的东西,这就要用的列表了,或者我们小时候 ...

  10. 为什么我要放弃javaScript数据结构与算法(第十一章)—— 算法模式

    本章将会学习递归.动态规划和贪心算法. 第十一章 算法模式 递归 递归是一种解决问题的方法,它解决问题的各个小部分,直到解决最初的大问题.递归通常涉及函数调用自身. 递归函数是像下面能够直接调用自身的 ...

随机推荐

  1. sublime text3之修改注释颜色

    在用sublime text3编写Python2代码时总觉得注释颜色太浅了, 看起来吃力,于是就尝试去修改,和sublime text2不同, sublime text3的主题配置文件在Sublime ...

  2. WLAN 感知

    WLAN 感知 通过 Android 8.0 中新增的 WLAN 感知功能,支持设备可以直接使用 WLAN 感知协议发现其他设备.与其他设备进行互连,以及将覆盖范围扩展到其他设备(Android 9 ...

  3. 用SAXReader解析xml文档【转】

    来源:http://blog.csdn.net/seayqrain/article/details/5024068 使用SAXReader需要导入dom4j-full.jar包. dom4j是一个Ja ...

  4. vue里面模板解析数据的时候

    页面中新建信息的时候值之间有多个空格的时候 可以使用pre标签,你写了多少个空格,页面就会渲染出来 html解析 什么是pre标签

  5. springboot整合redis,并解决乱码问题。

    热烈推荐:超多IT资源,尽在798资源网 springboot 版本为 1.5.9 //如果是2.x 修改 pom.xml 也可切换成 1.5.9 <parent> <groupId ...

  6. shell判断变量是字符还是数字

    ok,以后最好是每天一个shell小脚本吧,这样以后工作时还可以直接套用,嗯,比较不错,顺便还可以带给刚入门shell的朋友一些帮助,好了,废话不多说,下面是我两种判断的实现方式: 1.通过grep去 ...

  7. POJ——T 3728 The merchant

    http://poj.org/problem?id=3728 Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 5068   A ...

  8. 三 概要模式 2) MR倒排索引、性能分析、搜索干扰词。

    二  倒排索引     倒排索引(英语:Inverted index),也常被称为反向索引.置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射. ...

  9. glEnable(GL_DEPTH_TEST)作用

    glEnable(GL_DEPTH_TEST): 用来开启更新深度缓冲区的功能,也就是,如果通过比较后深度值发生变化了,会进行更新深度缓冲区的操作.启动它,OpenGL就可以跟踪再Z轴上的像素,这样, ...

  10. C#日期控件datetimepicker保存空值方法

    方法一(推荐): 设置datetimepicker的属性ShowCheckBox为true 在窗口初始化时候,添加代码this.datetimepicker1.Checked = false; 保存日 ...