Java高频面试之集合-15

devtools/2025/3/21 4:30:41/

hello啊,各位观众姥爷们!!!本baby今天来报道了!哈哈哈哈哈嗝🐶

面试官:解决哈希冲突有哪些方法?


1. 开放寻址法(Open Addressing)

核心思想:当哈希冲突发生时,通过特定规则探测下一个空闲槽位存储数据。

方法分类
  • 线性探测(Linear Probing)

    • 规则:冲突后顺序查找下一个槽位,公式:(hash(key) + i) % sizei为步长,初始为1,逐步递增)。
    • 优点:实现简单,无需额外数据结构。
    • 缺点:易产生聚集(Clustering),导致查找效率降低。
  • 二次探测(Quadratic Probing)

    • 规则:冲突后按二次方步长探测,公式:(hash(key) + i²) % size
    • 优点:减少聚集现象。
    • 缺点:可能导致二次聚集,且需保证哈希表大小为质数以覆盖所有槽位。
  • 双重哈希(Double Hashing)

    • 规则:使用第二个哈希函数计算步长,公式:(hash1(key) + i * hash2(key)) % size
    • 优点:探测序列分散,减少聚集。
    • 缺点:需设计两个独立哈希函数。

适用场景:内存敏感场景(如嵌入式系统),无需额外存储指针。


2. 链地址法(Chaining)

核心思想:每个哈希槽位维护一个链表(或树),冲突元素追加到同一槽位的链表中。

实现方式
  • 链表(LinkedList)

    • 操作:冲突元素插入链表尾部,查找需遍历链表。
    • 优点:实现简单,动态扩展。
    • 缺点:链表过长时查找退化为O(n)。
  • 红黑树(Java HashMap优化)

    • 规则:链表长度超过阈值(如8)时,转为红黑树,查找效率提升至O(log n)。
    • 优点:平衡查找效率与内存开销。
    • 缺点:树结构维护复杂度高。

适用场景:通用场景(如Java HashMap),适合频繁插入和删除。


3. 再哈希法(Rehashing)

核心思想:使用多个哈希函数,冲突时按顺序尝试不同哈希函数,直到找到空槽。

  • 优点:减少冲突概率。
  • 缺点:需设计多个高效哈希函数,实现复杂。
  • 典型应用:分布式系统的一致性哈希。

4. 建立公共溢出区(Overflow Area)

核心思想:将哈希表分为主表和溢出表,冲突元素存入溢出表。

  • 优点:主表结构清晰,实现简单。
  • 缺点:溢出表可能成为性能瓶颈。
  • 适用场景:小型哈希表或固定数据集。

5. 完美哈希(Perfect Hashing)

核心思想:通过特殊构造的哈希函数,确保静态数据集无冲突。

  • 优点:查找时间复杂度严格O(1)。
  • 缺点:构造复杂,仅适用于静态数据(如编译器符号表)。
  • 实现方式:两级哈希表,第一级哈希到桶,第二级桶内无冲突。

6. 动态扩容(Dynamic Resizing)

核心思想:当负载因子(元素数/容量)超过阈值时,扩容哈希表并重新哈希所有元素。

  • 扩容策略:容量通常翻倍(如Java HashMap)。
  • 优点:降低冲突概率,维持高效操作。
  • 缺点:扩容耗时,需重新哈希所有元素。

方法对比与选型建议

方法时间复杂度空间复杂度适用场景
开放寻址法平均O(1),最差O(n)内存敏感,低负载场景
链地址法平均O(1),最差O(n)中(指针开销)通用场景,高冲突容忍
再哈希法平均O(1)需要高哈希函数设计
公共溢出区平均O(1),最差O(n)小型或静态数据集
完美哈希O(1)静态数据集(如字典、符号表)
动态扩容分摊O(1)动态数据集,需平衡负载因子

🐮🐎

  • 开放寻址法:适合内存紧凑场景,但需处理聚集问题。
  • 链地址法:灵活通用,结合红黑树优化后适合高并发场景。
  • 完美哈希:静态数据集的最佳选择,但构造复杂。
  • 动态扩容:维持低负载因子,是多数现代哈希表的基础机制。

实际应用示例

  • Java HashMap:链地址法 + 动态扩容 + 红黑树优化。
  • Redis Hash:链地址法 + 渐进式扩容。

在这里插入图片描述


http://www.ppmy.cn/devtools/168797.html

相关文章

【Go】函数闭包、堆和栈的概念

闭包 闭包机制解析 在函数式编程中,闭包(Closure) 是一种特殊的函数结构,其核心特性是能够捕获并持有外部函数的上下文环境变量。这一机制打破了传统函数中局部变量的生命周期规则: 常规局部变量 在函数被调用时创建…

蓝桥杯备考:特殊01背包问题——》集合subset

我们划分成两个集合,实际上我们只需要看一部分就行了,也就是从集合的所有元素里挑出恰好满足集合总和的一半儿,当然,如果我们的集合总和是奇数的话,我们是无论如何也挑不出刚好一半儿的,因为我们没有小数&a…

【C++———IO流】

听专情的古人,把美言留给最爱的人........................................................................................ 文章目录 前言 一、【C/C IO流】 1、【C语言的输入与输出】 2、【CIO流引入】 二、【C标准IO流——】 2.1、【cin&&cout】 2.2…

Vue渲染函数 - render 函数

文章目录 Vue渲染函数 - render 函数1. 什么是 render 函数2、页面展示过程3、render 函数的参数4. 如何使用(1)基本渲染(2)传递属性和事件(3)条件渲染 5. render 函数的实际使用6.View Design 组件中的使用…

Git——分布式版本控制工具使用教程

本文主要介绍两种版本控制工具——SVN和Git的概念,接着会讲到Git的安装,Git常用的命令,以及怎么在Vscode中使用Git。帮助新手小白快速上手Git。如果想直接上手用Vscode操作远程仓库则直接看7和9即可! 目录 1. SVN和Git介绍 1.1 …

PyTorch中,将`DataLoader`加载的数据高效传输到GPU

一、数据加载到GPU的核心步骤 数据预处理与张量转换 若原始数据为NumPy数组或Python列表,需先转换为PyTorch张量: X_tensor torch.from_numpy(X).float() # 转换为浮点张量 y_tensor torch.from_numpy(y).long() # 分类任务常用长整型显式指定设备&…

《Linux 网络架构:基于 TCP 协议的多人聊天系统搭建详解》

一、系统概述 本系统是一个基于 TCP 协议的多人聊天系统,由一个服务器和多个客户端组成。客户端可以连接到服务器,向服务器发送消息,服务器接收到消息后将其转发给其他客户端,实现多人之间的实时聊天。系统使用 C 语言编写&#x…

k8s中的组件

1.namespace Namespace 用于将集群资源划分为不同的逻辑组&#xff0c;方便管理和隔离 kubectl get namespace 查看所有逻辑组 kubectl describe namespace <namespace-name> 查看某个逻辑组信息详情 kubectl create namespace ... 创建逻辑组 kubectl delete names…