当前位置: 首页 > news >正文

数据结构之哈希表

哈希表(散列表)

出现的原因

在顺序表中查找时,需要从表头开始,依次遍历比较a[i]与key的值是否相等,直到相等才返回索引i;在有序表中查找时,我们经常使用的是二分查找,通过比较key与a[i]的大小来折半查找,直到相等时才返回索引i。最终通过索引找到我们要找的元素。

但是,这两种方法的效率都依赖于查找中比较的次数。我们有一种想法,能不能不经过比较,而是直接通过关键字key一次得到所要的结果呢?这时,就有了散列表查找。

数据结构模型

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。

HashTable模型

代码实现

  • HashTable
package org.example.data.structure.hashtable;import java.util.Objects;/*** @author xzy* @since 2024/9/15 11:03*/
public class HashTable {private LinkedList[] linkedLists;public HashTable() {linkedLists = new LinkedList[8];for (int i = 0; i < linkedLists.length; i++) {linkedLists[i] = new LinkedList();}}public HashTable(int size) {if (size < 0) {throw new RuntimeException("未知异常");}linkedLists = new LinkedList[size];for (int i = 0; i < linkedLists.length; i++) {linkedLists[i] = new LinkedList();}}public void add(Person person) {int i = hash(person.getId());LinkedList linkedList = linkedLists[i];PersonNode node = new PersonNode();node.setData(person);linkedList.add(node);}public void delete(int id) {int i = hash(id);LinkedList linkedList = linkedLists[i];linkedList.delete(id);}public void update(Person person) {int i = hash(person.getId());LinkedList linkedList = linkedLists[i];linkedList.update(person);}public Person getById(int id) {int i = hash(id);LinkedList linkedList = linkedLists[i];return linkedList.getById(id);}public Person[] list() {Person[] personArr = new Person[linkedLists.length * 10];int i = 0;for (LinkedList linkedList : linkedLists) {Person[] list = linkedList.list();if (Objects.nonNull(list)) {for (Person person : list) {if (Objects.nonNull(person)) {personArr[i] = person;i++;}}}}return personArr;}private int hash(int id) {// 计算落到哪个链表中return id % linkedLists.length;}}
  • 链表实现
package org.example.data.structure.hashtable;import java.util.Objects;/*** @author xzy* @since 2024/9/15 10:04*/
public class LinkedList {private PersonNode head;public void add(PersonNode node) {if (Objects.isNull(head)) {// 链表未初始化head = node;return;}// 获取最后一个节点PersonNode tempNode = head;while (Objects.nonNull(tempNode.getNext())) {tempNode = tempNode.getNext();}tempNode.setNext(node);}public void delete(int id) {if (Objects.isNull(head)) {System.out.println("链表为空, 忽略删除操作");return;}// 先判断是否只有一个节点if (Objects.isNull(head.getNext())) {if (head.getData().getId() == id) {head = null;}} else {PersonNode tempNode = head;// 遍历节点while (true) {PersonNode next = tempNode.getNext();if (Objects.isNull(next)) {System.out.println("未找到对应的节点进行删除");break;} else {if (next.getData().getId() == id) {tempNode.setNext(next.getNext());break;} else {tempNode = next;}}}}}public void update(Person person) {if (Objects.isNull(head)) {System.out.println("链表为空, 不处理");return;}PersonNode tempNode = head;while (true) {if (Objects.isNull(tempNode)) {System.out.println("未找对需要更新的数据, 不处理");break;}if (tempNode.getData().getId() == person.getId()) {Person data = tempNode.getData();data.setName(person.getName());tempNode.setData(data);break;} else {tempNode = tempNode.getNext();}}}public Person getById(int id) {PersonNode tempNode = head;while (true) {if (Objects.isNull(tempNode)) {System.out.println("未找对需要更新的数据, 不处理");return null;}if (tempNode.getData().getId() == id) {return tempNode.getData();} else {tempNode = tempNode.getNext();}}}public Person[] list() {if (Objects.isNull(head)) {return new Person[0];}Person[] personArr = new Person[10];int i = 0;PersonNode tempNode = head;while (true) {if (Objects.nonNull(tempNode)) {personArr[i] = tempNode.getData();i++;tempNode = tempNode.getNext();} else {break;}}return personArr;}
}

后续优化

  • 未解决哈希冲突(主要是因为hash()实现过于简单)
  • 链表中未实现有序(可在插入时,在单链表中先排序再插入)

源码与测试案例

gitee地址

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Redis 与数据库数据一致性保证详解
  • 微服务实战系列之玩转Docker(十五)
  • Github 2024-09-16 开源项目周报 Top14
  • iOS 18 將在 9 月 16 日正式上線
  • 鸡蛋检测系统源码分享
  • leaflet【十】实时增加轨迹点轨迹回放效果实现
  • BSV区块链上的覆盖网络服务现已开放公测
  • mysql DBA常用的sql
  • 【JS逆向分析】某药品网站价格(Price)解密
  • AI基础 L22 Uncertainty over Time I 时间的不确定性
  • ELK预警方案:API+XXLJob
  • python画图|同时输出二维和三维图
  • 学习使用在windows系统上安装vue前端框架以及环境配置图文教程
  • Python快速入门 —— 第二节:函数与控制语句
  • macOS上谷歌浏览器的十大隐藏功能
  • hexo+github搭建个人博客
  • [数据结构]链表的实现在PHP中
  • 【402天】跃迁之路——程序员高效学习方法论探索系列(实验阶段159-2018.03.14)...
  • 【翻译】babel对TC39装饰器草案的实现
  • oldjun 检测网站的经验
  • Python进阶细节
  • Vue官网教程学习过程中值得记录的一些事情
  • 简析gRPC client 连接管理
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 浅谈web中前端模板引擎的使用
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 一道闭包题引发的思考
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 运行时添加log4j2的appender
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ‌U盘闪一下就没了?‌如何有效恢复数据
  • # 透过事物看本质的能力怎么培养?
  • #我与Java虚拟机的故事#连载10: 如何在阿里、腾讯、百度、及字节跳动等公司面试中脱颖而出...
  • #我与虚拟机的故事#连载20:周志明虚拟机第 3 版:到底值不值得买?
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (LLM) 很笨
  • (二)学习JVM —— 垃圾回收机制
  • (蓝桥杯每日一题)love
  • (五)关系数据库标准语言SQL
  • (一)RocketMQ初步认识
  • (源码分析)springsecurity认证授权
  • (自适应手机端)行业协会机构网站模板
  • .bat文件调用java类的main方法
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .NET C# 使用 iText 生成PDF
  • .net core控制台应用程序初识
  • .NET6实现破解Modbus poll点表配置文件
  • .NET开源项目介绍及资源推荐:数据持久层
  • .NET实现之(自动更新)
  • ??如何把JavaScript脚本中的参数传到java代码段中
  • @Bean有哪些属性
  • @Transactional事务注解内含乾坤?
  • [ Linux 长征路第五篇 ] make/Makefile Linux项目自动化创建工具
  • [001-03-007].第07节:Redis中的管道