关于hash的面试题

题目

在这里插入图片描述

选自牛客网

1.java里,HashMap的底层实现原理

  1. 数组结构HashMap 使用一个数组来存储元素。
  2. 哈希函数:通过键的哈希值来确定数组中的位置。
  3. 链表解决冲突:如果多个键的哈希值相同,它们会形成链表。
  4. 红黑树优化:当链表过长时,会转换为红黑树以提高性能。
  5. 动态扩容:当元素太多时,HashMap 会扩大数组大小并重新分配元素。
  6. 加载因子:控制数组何时扩容的参数。
  7. 允许 null 键和值HashMap 可以存储 null 键和 null 值。
  8. 非线程安全HashMap 本身不是线程安全的。

2.如何判断一个HashMap是否已经满了?

在Java中,HashMap并没有直接提供一个方法来判断它是否“满了”,因为HashMap的大小是动态变化的。但是,我们可以通过检查HashMap的当前大小和它的容量之间的关系来间接判断它是否接近满的状态。

HashMap有一个负载因子(load factor),默认值为0.75。这个负载因子定义了HashMap的填满程度。具体来说,当HashMap中元素的数量达到了容量(capacity)乘以负载因子的值时,HashMap会自动进行扩容。这个阈值被称为触发扩容的临界点。

以下是如何检查HashMap是否接近满的状态的方法:

double threshold = map.size() >= map.threshold();

这里的 map.size() 返回HashMap中当前键值对的数量,而 map.threshold() 返回的是HashMap当前的扩容阈值(即容量乘以负载因子)。如果 map.size() 大于或等于 map.threshold(),则意味着HashMap即将进行扩容,可以认为它接近满的状态。

需要注意的是,这个判断只是表示HashMap即将进行扩容,并不意味着它不能再接受新的键值对。在扩容之前,HashMap仍然可以继续添加新的键值对,直到扩容过程真正发生。

如果你想在HashMap达到某个特定大小时采取行动,你可以在添加元素时检查其大小,并在必要时手动触发扩容或其他操作:

if (map.size() >= map.threshold()) {
    // 执行相应的操作,比如扩容、通知或其他逻辑
}

请记住,频繁的扩容操作可能会影响性能,因为它们涉及到重新计算哈希值并将现有元素重新分配到新的数组中。因此,在设计系统时,应考虑初始容量和负载因子,以尽量减少不必要的扩容操作。


3.HashSet如何检查重复

  1. 哈希码计算:当向HashSet添加一个新元素时,首先会计算该元素的哈希码。哈希码是通过调用元素的hashCode()方法得到的。理想情况下,不同的元素应该产生不同的哈希码,但这并不总是可能的,因为哈希码的长度是有限的。

  2. 哈希表位置确定:使用哈希码来确定元素在哈希表中的存储位置。这个过程通常涉及到对哈希码进行某种形式的转换,以便生成一个数组索引。这个转换应该是均匀分布的,以避免或减少哈希冲突。

  3. 哈希冲突处理:如果两个不同的元素产生了相同的哈希码(即发生了哈希冲突),HashSet会将这些元素存储在哈希表的同一个位置,形成一个链表或红黑树(在Java 8及以后的版本中)。

  4. 重复检查:当尝试添加一个新元素时,如果计算出的哈希表位置已经被占用(即发生了哈希冲突),HashSet会遍历该位置上的链表或红黑树,并对每个节点调用equals()方法与新元素进行比较。如果找到了一个相等的元素,HashSet就不会添加新元素,因为它被认为是重复的。

  5. 添加元素:如果新元素没有找到与之相等的元素(即equals()方法没有返回true),HashSet会将新元素添加到哈希表中。

  6. 性能考虑:由于哈希冲突可能导致链表过长,影响性能,Java 8引入了红黑树来优化这种情况。当链表长度超过一定阈值(默认为8)时,链表会转换为红黑树,以提高查找效率。

总之,HashSet通过哈希码快速定位元素的可能位置,并通过equals()方法在发生哈希冲突时精确比较元素的内容,从而有效地检查重复并确保集合中的元素唯一性。


4.HashSet如何判断一个元素是否已经存在.

HashSet在判断一个元素是否已经存在时,同样依赖于元素的哈希码和equals()方法。以下是HashSet判断元素是否存在的详细过程:

  1. 计算哈希码:当查询一个元素是否存在于HashSet中时,首先会计算该元素的哈希码。这个哈希码是通过调用元素的hashCode()方法得到的。

  2. 确定哈希表位置:使用哈希码来确定元素可能在哈希表中的位置。这个过程通常涉及到对哈希码进行某种形式的转换,以便生成一个数组索引。这个转换应该是均匀分布的,以避免或减少哈希冲突。

  3. 哈希冲突处理:如果计算出的哈希表位置上有多个元素(即发生了哈希冲突),HashSet会遍历该位置上的链表或红黑树(在Java 8及以后的版本中)。

  4. 比较元素:对于链表或红黑树中的每个元素,HashSet会调用equals()方法与目标元素进行比较。如果找到了一个相等的元素,HashSet就认为该元素存在于集合中。

  5. 返回结果:如果没有找到相等的元素,或者目标元素的哈希码没有指向任何已存在的元素(即哈希表中对应位置为空),HashSet会认为该元素不存在于集合中。

总结来说,HashSet判断一个元素是否存在的过程如下:

  • 计算元素的哈希码。
  • 使用哈希码确定元素在哈希表中的可能位置。
  • 如果有哈希冲突,遍历该位置上的链表或红黑树。
  • 对于每个遍历到的元素,调用equals()方法与目标元素进行比较。
  • 如果找到相等的元素,则元素存在于集合中;否则,元素不存在于集合中。

这个过程的关键在于hashCode()equals()方法的正确实现,以确保HashSet能够正确且高效地判断元素是否存在。如果hashCode()方法不能提供良好的分散性,或者equals()方法不能正确地比较两个对象的内容,都可能导致HashSet的性能下降或行为不正确。

简单的理解hash

在这个示例中,元素A、D被存储在桶0的链表中,元素B、E被存储在桶2的链表中,元素C、F被存储在桶3的链表中。桶1目前是空的。

  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

布说在见

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值