JavaScript——哈希表(鏈地址法)

JavaScript——哈希表(鏈地址法)

/*哈希表類(鏈地址法)
哈希表裏每個索引對應的元素爲一個桶(bucket),每個桶爲一個數組。
桶裏的每個元素也是一個數組,稱爲元組(tuple)
每個元組由key和value組成
哈希表整體結構:[[[key,value],[key,value],...],[[key,value],[key,value],...],...]
*/
function HashTable(){
	this.storage = []
	//當前元素個數
	this.count = 0
	//哈希表長度(質數)
	this.limit = 7
	/*
	* 哈希函數,返回字符串對應的索引
	* 參數1:key , 參數2:哈希表的長度
	*/ 
	HashTable.prototype.hashFunc = function(key, size){
		let hashCode = 0
		key = String(key)
		//霍納算法,計算hashCode的值
		for (let i =0; i < key.length; i++){
			hashCode = 37 * hashCode + key.charCodeAt(i)
		}
		//求餘,返回小於哈希表長度的索引
		let index = hashCode % size
		return index
	}
	/*
	* 1.插入或修改數據
	*/ 
	HashTable.prototype.put = function(key, value){
		let index = this.hashFunc(key, this.limit)
		//取出對應索引的元素(桶)
		let bucket = this.storage[index]
		//1. 桶不爲空的情況
		if (bucket){
			//尋找對應的key是否已經存在
			for (let i = 0; i < bucket.length; i++){
				let tuple = bucket[i]
				//對應key已存在則將原value覆蓋
				if (tuple[0] == key){
					tuple[1] = value
					return
				}
			}
			//對應key不存在則往桶裏添加一條新數據
			bucket.push([key, value])
		}
		//2. 桶爲空的情況
		else{
			//創建一個新的桶
			bucket = []
			this.storage[index] = bucket
			bucket.push([key, value])
		}
		//元素個數+1
		this.count += 1
		//判斷哈希表是否需要擴容(當前元素個數大於總長度的0.75時需要擴容,否則操作效率會變低)
		if (this.count > this.limit * 0.75){
			let newLimit = this.getPrime(this.limit * 2)
			this.resize(newLimit)
		}
	}
	/*
	* 2.查找數據
	*/ 
	HashTable.prototype.get = function(key){
		let index = this.hashFunc(key, this.limit)
		let bucket = this.storage[index]
		//桶不爲空
		if (bucket){
			for (let i =0; i < bucket.length; i++){
				let tuple = bucket[i]
				if (tuple[0] == key){
					return tuple[1]
				}
			}
		}
		//桶爲空或遍歷完都沒查找到
		return null
	}
	/*
	* 3. 刪除數據
	*/ 
	HashTable.prototype.remove = function(key){
		let index = this.hashFunc(key, this.limit)
		let bucket = this.storage[index]
		//桶不爲空
		if (bucket){
			for (let i = 0; i < bucket.length; i++){
				let tuple = bucket[i]
				if (tuple[0] == key){
					//刪除數據,哈希表元素個數-1
					bucket.splice(i, 1)
					this.count -= 1
					//判斷哈希表是否需要縮容(當前元素個數小於總長度的0.25時需要縮容,但長度不能小於7)
					if (this.limit > 7 && (this.count < this.limit * 0.25)){
						let newLimit = this.getPrime(parseInt(this.limit / 2))
						this.resize(newLimit)
					}
					//返回刪除的數據
					return tuple[1]
				}
			}
		}
		//桶爲空或遍歷完都沒查找到要刪除的數據
		return null
	}
	/*
	* 4.質數判斷
	*/
	HashTable.prototype.isPrime = function(num){
		let sqrtNum = parseInt(Math.sqrt(num))
		for (let i = 2; i <= sqrtNum; i++){
			if (num % i == 0){
				return false
			}
		}
		return true
	}
	/*
	* 5.獲取質數
	*/ 
	HashTable.prototype.getPrime = function(num){
		while (this.isPrime(num) == false){
			num += 1
		}
		return num
	}
	/*
	* 6. 哈希表擴容或縮容
	*/
	HashTable.prototype.resize = function(newLimit){
		//保存原哈希表數據
		let oldStorage = this.storage
		//清空原哈希表數據
		this.storage = []
		this.count = 0
		this.limit = newLimit
		//遍歷得到所有桶
		for (let i =0; i < oldStorage.length; i++){
			let bucket = oldStorage[i]
			//判斷桶裏否有數據
			if (bucket){
				//將桶裏的所有數據(元組)重新添加到新哈希表
				for (let y = 0; y < bucket.length; y++){
					let tuple = bucket[y]
					this.put(tuple[0], tuple[1])
				}
			}
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章