数据结构——哈希表

梦里梦外; 2024-03-26 19:38 256阅读 0赞

一、哈希表介绍

1.1 哈希表初了解

哈希表是属于一个数据结构,并不是一个算法

哈希表:hashtable,也叫散列表,根据关键码值(Key value)而直接进行访问的数据结构。通过把关键码值映射到表中的一个位置来访问记录,以加快查找的速度。这个映射的函数叫做散列函数(柑橘关键码值能迅速的定位表中位置的方法),存放记录的数组叫做散列表。

需求:当有新员工来报道时,要求将该员工的信息加入(id,性别,年龄,住址….),当输入该员工的id时,要求查找到该员工的所有信息
要求:不使用数据库,尽量节省内存,越快越好

对于这种需求和要求,我们就可以 使用哈希表

每一次都查询数据库的话对数据库的压力很大,我们需要加一个缓存层(当然也可以加多个缓存层),缓存层的实现方式可以看下图。

比如,我们看下图,若我们用哈希表实现的缓存层,我们可以先把数据放在哈希表,当取数据时先在哈希表中取,取不到再到数据库,如果数据库有的话再给用户返回并添加到哈希表中。

7c8db1bd560e43f52bd7f81dbc817cc7.png

1.2 哈希表的内存结构图

百度来的,不是自己做的

数据+链表的形式,形成散列表(也叫哈希表)

先用散列函数进行计算,看看查找的数据下标进行计算,这样就直接精确到某条链表,更快的查找效率

38965c3384487e59e5c304d6524f1909.png

1.3哈希表实现思路图解

f3830a26887d450e971897ab00e51797.png

二、代码实现

在之前链表的基础上又添加了一个数组而已,并没有那么的难

哈希表在一定程度上就是一个缓存层但是没有redis缓存那么强大

  1. public class HashTabDemo {
  2. public static void main(String[] args) {
  3. // 创建hash表
  4. HashTab hashTab = new HashTab(7);
  5. Emp emp = new Emp(5, "Tom");
  6. Emp emp2 = new Emp(10, "Tom");
  7. Emp emp3 = new Emp(11, "Tom");
  8. Emp emp4 = new Emp(12, "Tom");
  9. hashTab.add(emp);
  10. hashTab.add(emp2);
  11. hashTab.add(emp3);
  12. hashTab.add(emp4);
  13. hashTab.list();
  14. hashTab.findEmpById(6);
  15. }
  16. }
  17. /**
  18. * 创建HashTab,管理多条链表
  19. */
  20. class HashTab {
  21. // 链表EmpLinked类型的数组
  22. private EmpLinkedList[] empLinkedListArray;
  23. // 我们要创建的数组的大小,表示最多有多少条链表
  24. private int size;
  25. /**
  26. * 构造方法
  27. *
  28. * @param size 指定empLinkedListArray数组的大小
  29. */
  30. public HashTab(int size) {
  31. this.size = size;
  32. // 初始化empLinkedListArray,记住,这个仅仅是将数组创建出来了,即 empLinkedListArray!=null,但是 empLinkedListArray[i]==null
  33. empLinkedListArray = new EmpLinkedList[size];
  34. // 有坑,不要忘记这个操作!!!!!!
  35. // 一定给要记好下面的初始化数组下标对应的链表,即让empLinkedListArray[i]!=null
  36. for (int i = 0; i < size; i++) {
  37. empLinkedListArray[i] = new EmpLinkedList();
  38. }
  39. }
  40. /**
  41. * 添加雇员:
  42. * 根据员工的id,得到该员工应该添加到哪条链表之上
  43. *
  44. * @param emp 要添加的雇员
  45. */
  46. public void add(Emp emp) {
  47. //根据员工的确定员工在哪条链之上
  48. int empLinkedListNo = hashFun(emp.id);
  49. //EmpLinkedList就是链表,在链表上进行添加
  50. empLinkedListArray[empLinkedListNo].add(emp);
  51. }
  52. /**
  53. * 遍历hash表(数组+链表共同组成hash表)
  54. */
  55. public void list() {
  56. for (int i = 0; i < size; i++) {
  57. // 数组的每一个元素都是一个列表
  58. empLinkedListArray[i].list(i);
  59. }
  60. }
  61. /**
  62. * 根据用户的id,查找雇员
  63. *
  64. * @param id
  65. * @return
  66. */
  67. public void findEmpById(int id) {
  68. // 根据id我们先确定好在哪条链
  69. int empLinkedListNO = hashFun(id);
  70. // 确定好链之后我们再从链中找元素
  71. Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);
  72. if (emp != null) {
  73. // 找到
  74. System.out.println("在"+empLinkedListNO+"中找到雇员:"+emp.id+"---->"+emp.name);
  75. } else {
  76. // 没有找到
  77. System.out.println("没有在哈希表中找到该雇员 ");
  78. }
  79. }
  80. /**
  81. * 编写散列函数,使用一个简单取模法
  82. * 作用:根据员工的id确定在哪条链表之上
  83. *
  84. * @param id
  85. * @return
  86. */
  87. public int hashFun(int id) {
  88. return id % size;
  89. }
  90. }
  91. /**
  92. * 表示雇员
  93. */
  94. class Emp {
  95. public int id;
  96. public String name;
  97. public Emp next; //指向下一个节点的引用 next默认为空就可以了
  98. public Emp(int id, String name) {
  99. this.id = id;
  100. this.name = name;
  101. }
  102. }
  103. /**
  104. * 表示链表
  105. */
  106. class EmpLinkedList {
  107. // 头指针,链表的head,指向第一个雇员Emp,因此我们这里直接这么写就可以
  108. private Emp head; //默认为空
  109. /**
  110. * 添加雇员到列表
  111. * 说明:
  112. * 假定,添加雇员时,id是自增长的,即id的分配总是从小到达,因此我们将该雇员加入到本链表的最后即可
  113. *
  114. * @param emp
  115. */
  116. public void add(Emp emp) {
  117. if (head == null) {
  118. // head为空说明是第一个雇员,直接将雇员emp赋值给head
  119. head = emp;
  120. // 添加成功直接返回
  121. return;
  122. }
  123. // 运行到这里说明不是第一个雇员,接下来我们就要遍历链表找到对应的地方添加进去
  124. Emp curEmp = head;
  125. while (curEmp.next != null) {
  126. // 移动指针
  127. curEmp = curEmp.next;
  128. }
  129. // 运行到这里curEmp的next是null,我们加在这里就好了
  130. curEmp.next = emp;
  131. }
  132. /**
  133. * 遍历链表的雇员信息
  134. */
  135. public void list(int number) {
  136. if (head == null) {
  137. // 链表为空
  138. System.out.println("第" + number + "条链表为空");
  139. return;
  140. }
  141. System.out.println("第" + number + "条链表的信息为:");
  142. // 辅助指针遍历链表
  143. Emp curEmp = head;
  144. while (curEmp != null) {
  145. System.out.println("====>id=" + curEmp.id + "-----name=" + curEmp.name);
  146. // 指针后移动
  147. curEmp = curEmp.next;
  148. }
  149. // 单纯的想输出一个换行
  150. System.out.println();
  151. }
  152. /**
  153. * 如果查找到,就返回Emp,没找到返回空
  154. *
  155. * @param id
  156. * @return
  157. */
  158. public Emp findEmpById(int id) {
  159. if (head == null) {
  160. System.out.println("链表为空");
  161. // 就不用再往下找了
  162. return null;
  163. }
  164. // 辅助指针
  165. Emp curEmp = head;
  166. // 遍历所在的链
  167. while (curEmp != null) {
  168. if (curEmp.id == id) {
  169. break;
  170. }
  171. // 后移
  172. curEmp = curEmp.next;
  173. }
  174. // 这个情况可能是找到了返回结果,也有可能是这个链上直接没有返回的null
  175. return curEmp;
  176. }
  177. }

619f6d9113ca90e164fe47f2f529af2f.png

发表评论

表情:
评论列表 (有 0 条评论,256人围观)

还没有评论,来说两句吧...

相关阅读

    相关 数据结构 -

    哈希表基本介绍 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访

    相关 数据结构——

    1、基础知识 1.1 引子 在实现编程中,常常面临着两个问题:存储和查询。存储和查询的效率往往决定了整个程序的效率。而我们常见存储数据的数据结构比如线性表,树等。数