数据结构基础四·哈希表

JavaScript数据结构基础学习

哈希表

现有的JavaScript“对象”都是基于哈希表实现的
哈希表提供了快速插入和查找操作,无论哈希表中总数有多少条数据,插入和查找的时间复杂度都是O(1)

哈希表引入了哈希函数,将输入的键名通过哈希函数转换成索引

在这里插入图片描述

为什么要把键名转换为索引不能直接存储呢?

1.有时候进行数据存储时,数据并没有设置键名。不允许字符串作为索引值
2.键名是用户动态设置的,不安全,通过key直接存储值导致哈希表内存分配不均
哈希表内存分配不均导致内存不足,转成索引值就是分配均匀的了(但是长度固定会导致哈希冲突)

查找第一个重复字符

使用for循环 时间复杂度O(n^2)
const str = 'hello world'
for(let i = 0;i<str.length;i++){
	for(j = i+1;j<str.length;j++){
		if(str[i] === str[j]0{
			return str[i]
		}
	}
}
	
使用哈希表

1.可以直接使用对象

	const str = 'hello world'
function findFirst(str) {
    if (str.length < 1) return new Error('字符串长度为空')
	const table = {}
	for(const word of str){
		if(table[word] ){
			return word
		}
		table[word] = 1
	}
}
  1. 使用Map对象
	function findFirst(str){
		  if (str.length < 1) return new Error('字符串长度为空')
		  const map = new Map()
		  for(const word of str){
			if(map.get(word){
				return word
			}	
			map.set(word,1)
		}
	}

3.自定义哈希函数使用

	class HashTable{
		constructor(){
			this.size = 1000 // 哈希表需要提前定义长度
			this.buckets = Array(1000).fill(null)
		}
		//将索引转换为索引值
		hash(key){
			let hash = 0;
			for( const char of key){
				hash+= char.charCodeAt(0)
				//charCodeAt() 方法可返回指定位置的字符的 Unicode 编码。这个返回值是 0 - 65535 之间的整数。
			}
			return hash % this.size
		}
		set(key,value){
			const keyHah = this.hash(key)
			this.buckets[keyHash] = value
		}
		get(key){
			const keyHahs= this.hash(key)
			return this.buckets[keyHash]
		}
	}
哈希碰撞
  • 哈希表必须规定长度,size内存不足的时候,会导致不同的key,返回同一个hash值。后面的值会覆盖前面的值
解决哈希碰撞链地址法

每一项都变成数组,相同的hash值push进去保持key值

	class HashTable{
		constructor(){
			this.size = 1000
			this.buckets = Array(1000).fill(null)
		}
		hash(key){
			let hash = 0;
			for(const char of key){
				hash =+ char.charCodeAt(0)
			}
			return hash % this.size
		}
		set(key,value){
			const keyHash = this.hash(key)
			const bucketArray = this.buckets[keyHash]
			const storedElement = bucketArray.find((element)=>{
				return element.key === keyHash
			})
			if(storedElement){
				storedElement.val = value
			}else{
			this.buckets.push({key:key,val:value})
			}
		}
		get(key){
			const keyHash = this.hash(key)
			const bucketArray = this.buckets[keyHash]
			const storedElement = bucketArray.find((element)=>{
				return element.key === key
			})
			return storedElement
		}
		showInfo(){
			for(const key in this.buckets){
				console.log(key,this.buckets[key])
			}
		}
	}
	const table = new HashTable()
	for (const char of 'abcde') {
	    table.set(char, char)
	}
	for (const char of 'fghijk') {
	    table.set(char, char)
	}
	for (const char of 'lmnopq') {
	    table.set(char, char)
	}
	
	console.log(table.showInfo())

在这里插入图片描述

解决哈希碰撞开放地址法

避免冲突,一旦冲突就去寻找哈希表中没有值的插槽

	class HashTable{
		constructor(){
			this.size = 1000
			this.buckets = Array(1000).fill(null)
		}
		hash(key){
			let hash = 0;
			for(const char of key){
				hash += char.charCodeAt(0)
			}
			return hash % this.size
		}
		set(key,value){
			let keyHash = this.hash(key)
			if(this.buckets[keyHash] === null || this.buckets[keyHash].key === key){
				this.buckets[keyHash] = {key:key,value:value}
			}
			else{
				while(this.buckets[keyHash] !== null){
					keyHash++
				}
				this.buckets[keyHash] = {key:key,value:value}
			}
		}
		get(key){
			let keyHash = this.hash(key)
			for(let i = keyHash;i<this.buckets.length;i++){
				if(!this.buckets[i]) continue;
				if(this.buckets[i].key === key){
					return this.buckets[i].value
				}
			}
			return undefined
		}
	}
内置js对象底层其实就是哈希表,只是它解决了哈希冲突
哈希表数组对象
元素访问理论上O(1)/ 哈希碰撞O(n)O(1)O(1)
末尾插入理论上O(1)/ 哈希碰撞O(n)O(1)O(1)
头部插入理论上O(1)/ 哈希碰撞O(n)O(n)O(1)
中间插入理论上O(1)/ 哈希碰撞O(n)O(n)O(1)
元素搜索理论上O(1)/ 哈希碰撞O(n)O(n)O(1)

单纯存储数据使用数组,如果想要考虑关联性的话使用哈希表

是否任何场景都可使用对象 ? NO!
  • 某些用例中,管理键值对会 导致冗余代码
  • 对于数组/列表循环通常更容易
  • 对于很多数组/列表,不需要在开头或中间插入大量内容或进行大量搜索
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值