哈希表(Hash Table)-----运用实例【通过哈希表来管理雇员信息】(java详解) (✧∇✧)

目录

一.哈希表简介:

实例介绍:

 类的创建与说明:

各功能图示:

 1.class HashTab{  }; 

2. class EmpLinkedList{ };

3. class Emp{ };

4.测试:

运行结果:

最后,完整代码:


一.哈希表简介:

哈希表(Hash Table):也叫做散列表。是根据关键码值(Key Value)直接进行访问的数据结构。

哈希表通过「键 key 」和「映射函数 Hash(key) 」计算出对应的「值 value」,把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做「哈希函数(散列函数)」,存放记录的数组叫做「哈希表(散列表)」。

 使用方法:

  • 向哈希表中插入一个关键码值:哈希函数决定该关键字的对应值应该存放到表中的哪个区块,并将对应值存放到该区块中。

  • 在哈希表中搜索一个关键码值:使用相同的哈希函数从哈希表中查找对应的区块,并在特定的区块搜索该关键字对应的值。

  • 实现哈希表: 数组+链表 或者  数组+二叉树

 原理示意图:

 由于这篇博客主要讲应用栗子,就不做哈希表的过多说明,如有需要,可以看看这篇博客:数据结构之—哈希表_哈希表数据结构-CSDN博客

实例介绍:

 有一个公司,当有新的员工来报道时,要求将该员工的信息加入 (id,性别,年龄,名字,住址..),当输入该员工的id时,要求查找到该员工的 所有信息。这里用数组+链表来实现

 类的创建与说明:

  • class HashTab{  }; 
    创建HashTab管理多条链表
    
  • class EmpLinkedList{ };
    创建EmpLinkedList ,表示链表
  • class Emp{ };
    创建Emp,表示雇员

各功能图示:

 

 1.class HashTab{  }; 

//创建HashTab 管理多条链表
class HashTab {private EmpLinkedList[] empLinkedListArray;private int size; //表示有多少条链表//构造器public HashTab(int size) {this.size = size;//初始化empLinkedListArrayempLinkedListArray = new EmpLinkedList[size];for(int i = 0; i < size; i++) {empLinkedListArray[i] = new EmpLinkedList();}}//添加雇员public void add(Emp emp) {//根据员工的id ,得到该员工应当添加到哪条链表int empLinkedListNO = hashFun(emp.id);//将emp 添加到对应的链表中empLinkedListArray[empLinkedListNO].add(emp);}//遍历所有的链表,遍历hashtabpublic void list() {for(int i = 0; i < size; i++) {empLinkedListArray[i].list(i);}}//根据输入的id,查找雇员public void findEmpById(int id) {//使用散列函数确定到哪条链表查找int empLinkedListNO = hashFun(id);Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);if(emp != null) {//找到System.out.printf("在第%d条链表中找到 雇员 id = %d\n", (empLinkedListNO + 1), id);}else{System.out.println("在哈希表中,没有找到该雇员~");}}//根据输入的id删除雇员public void delEmp(int id){int empLinkListNO = hashFun(id);//先查找在第几个链表中empLinkedListArray[empLinkListNO].delEmp(id);//然后执行删除操作System.out.println("删除完成");}//编写散列函数, 使用一个简单取模法public int hashFun(int id) {return id % size;}}

2. class EmpLinkedList{ };

//创建EmpLinkedList ,表示链表
class EmpLinkedList {//头指针,执行第一个Emp,因此我们这个链表的head 是直接指向第一个Empprivate Emp head; //默认null//添加雇员到链表//说明//1. 假定,当添加雇员时,id 是自增长,即id的分配总是从小到大//   因此我们将该雇员直接加入到本链表的最后即可public void add(Emp emp) {//如果是添加第一个雇员if(head == null) {head = emp;return;}//如果不是第一个雇员,则使用一个辅助的指针,帮助定位到最后Emp curEmp = head;while(true) {if(curEmp.next == null) {//说明到链表最后break;}curEmp = curEmp.next; //后移}//退出时直接将emp 加入链表curEmp.next = emp;}//遍历链表的雇员信息public void list(int no) {if(head == null) { //说明链表为空System.out.println("第 "+(no+1)+" 链表为空");return;}System.out.print("第 "+(no+1)+" 链表的信息为");Emp curEmp = head; //辅助指针while(true) {System.out.printf(" => id=%d name=%s\t", curEmp.id, curEmp.name);if(curEmp.next == null) {//说明curEmp已经是最后结点break;}curEmp = curEmp.next; //后移,遍历}System.out.println();}//根据id查找雇员//如果查找到,就返回Emp, 如果没有找到,就返回nullpublic Emp findEmpById(int id) {//判断链表是否为空if(head == null) {System.out.println("链表为空");return null;}//辅助指针Emp curEmp = head;while(true) {if(curEmp.id == id) {//找到break;//这时curEmp就指向要查找的雇员}//退出if(curEmp.next == null) {//说明遍历当前链表没有找到该雇员curEmp = null;break;}curEmp = curEmp.next;//以后}return curEmp;}public void delEmp(int id){Emp emp = findEmpById(id);//先找到雇员在删除if(emp == null){System.out.println("没有找到该雇员");}Emp curEmp = head;while(true){if(emp == head){//分两种情况进行删除head = head.next;//1.要删除的雇员在头节点处,直接让头指针指向下一个节点即可break;}if(curEmp.next == emp){//2.要删除的雇员不在头节点处,先找到位置在删除curEmp = curEmp.next.next;break;}curEmp = curEmp.next;}}
}

3. class Emp{ };

//表示一个雇员
class Emp {public int id;public String name;public Emp next; //next 默认为 nullpublic Emp(int id, String name) {super();this.id = id;this.name = name;}
}

4.测试:

public class HashTabDemo {public static void main(String[] args) {//创建哈希表HashTab hashTab = new HashTab(7);//写一个简单的菜单String key = "";Scanner scanner = new Scanner(System.in);while(true) {System.out.println("add:  添加雇员");System.out.println("list: 显示雇员");System.out.println("find: 查找雇员");System.out.println("del:  删除雇员");System.out.println("exit: 退出系统");key = scanner.next();switch (key) {case "add":System.out.println("输入id");int id = scanner.nextInt();System.out.println("输入名字");String name = scanner.next();//创建 雇员Emp emp = new Emp(id, name);hashTab.add(emp);break;case "list":hashTab.list();break;case "find":System.out.println("请输入要查找的id");id = scanner.nextInt();hashTab.findEmpById(id);break;case "del":System.out.println("请输入要删除的id");id = scanner.nextInt();hashTab.delEmp(id);break;case "exit":scanner.close();System.exit(0);default:break;}}}}

运行结果:

最后,完整代码:

import java.util.Scanner;public class HashTabDemo {public static void main(String[] args) {//创建哈希表HashTab hashTab = new HashTab(7);//写一个简单的菜单String key = "";Scanner scanner = new Scanner(System.in);while(true) {System.out.println("add:  添加雇员");System.out.println("list: 显示雇员");System.out.println("find: 查找雇员");System.out.println("del:  删除雇员");System.out.println("exit: 退出系统");key = scanner.next();switch (key) {case "add":System.out.println("输入id");int id = scanner.nextInt();System.out.println("输入名字");String name = scanner.next();//创建 雇员Emp emp = new Emp(id, name);hashTab.add(emp);break;case "list":hashTab.list();break;case "find":System.out.println("请输入要查找的id");id = scanner.nextInt();hashTab.findEmpById(id);break;case "del":System.out.println("请输入要删除的id");id = scanner.nextInt();hashTab.delEmp(id);break;case "exit":scanner.close();System.exit(0);default:break;}}}}//创建HashTab 管理多条链表
class HashTab {private EmpLinkedList[] empLinkedListArray;private int size; //表示有多少条链表//构造器public HashTab(int size) {this.size = size;//初始化empLinkedListArrayempLinkedListArray = new EmpLinkedList[size];for(int i = 0; i < size; i++) {empLinkedListArray[i] = new EmpLinkedList();}}//添加雇员public void add(Emp emp) {//根据员工的id ,得到该员工应当添加到哪条链表int empLinkedListNO = hashFun(emp.id);//将emp 添加到对应的链表中empLinkedListArray[empLinkedListNO].add(emp);}//遍历所有的链表,遍历hashtabpublic void list() {for(int i = 0; i < size; i++) {empLinkedListArray[i].list(i);}}//根据输入的id,查找雇员public void findEmpById(int id) {//使用散列函数确定到哪条链表查找int empLinkedListNO = hashFun(id);Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);if(emp != null) {//找到System.out.printf("在第%d条链表中找到 雇员 id = %d\n", (empLinkedListNO + 1), id);}else{System.out.println("在哈希表中,没有找到该雇员~");}}//根据输入的id删除雇员public void delEmp(int id){int empLinkListNO = hashFun(id);//先查找在第几个链表中empLinkedListArray[empLinkListNO].delEmp(id);//然后执行删除操作System.out.println("删除完成");}//编写散列函数, 使用一个简单取模法public int hashFun(int id) {return id % size;}}//表示一个雇员
class Emp {public int id;public String name;public Emp next; //next 默认为 nullpublic Emp(int id, String name) {super();this.id = id;this.name = name;}
}//创建EmpLinkedList ,表示链表
class EmpLinkedList {//头指针,执行第一个Emp,因此我们这个链表的head 是直接指向第一个Empprivate Emp head; //默认null//添加雇员到链表//说明//1. 假定,当添加雇员时,id 是自增长,即id的分配总是从小到大//   因此我们将该雇员直接加入到本链表的最后即可public void add(Emp emp) {//如果是添加第一个雇员if(head == null) {head = emp;return;}//如果不是第一个雇员,则使用一个辅助的指针,帮助定位到最后Emp curEmp = head;while(true) {if(curEmp.next == null) {//说明到链表最后break;}curEmp = curEmp.next; //后移}//退出时直接将emp 加入链表curEmp.next = emp;}//遍历链表的雇员信息public void list(int no) {if(head == null) { //说明链表为空System.out.println("第 "+(no+1)+" 链表为空");return;}System.out.print("第 "+(no+1)+" 链表的信息为");Emp curEmp = head; //辅助指针while(true) {System.out.printf(" => id=%d name=%s\t", curEmp.id, curEmp.name);if(curEmp.next == null) {//说明curEmp已经是最后结点break;}curEmp = curEmp.next; //后移,遍历}System.out.println();}//根据id查找雇员//如果查找到,就返回Emp, 如果没有找到,就返回nullpublic Emp findEmpById(int id) {//判断链表是否为空if(head == null) {System.out.println("链表为空");return null;}//辅助指针Emp curEmp = head;while(true) {if(curEmp.id == id) {//找到break;//这时curEmp就指向要查找的雇员}//退出if(curEmp.next == null) {//说明遍历当前链表没有找到该雇员curEmp = null;break;}curEmp = curEmp.next;//以后}return curEmp;}public void delEmp(int id){Emp emp = findEmpById(id);//先找到雇员在删除if(emp == null){System.out.println("没有找到该雇员");}Emp curEmp = head;while(true){if(emp == head){//分两种情况进行删除head = head.next;//1.要删除的雇员在头节点处,直接让头指针指向下一个节点即可break;}if(curEmp.next == emp){//2.要删除的雇员不在头节点处,先找到位置在删除curEmp = curEmp.next.next;break;}curEmp = curEmp.next;}}
}

博客到这里也是结束了,制作不易,喜欢的小伙伴可以点赞加关注支持下博主,这对我真的很重要~~

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

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

相关文章

关于数字图像处理考试

我们学校这门科目是半学期就完结哦&#xff0c;同学们学习的时候要注意时间哦。 选择题不用管&#xff0c;到时候会有各种版本的复习资料的。 以下这些东西可能会是大题的重点&#xff1a; 我根据平时代码总结的&#xff0c;供参考 基本操作&#xff1a; 1.读图&#xff1a;…

【LeetCode】37. 解数独(困难)——代码随想录算法训练营Day30

题目链接&#xff1a;37. 解数独 题目描述 编写一个程序&#xff0c;通过填充空格来解决数独问题。 数独的解法需 遵循如下规则&#xff1a; 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&…

机器学习——有监督学习和无监督学习

有监督学习 简单来说&#xff0c;就是人教会计算机学会做一件事。 给算法一个数据集&#xff0c;其中数据集中包含了正确答案&#xff0c;根据这个数据集&#xff0c;可以对额外的数据希望得到一个正确判断&#xff08;详见下面的例子&#xff09; 回归问题 例如现在有一个…

【深度学习:Bard】我们 AI 之旅的重要下一步

【深度学习&#xff1a;AI 之旅】我们 AI 之旅的重要下一步 Bard简介将 AI 的优势带入我们的日常产品中帮助开发人员利用 AI 进行创新大胆负责 人工智能是我们今天正在研究的最深刻的技术。无论是帮助医生更早地发现疾病&#xff0c;还是使人们能够用自己的语言获取信息&#x…

深度学习中的Droupout

1. 什么是Droupout Dropout的作用是防止过拟合。 Dropout在训练模型中是如何实现的呢&#xff1f;Dropout的做法是在训练过程中按一定比例&#xff08;比例参数可设置&#xff09;随机忽略或屏蔽一些神经元。这些神经元被随机“抛弃”&#xff0c;也就是说它们在正向传播过程…

【C/C++】整数及乘积的溢出问题

文章目录 一、为什么会溢出&#xff1f;二、怎样解决&#xff1f;三、看个例题四、补充&#xff1a;scanf和cin的区别 一、为什么会溢出&#xff1f; 整数乘积的溢出问题是指两个整数相乘得到的结果超过了所能表示的数据类型的范围。 在计算机中&#xff0c;整数的表示是有限…

移动应用开发Android 创建第一个Android项目

文章目录 一、创建第一个Android项目1.1 准备好Android Studio1.2 运行程序1.3 程序结构是什么app下的结构res - 子目录&#xff08;所有图片、布局、字AndroidManifest.xml 有四大组件&#xff0c;程序添加权限声明 Project下的结构 二、开发android时&#xff0c;部分库下载异…

Spinnaker多云持续交付平台: 部署Minio存储服务

目录 一、实验 1.环境 2.K8S storage节点部署NFS 3.K8S 动态创建PV 4.K8S master节点部署HELM3 4.K8S master节点部署Minio存储服务&#xff08;第一种方式安装&#xff09; 5.Minio客户端安装MC命令 6.K8S master节点使用Docker 部署Minio存储服务&#xff08;第二种方…

【前端】实现Vue组件页面跳转的多种方式

目录 前言1. 内嵌2. 跳转新页面2.1 Demo12.2 Demo22.3 Demo3 3. 拓展 前言 通过某个Button让页面多种方式跳转 1. 内嵌 想要在Vue应用中内嵌一个外部网页&#xff0c;可以使用<iframe>标签 下面是一个示例&#xff1a; <template><div><!-- 在这里嵌入…

阿里云游戏服务器租用价格表,2024最新报价

阿里云游戏服务器租用价格表&#xff1a;4核16G服务器26元1个月、146元半年&#xff0c;游戏专业服务器8核32G配置90元一个月、271元3个月&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云游戏专用服务器详细配置和精准报价&#xff1a; 阿里云游戏服务器租用价格表 阿…

【C++修行之道】(引用、函数提高)

目录 一、引用 1.1引用的基本使用 1.2 引用注意事项 1.3 引用做函数参数 1.4 引用做函数返回值 1.5 引用的本质 1.6 常量引用 1.7引用和指针的区别 二、函数提高 2.1 函数默认参数 2.2函数占位参数 2.3 函数重载 2.4函数重载注意事项 一、引用 1.1引用的基本使用 …

【RT-DETR进阶实战】利用RT-DETR进行视频划定区域目标统计计数

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 Hello,各位读者,最近会给大家发一些进阶实战的讲解,如何利用RT-DETR现有的一些功能进行一些实战, 让我们不仅会改进RT-DETR,也能够利用RT-DETR去做一些简单的小工作,后面我也会将这些功能利用PyQt或者是…

备战蓝桥杯---搜索(完结篇)

再看一道不完全是搜索的题&#xff1a; 解法1&#xff1a;贪心并查集&#xff1a; 把冲突事件从大到小排&#xff0c;判断是否两个在同一集合&#xff0c;在的话就返回&#xff0c;不在的话就合并。 下面是AC代码&#xff1a; #include<bits/stdc.h> using namespace …

LeetCode-第28题-找出字符串中第一个匹配项的下标

1.题目描述 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 2.样例描述 3.思路描述 可以让字符串 …

【前端web入门第四天】01 复合选择器与伪类选择器

文章目录: 1. 复合选择器 1.1 后代选择器 1.2 子代选择器 1.3 并集选择器1.4 交集选择器(了解) 2.伪类选择器 2.1 伪类-文本2.2 伪类-超链接&#xff08;拓展) 1. 复合选择器 什么叫复合选择器? 由两个或多个基础选择器&#xff0c;通过不同的方式组合而成。 复合选择器的作…

158基于matlab的用于分析弧齿锥齿轮啮合轨迹的程序

基于matlab的用于分析弧齿锥齿轮啮合轨迹的程序&#xff0c;输出齿轮啮合轨迹及传递误差。程序已调通&#xff0c;可直接运行。 158 matlab 弧齿锥齿轮啮合轨迹 传递误差 (xiaohongshu.com)

RedissonClient妙用-分布式布隆过滤器

目录 布隆过滤器介绍 布隆过滤器的落地应用场景 高并发处理 多个过滤器平滑切换 分析总结 布隆过滤器介绍 布隆过滤器&#xff08;Bloom Filter&#xff09;是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是…

SolidWorks的抽壳

抽壳在建模的时候是比较常见的要求&#xff0c;这里废话不多说&#xff0c;直接开始实例操作。 文章目录 一、规则实体抽壳2、多面抽壳3、空心化抽壳 二、椎体抽壳三、不规则实体抽壳1、不规则实体2、部分实体抽壳 文章随时可能更新&#xff0c;请关注文章原出处&#xff1a; …

JVM之GC垃圾回收

GC垃圾回收 如何判断对象可以回收 引用计数法 如果有对象引用计数加一&#xff0c;没有对象引用&#xff0c;计数减一&#xff0c;如果计数为零&#xff0c;则回收 但是如果存在循环引用&#xff0c;即A对象引用B对象&#xff0c;B对象引用A对象&#xff0c;会造成内存泄漏 可…

Gitlab和Jenkins集成 实现CI (二)

Gitlab和Jenkins集成 实现CI (一) Gitlab和Jenkins集成 实现CI (二) Gitlab和Jenkins集成 实现CI (三) 配置Gitlab api token 配置 Gitlab 进入gitlab #mermaid-svg-t84fR8wrT4sB4raQ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:…