数据结构与算法-哈希表

news2024/9/23 15:33:10

引言

        在计算机科学中,数据结构与算法是构建高效软件系统的关键基石。其中,哈希表作为一种非常实用的数据结构,以其快速查找、插入和删除等特性,在诸多领域发挥着无可替代的作用。本文将深入探讨哈希表的工作原理、实现细节以及其在实际应用中的价值。

一、什么是哈希表?

        哈希表(Hash Table) 是一种通过哈希函数将键(key)映射到特定数组索引位置的数据结构,以实现对数据的高效存储和检索。通过巧妙地设计哈希函数,使得不同的键能尽可能均匀地分布在整个数组中,从而达到接近于O(1)的时间复杂度进行数据操作的目标。

二、哈希表的工作原理

  1. 哈希函数:哈希表的核心在于哈希函数的设计,它负责将任意长度的键转换为固定范围内的哈希值。优秀的哈希函数应具备以下特点:

    • 确定性:对于相同的键,哈希函数总是返回相同的哈希值。
    • 均匀分布:输入域中任何两个不相同的键,其哈希值冲突的概率尽可能小。
  2. 散列冲突处理:尽管理想情况下每个键都有唯一的哈希值,但实际中往往无法完全避免冲突。解决冲突的常见方法有开放寻址法和链地址法(也称为拉链法):

    • 开放寻址法:当发生冲突时,寻找下一个未被占用的位置存放元素,如线性探测、二次探测或双哈希探测等。
    • 链地址法:每个数组位置对应一个链表,所有哈希值相同的数据项链接在这个位置对应的链表上。
  3. 装载因子:哈希表的装载因子是指已存入表中的元素数量与表的大小之比。合理控制装载因子可以降低冲突概率,提高哈希表性能。

三、哈希表的时间复杂度分析

  • 理想情况:若哈希函数能够完美分散键,并且不存在散列冲突,哈希表的插入、查找和删除操作的时间复杂度均为O(1)。
  • 实际情况:考虑散列冲突,哈希表的操作时间复杂度依赖于哈希函数的质量、冲突处理策略及装载因子等因素。良好的设计下,平均时间复杂度仍可维持在接近O(1)的水平。

四、哈希表的实际应用

哈希表因其高效的查找性能,在众多实际场景中得到了广泛应用:

  1. 数据库索引:许多数据库系统利用哈希表作为内部索引来加速查询过程,尤其在执行点查询时效果显著。

  2. 缓存系统:在内存有限的情况下,哈希表可用于缓存频繁访问的数据,减少磁盘I/O操作,提升系统响应速度。

  3. 编程语言数据结构:诸如Python、Java等现代编程语言中,都内置了哈希表实现的数据结构,如Python的dict和Java的HashMap。

  4. 唯一性验证:在需要确保元素唯一性的场景,如用户ID验证、去重操作等,哈希表能提供快速的检查机制。

  5. 集合与映射操作:哈希表常用于实现集合(Set)、字典(Dictionary)或映射(Map)等抽象数据类型。

五、哈希表的代码实践

1.思路分析

2.代码实践 

1.员工类

//员工
class Emp {
    private int id;
    private String name;
    private String address;
    private Emp next;

    public Emp(int id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    public Emp getNext() {
        return next;
    }

    public void setNext(Emp next) {
        this.next = next;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

2.链表 

//员工
class Emp {
    private int id;
    private String name;
    private String address;
    private Emp next;

    public Emp(int id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    public Emp getNext() {
        return next;
    }

    public void setNext(Emp next) {
        this.next = next;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

3.哈希表 

//管理多条链表
class HashTable {
    private int size;
    private EmpLinkedList[] empLinkedListsArray;

    public HashTable(int size) {
        this.size = size;
        empLinkedListsArray = new EmpLinkedList[size];
//        这里要给数组的每一个链表进行初始化,否则后续会空指针
        for (int i = 0; i < size; i++) {
            empLinkedListsArray[i] = new EmpLinkedList();
        }
    }

    //    添加雇员
    public void add(Emp emp) {
//        根据员工id获取到该员工在哪一个条链表
        int empLinkedListNo = hashFun(emp.getId());
//        将emp添加到该链表中
        empLinkedListsArray[empLinkedListNo].add(emp);
    }

    //    遍历所有的hashtable
    public void list() {
        for (int i = 0; i < empLinkedListsArray.length; i++) {
            empLinkedListsArray[i].show();
        }
    }

    //    查找emp
    public Emp findEmp(int empNo) {
        int empLinkedListNo = hashFun(empNo);
        return empLinkedListsArray[empLinkedListNo].read(empNo);
    }


    //    编写散列函数
    public int hashFun(int empId) {
        return empId % size;
    }
}

六、总结

        哈希表作为一种高性能的数据结构,在实现快速查找、更新和删除等方面表现出色。然而,它的效率取决于哈希函数的设计、冲突处理策略的选择以及装载因子的管理。理解并掌握哈希表的相关知识,不仅有助于我们优化代码实现,还能在多种应用场景中挖掘出更多潜在的性能优势。随着技术的发展,哈希表将继续在数据处理领域扮演重要角色,为我们打造更强大、更高效的软件系统贡献力量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1502754.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt Creator常见问题解决方法

Qt Creator源文件重命名的正确方法 光改文件名是不够的&#xff0c;还要在.pro文件中的SOURCES中把名字改成之后的。 中文乱码&#xff08;字符集设置&#xff09; 菜单栏-工具-选项-设置为utf-8

Reset Verification IP

Reset Verification IP IP 参数及接口 IP 例化界面 相关函数 assert_reset //置位复位信号 < hierarchy_path>.assert_reset();deassert_reset //取消置位复位信号 < hierarchy_path>.deassert_reset();set_master_mode //设置 RST_VIP 模式为 Master < hi…

STM32基本定时功能

1、定时器就是计数器。 2、怎么计数&#xff1f; 3、我们需要有一恒定频率的方波信号&#xff0c;再加上一个寄存器。 4、比如每来一个上升沿信号&#xff0c;寄存器值加1&#xff0c;就可以完成计数。 5、假设方波频率是100Hz&#xff0c;也就是1秒100个脉冲。…

严刑拷打_微服务

文章详情 &#xff1a;&#x1f60a; 作者&#xff1a;Lion J &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_69252724 &#x1f389; 主题&#xff1a; 微服务相关知识 ⏱️ 创作时间&#xff1a;2024年03月8日 ———————————————— 文章目…

[数据结构]队列

1.队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出 FIFO(First In First Out) 入队列&#xff1a;进行插入操作的一端称为队尾 出队列&#xff1a;进行删除操作的一端称为队头 2…

Dynamo3.0.3——六年来最大的更新

Hello大家好&#xff01;我是九哥~ 前几天&#xff0c;Dynamo Core 3.0.0版本发布&#xff0c;迎来了Dynamo六年来最大的一次更新。最大的改变&#xff0c;是更新到了.net8&#xff0c;这回对Dynamo节点包产生不小影响。接下来我们详细看一下都有哪些变化。 首先&#xff0…

【vue.js】文档解读【day 3】 | 列表渲染

如果阅读有疑问的话&#xff0c;欢迎评论或私信&#xff01;&#xff01; 文章目录 列表渲染v-forv-for 与对象在 v-for 里使用范围值template 上的 v-forv-for与v-if通过key管理状态组件上使用v-for数组变化侦测 列表渲染 v-for 在我们想要渲染出一个数组中的元素时&#xf…

node-day3-es6模块化+webpack

模块化 一、模块化分类 回顾node.js模块化&#xff1a; node.js遵循了CommonJS的模块化规范【见下文】&#xff0c;其中&#xff1a; 1.导入其它模块使用require()方法 2.模块对外共享成员使用module.exports对象 模块化的好处&#xff1a; 大家都遵守同样的模块化规范写代…

Only fullscreen opaque activities can request orientation

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 未经允许不得转载 目录 一、导读二、概览三、分析四、 推荐阅…

【电工学笔记】上册第一、二章

电工学 上次考试败在了单位&#xff0c;这次单位 一定要记熟。 第一章 电源或信号源的电压或电流称为激励,它推动电路工作; 由激励所产生的电压和电流称为响应。 复杂电路中,一般无法事先判断某个支路电流的 实际方向或者某个电路元件电压的实际方向 140V/4算不出总电阻的 …

leetcode26---删除有序数组中的重复项

大家好&#xff0c;我是大唐&#xff0c;刚刷完了几道经典的leetcode题&#xff0c;今天给大家分享一道leetcode上面的快慢指针经典题型---删除有序数组中的重复项&#xff0c;我们往下看。 题目描述 给你一个 非严格递增排列 的数组 nums &#xff0c;请你原地删除重复出现的元…

【数据结构】拆分详解 - 排序

文章目录 前言一、排序的概念及其运用  1.1 排序的概念  1.2 排序的运用  1.3 常见的排序算法  1.4 排序算法性能测试对比函数 二、常见排序算法的实现  2.1 插入排序   2.1.1  基本思想   2.1.2  直接插入排序   2.1.3  希尔排序     1. 预排序&am…

Dataset 读取数据

Dataset 读取数据 from torch.utils.data import Dataset from PIL import Image import osclass Mydata(Dataset):def __init__(self,root_dir,label_dir):self.root_dir root_dir #根目录 dataset/trainself.label_dir label_dir #标签的后面链接目录 ants_ima…

ChatGPT 提问没反应了,怎么办?4种方法!试试看

用了将近 1 年的 ChatGPT 昨天下午提问忽然之间没反应了&#xff0c;有点失落&#xff0c;我原本以为是账号到期了呢。 之后&#xff0c;尝试用谷歌邮箱注册登录也不行。 打开调试一看&#xff0c;接口状态 403 &#xff0c;没有权限了&#xff0c;logout。 怎么办呢&#xf…

2023年12月CCF-GESP编程能力等级认证Python编程七级真题解析

本文收录于专栏《Python等级认证CCF-GESP真题解析》,专栏总目录・点这里 一、单选题(每题 2 分,共 30 分) 第1题 假设变量 x 为 float 类型,如果下面代码输入为 100,输出最接近( )。 A.0 B.-5 C.-8 D.8 答案:B 第2题 对于下面动态规划方法实现的函数,以下选项中…

【Nestjs实操】服务依赖注入

在开始学习之前&#xff0c;我们首先准备下开发环境&#xff1a; Node&#xff1a;16.20.2包管理器&#xff1a;pnpmnestjs版本&#xff1a;10.2.1全局安装nestjs命令行&#xff1a;pnpm add -g nestjs/cli 一、初始化项目 执行nest new nestjs-blog&#xff0c;系统会自动创…

关于 JVM

1、请你谈谈你对JVM的理解&#xff1f; JVM由JVM运行时数据区&#xff08;图示中蓝色框包含部分&#xff09;、执行引擎、本地库接口、本地方法库组成。 JVM运行时数据区&#xff0c;分为方法区、堆、虚拟机栈、本地方法栈和程序计数器。 1.方法区 Java 虚拟机规范中定…

黑马点评-异步秒杀实现

异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是…

Draco点云压缩测试

ref&#xff1a;https://github.com/google/dracohttps://codelabs.developers.google.com/codelabs/draco-3d/index.html#6 Draco Draco 是一个用于编码压缩和解压缩 3D 几何网格和点云的库&#xff0c;从而改进 3D 图形的存储和传输该代码支持压缩点、连接信息、纹理坐标、颜…

个人代码分享(底层模板函数和三大模板)2024.3.6

源码&#xff1a;&#xff08;百度网盘&#xff09; 链接&#xff1a;https://pan.baidu.com/s/1jdfrQOGCWJaQgSUPEWcfdw?pwd1234 提取码&#xff1a;1234 说明&#xff1a; 从复习到应用所有学到的东西去做真题&#xff0c;笔者对于之前发过的文章里面的代码有着很多改动&…