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

    1.File Zilla File Zilla是一个开源的,跨平台的Linux FTP客户端.File Zilla有一个标签式的用户界面,允许用户查看正在传输的文件的所有细节.File Zilla是通 ...

  2. center os 7最小化安装后按table无法补全命令的问题

    闲来无趣,这两天huskiesir又重新安装了下center os 7操作系统,结果呢,发现一个问题:按table键无法补全命令啊. 咦,奇怪了,这次怎么回事,完全没遇到过啊.哦,回想了一下,和以往的 ...

  3. PHP DES-ECB加密对接Java解密

    最近公司有个业务,需要对接第三方接口,但是参数是需要加密的,对方也只提供了一个java的demo,在网上到处搜索,没有找到直接就能用的方法,后来还是跟公司的Android工程师对接出来的,在这里记录一 ...

  4. CF 414B Mashmokh and ACM 动态规划

    题意: 给你两个数n和k.求满足以下条件的数列有多少个. 这个数列的长度是k: b[1], b[2], ……, b[k]. 并且 b[1] <= b[2] <= …… <= b[k] ...

  5. bug14052601

    AppDelegate.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall cocos2d::ui::Margin::Margin(void ...

  6. [Recompose] Make Reusable React Props Streams with Lenses

    If you hard-code a stream of props to target a specific prop, it becomes impossible to reuse that st ...

  7. 荣耀A55高调上市仅仅为孤独求败?

        坦白说.华为近年来在手机市场上确实取得了一些成绩.比方之前P6的出现就凭借超薄的设计.突出的性价比让大家看到了国产手机的新希望.按理说.在手机市场上尝到甜头的华为应该继续坚持低价.亲民的路线, ...

  8. HTTP协议学习,post于get;用Fiddler测试请求

    转载 收藏于网络 1.简介: HTTP协议:Hypertext transfer protocol 超文本 传输 协议 它是TCP/IP协议集中的一个运用层协议. 用于定义WEB浏览器和WEB服务器之 ...

  9. 携手互联网企业10巨头设VC基金

    包括小米科技.盛大集团.人人网.掌趣科技.游族网络.龙图游戏.蓝港互动.37游戏.星辉互动娱乐.博雅互动等10家知名互联网企业作为出资人(LP)的优格创投基金近日正式成立. 众所周知,伴随着移动互联网 ...

  10. 手把手教你在VMware虚拟机中安装Ubuntu14.04系统

    在VMware中创建完虚拟机之后,一般需要给虚拟机安装系统,比较受青睐的系统有Ubuntu和Centos,关于Centos系统的安装之前已经写过了,感兴趣的小伙伴可以戳这篇文章:靠谱的centos7. ...