淺談散列表(哈希表)

散列是一種常用的數據存儲技術,散列後可以快速插入和取用數據,散列使用的數據結構叫散列表也叫哈希表;

一個簡單的散列函數如下:

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)');
}










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章