数据结构 哈希表

先看一下下面的这张图(哈希表的一种实现)(奇丑无比0.0)
在这里插入图片描述

散列(Hash):散列的思想是将条目(键/值对)分布在一系列存储桶(bucket)中。给定一个键(key),再通过算法计算出索引(index),该索引显示条目的位置。通常可以分为两步完成:

hash = hashfunc(key)        //计算key对应hash值
index = hash % array_size   //通过取模"%"使index始终位于0~array_size-1(即索引范围始终位于数组中)

负载因子(factor):负载因子=已经插入的数据数量/可以插入的数据总量。对于固定数量的桶,查找时间会随着条目数量的增加而增加,因此无法实现所需的恒定时间。为了实现这个恒定时间,可以在达到负载因子时进行扩容。

扩容:强制散列所有条目,array_size变大了(通常是两倍),从而使index的范围变广了,hash值不同但index相同的概率减小了(如17、33对16取模结果为1、1;而17、33对32取模结果为17、1,entry分布在bucket中分布更均匀了是不是),那index依然相同该怎么办呢,这里(仅)介绍一下链地址法

System.out.println(17%32);

链地址法:长得像上面图示那样,哈希表操作的时间是找到bucket的时间(是常数)加上列表操作的时间。bucket里可以放第一个条目(entry)的索引,也可以放第一个条目,HashMap属于后者,这样做是因为在大多数情况下,指针遍历的次数可以减少1,从而提高访问的缓存效率(该缓存指的是内存,因为链表无法使用CPU缓存,链表无法使用CPU缓存是因为CPU缓存需要连续的地址空间)但缺点是空bucket与entry占用相同的空间(网上是这么说的,但是根据HashMap的情况来看,HashMap会初始化entry数组,但存储在数组内的entry没有空参构造函数,所以最终的结果为null而非初始化的entry,所以缺点方面还是不要太钻牛角尖0.0)

时钟周期(有点跑题了0.0):时钟周期是CPU工作的最小时间单位,1 / 时钟周期 =工作频率,而CPU缓存工作所需要的时钟周期少,内存需要的时钟周期多,由此可见CPU在处理CPU缓存和内存中的相同任务时,所用的时间是不一样的(这也是为什么访问数组比访问链表快的原因之一!详见数组、链表对于内存及CPU访问缓存机制)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
哈希表是一种基于哈希函数进行快速查找的数据结构,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。哈希表的设计思路如下: 1. 哈希函数的设计:哈希函数是哈希表的核心,它将关键字映射到哈希表中的位置。一个好的哈希函数应该具有以下特点: - 映射范围广:哈希函数应该将关键字均匀地映射到哈希表中的位置,避免出现大量的哈希冲突。 - 计算速度快:哈希函数的计算速度应该尽可能快,以提高哈希表的访问速度。 - 低冲突率:哈希函数应该尽可能地避免哈希冲突,以提高哈希表的访问效率。 2. 哈希冲突的解决:由于哈希函数的映射范围是有限的,所以不同的关键字可能会映射到同一个位置,这就是哈希冲突。哈希冲突的解决方法有以下两种: - 链地址法:将哈希表中的每个位置都连接一个链表,当发生哈希冲突时,将新的关键字插入到链表的末尾。 - 开放地址法:当发生哈希冲突时,通过某种算法找到哈希表中的下一个空位置,将新的关键字插入到该位置。 3. 哈希表的增删查改操作:哈希表的增删查改操作都需要先通过哈希函数找到关键字在哈希表中的位置,然后再进行相应的操作。具体操作如下: - 插入操作:将新的关键字插入到哈希表中的对应位置,如果发生哈希冲突,则按照链地址法或开放地址法进行解决。 - 删除操作:将关键字从哈希表中对应位置删除,如果该位置上有链表,则需要遍历链表找到对应的关键字进行删除。 - 查找操作:通过哈希函数找到关键字在哈希表中的位置,如果该位置上有链表,则需要遍历链表找到对应的关键字进行查找。 - 修改操作:通过哈希函数找到关键字在哈希表中的位置,如果该位置上有链表,则需要遍历链表找到对应的关键字进行修改。 下面是一个使用链地址法实现的哈希表的Python代码示例: ```python class ListNode: def __init__(self, key=None, value=None): self.key = key self.value = value self.next = None class MyHashMap: def __init__(self): self.size = 1000 self.table = [None] * self.size def _hash(self, key): return key % self.size def put(self, key, value): index = self._hash(key) if not self.table[index]: self.table[index] = ListNode(key, value) else: node = self.table[index] while node: if node.key == key: node.value = value return if not node.next: break node = node.next node.next = ListNode(key, value) def get(self, key): index = self._hash(key) node = self.table[index] while node: if node.key == key: return node.value node = node.next return -1 def remove(self, key): index = self._hash(key) node = prev = self.table[index] if not node: return if node.key == key: self.table[index] = node.next else: node = node.next while node: if node.key == key: prev.next = node.next break node, prev = node.next, prev.next ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值