散列是一种常用的数据存储技术,散列后可以快速插入和取用数据,散列使用的数据结构叫散列表也叫哈希表;
一个简单的散列函数如下:
function HashTable(){
this.table = new Array(137);
this.simpleHash = simpleHash;
//this.betterHash = betterHash;
this.showDistro = showDistro;
this.put = put;
}
function put(key, data) {
var pos = this.simpleHash(key);
this.table[pos] = data;
}
//function get(key) {
// return this.table[this.betterHash(key)];
//}
function simpleHash(data){
var total = 0;
for(var i = 0; i < data.length; ++i){
total += data.charCodeAt(i)
}
return total % this.table.length;
}
function showDistro() {
for(var i =0; i < this.table.length; ++i){
if(this.table[i] != undefined){
print(i + ":" + this.table[i])
}
}
}
这种方式不可避免的出现重复的情况,也叫‘碰撞’,可以使用霍纳算法来避免,如下:
//霍纳算法
function betterHash(string) {
const H = 37;
var total = 0;
for(var i =0; i < string.length; ++i){
total += H*total + string.charCodeAt(i);
}
total = total % this.table.length;
if(total < 0) {
total += this.table.length - 1;
}
return parseInt(total);
}
这种做法只是临时的,碰撞处理常用的有两种解决方案,开链法、线性探测法:
开链法说白了就是个二维数组,把相同的以数组形式存放,如下:
//开链法
function put(key, data){
var pos = this.betterHash(key);
var index = 0;
if(this.table[pos][index] == undefined){
this.table[pos][index+1] = data;
}
++index;
else {
while(this.table[pos][index] != undefined) {
++ index;
}
this.table[pos][index + 1] = data;
}
}
function get(key){
var index = 0;
var hash = this.betterHash(key);
if(this.table[pos][index] = key){
return this.table[pos][index+1];
}
index += 2;
else{
while(this.table[pos][index] != key){
index += 2;
}
return this.table[pos][index+1];
}
return undefined;
}
线性探测法说白了就是出现重复时,检查下一个位置,若为空则使用,不为空再下一位置
//线性探测法
function put(key, data){
var pos = this.betterHash(key);
if(this.table[pos]==undefined){
this.table[pos] = key;
this.values[pos] = data;
}
else{
while(this.table[pos] != undefined){
pos++;
this.table[pos] = key;
this.values[pos] = data;
}
}
}
function get(key){
var hash = -1;
hash = this.betterHash(key);
if(hash > -1){
for(var i = hash; this.table[hash] != undefined; i++){
if(this.table[hash] == key){
return this.values[hash];
}
}
}
return undefined;
}
具体选择开链法还是线性探测法,主要根据以下这个公式判断:
如果数组的大小是待存储数据个数的1.5倍使用开链法,如果数组的大小是待存储数据的两倍及两倍以上,使用线性探测法;(ps:这公式怎么得出,就不详说了)
以下是一个简单的案例,通讯录录入:人名对应号码
var pnumbers = new HashTable();
var name, number;
for(var i = 0; i < 3; i++) {
putstr('Enter a name (spce to quit):');
name = readline();
putstr('Enter a number');
number = readline();
}
pnumbers.put(name, number);
name = '';
putstr('Name for number (Enter quit to stop):');
while(name != 'quit'){
name = readline();
if(name == 'quit'){
break;
}
print(name + 's number is ' + pnumbers.get(name));
putstr('Name for number (Enter quit to stop)');
}