散列:实现散列表的数据后可以快速地实现插入或者删除。但是对于实现查找操作则效率非常的低。
散列表的底层是数组实现的,长度是预先设定,可以随时根据需求增加。所有的元素根据和该元素对应的键,保存在特定的位置。使用散列表存储数据时,通过一个散列函数将键值映射为一个数字,数字的范围是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. Bayes++ Library入门学习之熟悉class-Importance_resampler

    接下来,需要介绍的是重要性重采样类Bayesian_filter::Improtance_resampler.该类实现了两种重采样方法[1][2],和其子类的继承关系图如下: 其中Standard_r ...

  2. 前端之CSS介绍

    CSS介绍 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素. 当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染). CSS的语法 CSS语 ...

  3. 第三讲 $\mathbb{R}^4$上平凡主丛的联络、曲率与Yang-Mills泛函

    一. $\mathbb{R}^4$或$\mathbb{R}^n$上平凡主丛的联络与曲率$\newcommand{\R}{\mathbb{R}}$ 回忆切丛$T\R^n\cong \R^n\times\ ...

  4. Attach、Detach和DeleteObject

    原文:Attach.Detach和DeleteObject,想飞的梦想 1.CWnd Attatch和Detach的关系 首先,要明白Windows对象和MFC对象的区别. MFC对象实际上并没有把整 ...

  5. 每天一个linux命令(九月)

    2014-09-02 top 实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器 命令參数: -b 批处理 -c 显示完整的治命令 -I 忽略失效过程 -s 保密模式 -S 累积模 ...

  6. Codeforces Round #313 (Div. 2) 解题报告

    A. Currency System in Geraldion: 题意:有n中不同面额的纸币,问用这些纸币所不能加和到的值的最小值. 思路:显然假设这些纸币的最小钱为1的话,它就能够组成随意面额. 假 ...

  7. HIT 2255 Not Fibonacci(矩阵高速幂)

    #include <iostream> #include <cstdio> #include <cstring> using namespace std; cons ...

  8. 八款常用的 Python GUI 开发框架推荐

    作为Python开发者,你迟早都会用到图形用户界面来开发应用.本文将推荐一些 Python GUI 框架,希望对你有所帮助,如果你有其他更好的选择,欢迎在评论区留言. Python 的 UI 开发工具 ...

  9. BZOJ3158: 千钧一发

    [传送门:BZOJ3158] 简要题意: 给出n个机器,每个机器有a[i]基础值和b[i]价值 选出一部分机器使得这些机器里面两两至少满足以下两种条件之一: 1.a[i]2+a[j]2!=T2(T为正 ...

  10. POJ 3189 二分+Dinic

    题意: 思路: 二分跨度 枚举最低座次 建图:源点向每头牛连边权为1的边 每头牛向当前枚举的B的区间这段连上边权为1的边 所有座次向汇点连边权为牛棚容量的边 判判流量是不是等于n 一开始写得是直接枚举 ...