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

QQ截图20200824153612.jpg

2、哈希表的基本介绍

QQ截图20200824153703.jpgQQ截图20200824153709.jpg

3、 google 公司的一个上机题

QQ截图20200824153807.jpg

思路分析

使用的是对象数组+链表的方式来进行存储数据信息并且通过散列函数来确定对应数组的位置。
QQ截图20200824153817.jpg

代码实现(说明+完整过程+测试)

源代码:HashTab.java

说明:创建三个类,第一个类是员工类包含next指针,第二个类是管理员工的链表类包含head节点(头节点),第三个类就是哈希表包含对象数组(对象为链表类)。

链表类:包含增加、查询、遍历链表、根据id查找链表的方法
哈希表:同样包含增加、查询、遍历、以及根据id查找方法(调用链表中的方法有点像web中的DAO层与Service
层),并且包含对应散列函数方法用于计算获取到对应数组下标的链表。

注意点:**** 这里的链表头节点不为空与之前学习的空头节点有些不同
创建对象数组时,创建完对象还需要创建数组中每个自定义类的对新昂

主要类


① 员工类

  1. //创建职工类
  2. class Emp{
  3. public String name;
  4. public int id;
  5. public Emp next;//下一个节点
  6. public Emp(String name, int id) {
  7. super();
  8. this.name = name;
  9. this.id = id;
  10. }
  11. @Override
  12. public String toString() {
  13. return "Emp [name=" + name + ", id=" + id + "]";
  14. }
  15. }

② 员工链表类

  1. //创建管理类的链表
  2. class EmpList{
  3. private Emp head;//表示头节点
  4. //添加emp类到该链表的最后
  5. public void add(Emp emp) {
  6. if(head == null) {
  7. head = emp;//emp节点则为头节点
  8. return;
  9. }
  10. //设置一个辅助节点
  11. Emp cur = head;
  12. while(true) {
  13. //如果辅助节点下一个节点为null,那么此时就是最后一个节点
  14. if(cur.next == null) {
  15. cur.next = emp;//将emp节点插入到最后即可退出
  16. return;
  17. }
  18. cur = cur.next;//继续向后遍历
  19. }
  20. }
  21. // 遍历该链表
  22. public void list(int n) {
  23. if (head == null) {
  24. System.out.println("第"+n+"组链表为空!");
  25. return;
  26. }
  27. // 设置一个辅助节点
  28. Emp cur = head;
  29. System.out.printf("第"+n+"组链表如下:");
  30. while (true) {
  31. System.out.print(cur);//直接打印信息
  32. if(cur.next == null) {//说明这里是最后一个节点
  33. System.out.println();
  34. return;
  35. }
  36. //向后继续遍历
  37. cur = cur.next;
  38. }
  39. }
  40. //根据id来查找到对应emp类
  41. public Emp findEmpById(int id) {
  42. //如果头节点为空,那么返回null值
  43. if(head == null) {
  44. return null;
  45. }
  46. Emp cur = head;
  47. while(true) {
  48. if(cur.id == id) {
  49. break;//退出循环,此时cur为找到职工
  50. }
  51. //如果此时已经是最后一个节点,那么cur置为null,退出循环
  52. if(cur.next == null) {
  53. cur = null;
  54. break;
  55. }
  56. cur = cur.next;//往下进行遍历
  57. }
  58. return cur;//统一进行返回即可
  59. }
  60. //根据id删除对应信息
  61. public int deleteEmpById(int id) {
  62. if(head == null) {//链表为空返回-1
  63. return -1;
  64. }
  65. Emp cur = head;
  66. if(head.id == id) {//因为头节点是有数据的所以先单独判断头节点
  67. head = head.next;//直接删除本身节点
  68. return 1;//表示删除成功
  69. }
  70. while(true) {
  71. if(cur.next == null) {
  72. return -1;//如果到最后一个节点依旧没有找到直接返回-1表示为删除
  73. }
  74. if(cur.next.id == id) {
  75. cur.next = cur.next.next;//本身节点的next直接指向删除节点的下一个节点
  76. return 1;//删除成功
  77. }
  78. cur = cur.next;//进行后移操作
  79. }
  80. }
  81. }

③ 哈希表

  1. //创建hashtable类
  2. class MyHashTab{
  3. private EmpList[] empLists;//创建一个员工链表数组
  4. private int size;//size表示多少个员工链表
  5. //创建hashtable类并配置对应size
  6. public MyHashTab(int size) {
  7. this.size = size;
  8. empLists = new EmpList[size];//进行开辟数组空间
  9. //注意点:对于对象数组不仅要开辟数组空间还要开辟对象空间
  10. for(int i = 0;i<size;i++) {
  11. empLists[i] = new EmpList();
  12. }
  13. }
  14. //创建一个散列函数,根据id来得到散列值
  15. public int hashFun(int id) {
  16. return id%size;
  17. }
  18. //进行添加操作
  19. public void add(Emp emp) {
  20. int hashFun = hashFun(emp.id);//获取散列值
  21. //根据获取的散列值来分配对应链表中,并执行该链表的add操作
  22. empLists[hashFun].add(emp);
  23. }
  24. //进行遍历操作
  25. public void list() {
  26. //直接遍历数组进行输出
  27. for(int i = 0;i<empLists.length;i++) {
  28. //这里进行判断即可
  29. if(empLists[i] != null) {
  30. empLists[i].list(i);
  31. }
  32. }
  33. }
  34. //进行根据id查找工作
  35. public void find(int id) {
  36. int hashFun = hashFun(id);//获取到对应数组链表的下标
  37. //通过对应下标找到链表进行调用方法
  38. Emp findEmpById = empLists[hashFun].findEmpById(id);
  39. if(findEmpById != null) {
  40. System.out.println("已在第"+hashFun+"组链表中找到,信息为:"+findEmpById);
  41. }else {
  42. System.out.printf("未找到id为%d的信息\n",id);
  43. }
  44. }
  45. //根据id值来进行删除工作
  46. public void deleteEmpById(int id) {
  47. int hashFun = hashFun(id);//获取到对应数组链表的下标
  48. int deleteEmpById = empLists[hashFun].deleteEmpById(id);
  49. if(deleteEmpById == 1) {
  50. System.out.printf("已删除第%d组下的对应id员工!\n",hashFun);
  51. }else {
  52. System.out.println("链表为空或无该节点!");
  53. }
  54. }
  55. }

测试类(已测试)

  1. package hashTableExer;
  2. import java.util.Scanner;
  3. public class HashTab {
  4. public static void main(String[] args) {
  5. MyHashTab myHashTab = new MyHashTab(7);
  6. String key = "";
  7. Scanner scanner = new Scanner(System.in);
  8. while(true) {
  9. System.out.println("请选择你想使用的操作:\n"
  10. + "add:添加职员\n"+"list:遍历职员\n"+"find:输入id查找\n"+"delete:根据id删除\n"+"exit:退出程序");
  11. key = scanner.next();
  12. switch (key) {
  13. case "add":
  14. System.out.println("请输入姓名:");
  15. String name = scanner.next();
  16. System.out.println("请输入id:");
  17. int id = scanner.nextInt();
  18. myHashTab.add(new Emp(name, id));//向哈希表中添加一个雇员
  19. System.out.println("添加成功!");
  20. break;
  21. case "list":
  22. myHashTab.list();//进行遍历哈希表中的所有链表
  23. break;
  24. case "find":
  25. System.out.println("请输入你想要查找的id:");
  26. int findId = scanner.nextInt();
  27. myHashTab.find(findId);
  28. System.out.println("查找完成!");
  29. break;
  30. case "delete":
  31. System.out.println("请输入你想要删除的id:");
  32. int deleteId = scanner.nextInt();
  33. myHashTab.deleteEmpById(deleteId);
  34. break;
  35. case "exit":
  36. scanner.close();//手动关闭
  37. System.exit(0);//退出程序
  38. default:
  39. break;
  40. }
  41. }
  42. }
  43. }

运行结果:这里仅仅展示删除操作,其余操作太多
QQ截图20200825113128.jpg


整理者:长路 时间:2020/8/24-2020/8/25