散列是一種常用的數據存儲技術,散列後可以快速插入和取用數據,散列使用的數據結構叫散列表也叫哈希表;
一個簡單的散列函數如下:
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)');
}