什么是字典组织?
字典
是以键值对情势存储数据的数据组织,就像电话号码薄里的名字和电话号码那样的一一对应的关联。
javascript
的Object
类就是以如许的一种字典情势设想的。
键值对在字典中以如许的体式格局标记:d = {key1 : value1, key2 : value2 }。
字典中的键/值对是没有递次的。假如你想要一个特定的递次,那末你应当在运用前本身对它们排序。
Dictionary类
Dictionary
类的基本是Array
类,而不是Object
类。我们想对字典中的键排序,而在js中是不能对 对象 的属性举行排序的。话虽如此,但在js
中一切皆对象,数组也是对象。以下面的代码最先定义Dictionary
类:
<script type="text/javascript">
function Dictionary(){
this.datastore = new Array();
}
</script>
先来定义add()
要领。该要领接收两个参数:键和值
。键是值在字典中的索引,代码以下:
function add(key,value){
this.datastore[key] = value;
}
接下来定义find()
要领,该要领以 键
做为参数,返回和其关联的值。代码以下:
function find(key){
return this.datastore[key];
}
从字典中删除键-值对 须要运用js
中的delete
函数。该函数是Object
类的一部分,该函数同时删掉键和与其关联的值:
function remove(key){
delete this.datastore[key];
}
末了,我们愿望能够显现字典中所有的键-值对,能够运用以下的要领:
function showAll(){
for(var key in Object.keys(this.datastore)){
print(key + "->" + this.datastore[key]);
}
}
Dictionary类的辅佐要领
我们能够定义一些在特定情况下有效的辅佐要领。比方要晓得字典中的元素个数能够定义一个count()
要领,代码以下:
function count(){
var n=0;
for(var key in Object.keys(this.datastore)){
++n;
}
return n;
}
为何不运用length
属性?这是由于当键的范例为字符串时,length
属性就不管用了
还能够定义一个clear消灭要领:
function clear(){
for each(var key in Object.keys(this.datastore)){
delete this.datastore[key];
}
}
备注:
for each in
(IE6,7,8不支持)没法取得对象的属性名,只能猎取到属性值。
别的,遍历对象也只管运用for in
而不是for each
,而遍历数组的话照样运用for
轮回吧
for each in
没法取得对象的属性名,只能猎取到属性值。
散列(hash)
什么是哈希表?
哈希表(Hash table,也叫散列表),是依据关键码值(Key value)而直接举行接见的数据组织。也就是说,它经由过程把关键码值映照到表中一个位置来接见纪录,以加速查找的速率。这个映照函数叫做散列函数,寄存纪录的数组叫做散列表。
哈希表的做法实在很简朴,就是把Key
经由过程一个牢固的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度举行取余,取余效果就当作数组的下标,将value存储在以该数字为下标的数组空间里。
而当运用哈希表举行查询的时刻,就是再次运用哈希函数将key
转换为对应的数组下标,并定位到该空间猎取value
,如此一来,就能够充分利用到数组的定位机能举行数据定位
散列表的查找步骤
当存储纪录时,经由过程散列函数盘算出纪录的散列地点
当查找纪录时,我们经由过程一样的是散列函数盘算纪录的散列地点,并按此散列地点接见该纪录
在js
中,散列函数会将每一个键值映照为一个唯一的数组索引。但是,键的数目是无穷的,数组的长度是有限的,所以,应当让散列函数只管将键匀称地映照到数组中。
哈希表也是种数据组织,它能够供应疾速的插进去操纵和查找操纵。哈希表运算速率极快,哈希表的速率显著比树快,树的操纵一般须要O(N)的时候级。哈希表不仅速率快,编程完成也相对轻易。
哈希表算法
哈希表最常见的例子是以门生学号为关键字的结果表,1号门生的纪录位置在第一条,10号门生的纪录位置在第10条…
假如我们以门生姓名为关键字,怎样竖立查找表,使得依据姓名能够直接找到响应纪录呢?
用上述获得的数值作为对应纪录在表中的位置,获得下表:
上面这张表即哈希表。
假如未来要查李秋梅的结果,能够用上述要领求出该纪录所在位置:
李秋梅:lqm 12+17+13=42
取表中第42条纪录即可。
HashTable类
我们运用一个类来示意散列表,该类包括盘算散列值的要领、向散列中插进去数据的要领、从散列表中读取数据的要领、显现散列表中数据散布的要领等。HashTable
类的组织函数定义以下:
function HashTable(){
this.table = new Array(137);//设定数组长度为137,质数
this.simpleHash = simpleHash;
this.showDistro = showDistro;
this.put = put;
}
散列函数的挑选依赖于键值的数据范例。假如键是整形,最简朴的散列函数就是以数组的长度对键取余。
运用一个简朴的散列函数做散列:
load("HashTable.js");
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.showDistro();
输出以下:
35:Cynthia
45:Clayton
57:Donnie
77:David
95:Danny
116:Mike
132:Jennifer
134:Jonathan
simpleHash()
函数经由过程运用js
的charCodeAt()
函数,返回每一个字符的ASCII
码值,然后再将它们相加获得散列值。put
要领经由过程挪用simpleHash()
函数获得数组的索引,然后将数据存储到该索引对应的位置上。
一个更好的散列函数
为了防止碰撞,首先要确保散列表中用来存储数据的数组其大小是个质数,这和盘算散列值时运用的取余运算有关。数组的长度应当在100以上,这是为了让数据在散列表中散布得更匀称
散列化整型键
这里我们运用一个展现门生结果的数据集,将随机发生一个9位数的键,用以辨认门生身份和一门结果,下面是发生门生数据(包括ID和结果)的函数:
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;
}
}
运用getRandomInt()
函数时,能够指定随机数的最值。genStuData()
函数天生门生的数据。里层的轮回用来天生门生的ID,紧跟在轮回背面的代码天生一个随机的结果,并把结果弄在ID的背面。主程序会把ID和结果星散。散列函数将门生ID里的数字相加,运用simpleHash()
函数盘算出散列值。
对散列表排序
put
要领同时接收键和数据作为参数,对键值散列后,将数据存储到散列表中:
function put(key,data){
var pos = this.betterHash(key);
this.table[pos] = data;
}
put
要领将键值散列化后,将数据存储到散列化后的键值对应在数组中的位置上。
从散列表中取值
定义get()
要领,用以读取存储在散列表中的数据。该要领一样须要对键值举行散列化,然后才晓得数据存储在数组的什么位置,代码以下:
function get(key){
return this.table[this.betterHash(key)];
}