原文链接传送门

哈希表(散列)-Google上机题

看一个实际需求,google公司的一个上机题:

有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址…),当输入该员工的id时,要求查找到该员工的 所有信息.

要求: 不使用数据库,尽量节省内存,速度越快越好=>哈希表(散列)

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。 15 111 % 15

哈希表就是数组里面存储链表

google公司的一个上机题:

有一个公司,当有新的员工来报道时,要求将该员工的信息加入(id,性别,年龄,名字,住址…),当输入该员工的id时,要求查找到该员工的 所有信息.

要求:

不使用数据库,速度越快越好=>哈希表(散列) 添加时,保证按照id从低到高插入 [课后思考:如果id不是从低到高插入,但要求各条链表仍是从低到高,怎么解决?]

  1. 使用链表来实现哈希表, 该链表不带表头[即: 链表的第一个结点就存放雇员信息]
  2. 思路分析并画出示意图
  3. 代码实现[增删改查(显示所有员工,按id查询)]

// 哈希表之所以能够提高效率,是因为他能够同时管理多个链表

Emp

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

HashTab

///创建hashTab 管理多条链表class HashTab{// 数组里面放的是链表private EmpLinkedList[] empLinkedListArray;//private Integer size = 7;// 构造器public HashTab(int size) {// 初始化empLinkedListArrayempLinkedListArray = new EmpLinkedList[size];// ? 留一个坑// 这里能直接用么/** add:添加雇员list:显示雇员exit:退出雇员add输入idtomException in thread "main" java.util.InputMismatchExceptionat java.util.Scanner.throwFor(Scanner.java:864)at java.util.Scanner.next(Scanner.java:1485)at java.util.Scanner.nextInt(Scanner.java:2117)at java.util.Scanner.nextInt(Scanner.java:2076)at com.atguigu.hashtab.HashTabDemo.main(HashTabDemo.java:30)Process finished with exit code 1* */// 这个时候不要忘了, 分别初始化 每个链表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);}// 不管你是什么操作,总是要找链表// 遍历所有的链表public void list() {// 遍历Hash表for (int i = 0; i < size; i++) {empLinkedListArray[i].list(i);}}// 编写一个散列函数// 散列函数有很多种写法// 这里使用简单的方法-取模法public int hashFun(int id) {return id % size;}/*** 更根据输入的id,查找雇员* @param id*/public void findEmpById(int id) {// 使用散列函数确定到哪条链表查找int empLinkedListNO = hashFun(id);Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);if (emp != null) {// 说明找到了System.out.println("找到了该雇员");System.out.printf("在第%d条链表中找到了该雇员,id = %d",id,empLinkedListNO+1);} else {System.out.println("在哈希表中,没有找到该雇员~");}}
}

EmpLinkedList

class EmpLinkedList{// 头指针, 执行第一个Emp,因此我们这个链表的head,是直接 指向第一个Empprivate Emp head;//添加雇员到链表// 说明.// 1. 假定,当添加雇员的时候,id是自增长的,即id 的分配总是从小到大public void add(Emp emp) {// 如果是添加第一个雇员if (head == null) {head = emp;return;}// 如果不是添加第一个雇员,则使用一个辅助的指针,帮助定位到最后Emp currEmp = head;while (true) {if (currEmp.next == null) {// 说明到链表最后break;}// 后移currEmp = currEmp.next;}// 退出时,直接将emp 加入链表currEmp.next = emp;}// 遍历链表的雇员信息public void list(int no) {// 判断是否为空if (head == null) {// 说明链表为空System.out.println("当前链"+no+"表为空!");return;}// 没有空
//        打印信息System.out.println("当前链"+no+"表的信息为");// 辅助指针Emp currEmp = head;while (true) {System.out.printf("=> id =%d name = %s\t",currEmp.id,currEmp.name);if (currEmp.next == null) {// 说明,currEmp 已经是最后节点break;}// 后移 遍历currEmp = currEmp.next;}System.out.println();}/***     // 根据id 查找雇员*    // 如果查找到 ,就返回Emp,如果没有找打到,就返回null* @param id* @return*/public Emp findEmpById(int id) {// 判断链表是否为空if (head == null) {System.out.println("链表为空");return null;}//辅助指针Emp curEmp = head;while (true) {//if (curEmp.id == id) {// 找到break;//  这个时候,currEmp就指向了要查找的雇员}// 退出if (curEmp.next == null) {// 说明遍历当前链表没有找到该雇员curEmp = null;}// 后移curEmp = curEmp.next;}return curEmp;}
}

主函数

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("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");int findId = scanner.nextInt();hashTab.findEmpById(findId);break;case "exit":scanner.close();System.exit(0);default:break;}}
}
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
1
输入名字
tom
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
2
输入名字
jack
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
3
输入名字
pin
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
6
输入名字
nanc
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
list
当前链0表为空!
当前链1表的信息为
=> id =1 name = tom
当前链2表的信息为
=> id =2 name = jack
当前链3表的信息为
=> id =3 name = pin
当前链4表为空!
当前链5表为空!
当前链6表的信息为
=> id =6 name = nanc
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
123
输入名字
sme
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
list
当前链0表为空!
当前链1表的信息为
=> id =1 name = tom
当前链2表的信息为
=> id =2 name = jack
当前链3表的信息为
=> id =3 name = pin
当前链4表的信息为
=> id =123 name = sme
当前链5表为空!
当前链6表的信息为
=> id =6 name = nanc
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
678
输入名字
vicr
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
list
当前链0表为空!
当前链1表的信息为
=> id =1 name = tom
当前链2表的信息为
=> id =2 name = jack
当前链3表的信息为
=> id =3 name = pin
当前链4表的信息为
=> id =123 name = sme
当前链5表为空!
当前链6表的信息为
=> id =6 name = nanc  => id =678 name = vicr
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
389
输入名字
wef
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
9
输入名字
zho
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
list
当前链0表为空!
当前链1表的信息为
=> id =1 name = tom
当前链2表的信息为
=> id =2 name = jack  => id =9 name = zho
当前链3表的信息为
=> id =3 name = pin
当前链4表的信息为
=> id =123 name = sme => id =389 name = wef
当前链5表为空!
当前链6表的信息为
=> id =6 name = nanc  => id =678 name = vicr
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
34
输入名字
mach
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
list
当前链0表为空!
当前链1表的信息为
=> id =1 name = tom
当前链2表的信息为
=> id =2 name = jack  => id =9 name = zho
当前链3表的信息为
=> id =3 name = pin
当前链4表的信息为
=> id =123 name = sme => id =389 name = wef
当前链5表为空!
当前链6表的信息为
=> id =6 name = nanc  => id =678 name = vicr    => id =34 name = mach
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
find
输入id
8
Exception in thread "main" java.lang.NullPointerExceptionat com.atguigu.hashtab.EmpLinkedList.findEmpById(HashTabDemo.java:237)at com.atguigu.hashtab.HashTab.findEmpById(HashTabDemo.java:128)at com.atguigu.hashtab.HashTabDemo.main(HashTabDemo.java:44)Process finished with exit code 1

最后这里置空要 加上break

if (curEmp.next == null) {// 说明遍历当前链表没有找到该雇员curEmp = null;break;}

这下就可以了

add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
1
输入名字
tom
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
2
输入名字
nancy
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add4
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
add
输入id
4
输入名字
victor
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
list
当前链0表为空!
当前链1表的信息为
=> id =1 name = tom
当前链2表的信息为
=> id =2 name = nancy
当前链3表为空!
当前链4表的信息为
=> id =4 name = victor
当前链5表为空!
当前链6表为空!
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
find
输入id
6
链表为空
在哈希表中,没有找到该雇员~
add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员
find
输入id
4
找到了该雇员
在第4条链表中找到了该雇员,id = 5add:添加雇员
list:显示雇员
find:查找雇员
exit:退出雇员

完整代码

package com.atguigu.hashtab;import java.util.Scanner;/*** ClassName:  <br/>* Description:  <br/>* Date: 2021-02-24 13:10 <br/>* <br/>* @project data_algorithm* @package com.atguigu.hashtab*/
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("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");int findId = scanner.nextInt();hashTab.findEmpById(findId);break;case "exit":scanner.close();System.exit(0);default:break;}}}
}///创建hashTab 管理多条链表class HashTab{// 数组里面放的是链表private EmpLinkedList[] empLinkedListArray;//private Integer size = 7;// 构造器public HashTab(int size) {// 初始化empLinkedListArrayempLinkedListArray = new EmpLinkedList[size];// ? 留一个坑// 这里能直接用么/** add:添加雇员list:显示雇员exit:退出雇员add输入idtomException in thread "main" java.util.InputMismatchExceptionat java.util.Scanner.throwFor(Scanner.java:864)at java.util.Scanner.next(Scanner.java:1485)at java.util.Scanner.nextInt(Scanner.java:2117)at java.util.Scanner.nextInt(Scanner.java:2076)at com.atguigu.hashtab.HashTabDemo.main(HashTabDemo.java:30)Process finished with exit code 1* */// 这个时候不要忘了, 分别初始化 每个链表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);}// 不管你是什么操作,总是要找链表// 遍历所有的链表public void list() {// 遍历Hash表for (int i = 0; i < size; i++) {empLinkedListArray[i].list(i);}}// 编写一个散列函数// 散列函数有很多种写法// 这里使用简单的方法-取模法public int hashFun(int id) {return id % size;}/*** 更根据输入的id,查找雇员* @param id*/public void findEmpById(int id) {// 使用散列函数确定到哪条链表查找int empLinkedListNO = hashFun(id);Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);if (emp != null) {// 说明找到了System.out.println("找到了该雇员");System.out.printf("在第%d条链表中找到了该雇员,id = %d",id,empLinkedListNO+1);} else {System.out.println("在哈希表中,没有找到该雇员~");}}
}/*** 表示一个雇员*/
class Emp{public int id;public String name;public Emp next;//next 默认为空public Emp(int id, String name) {this.id = id;this.name = name;}
}class EmpLinkedList{// 头指针, 执行第一个Emp,因此我们这个链表的head,是直接 指向第一个Empprivate Emp head;//添加雇员到链表// 说明.// 1. 假定,当添加雇员的时候,id是自增长的,即id 的分配总是从小到大public void add(Emp emp) {// 如果是添加第一个雇员if (head == null) {head = emp;return;}// 如果不是添加第一个雇员,则使用一个辅助的指针,帮助定位到最后Emp currEmp = head;while (true) {if (currEmp.next == null) {// 说明到链表最后break;}// 后移currEmp = currEmp.next;}// 退出时,直接将emp 加入链表currEmp.next = emp;}// 遍历链表的雇员信息public void list(int no) {// 判断是否为空if (head == null) {// 说明链表为空System.out.println("当前链"+no+"表为空!");return;}// 没有空
//        打印信息System.out.println("当前链"+no+"表的信息为");// 辅助指针Emp currEmp = head;while (true) {System.out.printf("=> id =%d name = %s\t",currEmp.id,currEmp.name);if (currEmp.next == null) {// 说明,currEmp 已经是最后节点break;}// 后移 遍历currEmp = currEmp.next;}System.out.println();}/***     // 根据id 查找雇员*    // 如果查找到 ,就返回Emp,如果没有找打到,就返回null* @param id* @return*/public Emp findEmpById(int id) {// 判断链表是否为空if (head == null) {System.out.println("链表为空");return null;}//辅助指针Emp curEmp = head;while (true) {//if (curEmp.id == id) {// 找到break;//  这个时候,currEmp就指向了要查找的雇员}// 退出if (curEmp.next == null) {// 说明遍历当前链表没有找到该雇员curEmp = null;break;}// 后移curEmp = curEmp.next;}return curEmp;}
}

扩展

删除功能???

原文链接传送门

哈希表思路图解和代码实现相关推荐

  1. PTA 旅游规划(邻接表) 思路分析及代码解析

    PTA 旅游规划_使用邻接表 思路分析及代码解析v1.0 一.前导 1. 需要掌握的知识 2. 题目信息 二.解题思路分析 1. 题意理解 1. 1 输入数据 1.2 输出数据 2. 思路分析(重点) ...

  2. 【数据结构】哈希表详解以及代码实现

    目录 1.来源: 2.哈希函数 1.哈希函数的设计规则 2.哈希函数的设计思路 3.哈希碰撞 4.解决哈希碰撞的方案 5.负载因子 3.基于开散列方案的HashMap实现 1.HashMap类中的属性 ...

  3. 《我的第一本算法书》阅读笔记 1-6 哈希表原理图解

    目录 普通数组线性查找工作流程 哈希表怎么存储数据 出现冲突怎么办?(eg.链地址法) 哈希表怎么查找数据 解说 补充说明 来源 在哈希表这种数据结构中,使用将在 5-3 节讲解的"哈希函数 ...

  4. 数据结构之哈希表以及常用哈希的算法表达(含全部代码)

    目录 为什么要有哈希 哈希表 含义 创建哈希表需要注意的点 算法的选择 哈希冲突的处理 线性探测法 再哈希法 链表法 哈希表的实现(代码部分) 确定结构体(节点) 准备一个哈希算法 创建一个哈希表(即 ...

  5. 【LeetCode笔记】169. 多数元素(Java、摩尔投票法、哈希表)

    文章目录 题目描述 思路 & 代码 思路一:哈希表 思路二: 摩尔投票法 题目描述 好家伙,这是今天最有意思的题目了 思路 & 代码 思路一:哈希表 先说缺点:空间复杂度O(n) 一次 ...

  6. 【Java数据结构与算法】第十章 哈希表和二叉树

    第十章 哈希表和二叉树 文章目录 第十章 哈希表和二叉树 一.哈希表 1.介绍 2.代码实现 二.二叉树 1.介绍 2.遍历二叉树 3.查找二叉树 4.二叉树删除节点 5.二叉树综合实例 一.哈希表 ...

  7. LeetCode-1.两数之和(哈希表)

    题目内容 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/two-sum 给定一个整数数组 nums 和一个整数目标值 target,请你在该数 ...

  8. JavaScript 数据结构与算法(二)哈希表

    本文参考文献:https://www.cnblogs.com/AhuntSun-blog/p/12636718.html 配套视频教程:https://www.bilibili.com/video/B ...

  9. 力扣LeetCode-哈希表

    哈希表 一.基本知识点 1. 定义 哈希表是根据关键码的值而直接进行访问的数据结构. 2. 解决问题 快速判断一个元素是否出现集合里. 3. 哈希碰撞解决方法 拉链法与线性探测法. 4. 常见的三种哈 ...

最新文章

  1. Mysqlreport总结
  2. Java—正整数分解成质因数
  3. dos批处理命令详解
  4. py4j.protocol.Py4JJavaError: An error occurred while calling o90.save
  5. 斐波那契数列c++代码_轮到你了,斐波那契数列!
  6. excel转txt工具
  7. 借助实时数据推送快速制作在线对战五子棋小游戏丨实战
  8. 修复计算机的英语,Windows Repair最新版
  9. 动力环境监控系统论文_动力环境监控系统现状及在电源维护中的作用
  10. bat启动脚本 springboot_Windows系统配置.bat启动spring boot项目jar
  11. 2020 年,你必须知道发展最快和衰落最快的软件技能
  12. 如何通过PXE实现一键自动化安装操作系统
  13. Goldengate进程的拆分与合并
  14. .NET资源站点汇总
  15. OpenJudge 7624 山区建小学
  16. Commander(指挥官)介绍
  17. 妈妈的味道,从一碗北极虾荠…
  18. 哎,开发又被骗了……
  19. c++:一维黎曼问题多种格式求解
  20. Android基于Poi生成Word

热门文章

  1. 人心散了、项目必然要败
  2. 项目经理如何把工作简单化
  3. Vuejs:组件 slot 内容分发
  4. 解决:Could not find or load main class org.apache.rocketmq.example.quickstart.Producer
  5. 遍历Map key-value的两种方法、遍历Set方法
  6. java.util.UnknownFormatConversionException: Conversion = ‘,‘ 解决
  7. mysql 索引的统计
  8. 多态方法调用的解析和分派
  9. shell编程中date用法(转)
  10. 写一个函数,使给定的一个二维数组(3×3)转置,即行列互换