数据结构之哈希表HashTable实例讲解

╰+哭是因爲堅強的太久メ 2022-05-23 09:21 284阅读 0赞

哈希表 是一种以关联方式存储数据的数据结构,在哈希表中,数据以数组格式存储,其中每个数据值都有自己唯一的索引。如果我们知道所需数据的索引,那么数据的访问就会变得非常快。 所以关键是 找到索引, 而检索 数值关键字 到 索引 的方式就是 哈希(Hashing)。

因此,在这个结构中插入和搜索操作非常快,不管数据的大小。哈希表使用数组作为存储介质,并使用散列技术(就是我们的哈希算法)生成一个索引。

哈希(Hashing)

哈希是一种将一系列键值转换成数组的一系列索引的技术。我们以取模运算(基数是20)来演示哈希算法。
这里写图片描述

图解: 通过hash算法将左边的key映射到右边的存储数组中的索引值。

假定有以下值键组:注意:第二个值表示key,一般我们(是key,value)才是规范的写法。

(100, 1)
(100, 2)
(100, 42)
key分别为: 1, 2, 42; 使用哈希算法(取模,基数为20)后, 各自映射的索引值应该是: 1, 2, 2。如图:

这里写图片描述

哈希碰撞

哈希碰撞:就是不同key的哈希值是一样的。我们的实例:1,2,42 进行 20 取模后,就发生了哈希碰撞,其中2 和 42 哈希后的索引值是一样的。

线性推测(Linear Probing)

发生哈希碰撞后,我们可以使用简单的线性推测,依次往下寻找直到找到一个空的位置。像42,先哈希再进行线性推测后,索引值为3。因为索引2后面的索引位置3是空的坑位。

这里写图片描述

数据项

  1. class DataItem{
  2. int data;
  3. int key; //key关键字,对其使用哈希算法
  4. }

插入数据到hash存储结构中

  1. /** * 插入新值到hash表 * <pre> * hash后,发现坑位没有被占,则占有该坑位; * hash后,发现该坑位被占了: * Step1: key和新插入的key不登,则使用线性推测方式,按队列顺序往后打探下一个坑位的情况(这是一个循环表顺序) * Step2: 循环打探坑位:发现新坑位则占住 * </pre> * @param item */
  2. static void insert(DataItem item) {
  3. boolean standFlag = false;
  4. //获取hash索引
  5. int idx = hashCode(item.key);
  6. if( null != hashArray[idx] ) {
  7. if( hashArray[idx].key != item.key ) {
  8. //【被占】---》 则使用线性推测方式处理,找到空位进入
  9. while( null != hashArray[idx] && hashArray[idx].key != item.key ) {
  10. idx = hashCode( ++idx );
  11. if( null == hashArray[idx] ) {
  12. hashArray[idx] = item;
  13. standFlag = true;
  14. }
  15. }
  16. }
  17. }else {
  18. //hash索引处为empty,则坑可用,直接存储
  19. hashArray[idx] = item;
  20. standFlag = true;
  21. }
  22. if( !standFlag ) {
  23. System.err.println("插入失败!");
  24. }
  25. }

检索

  1. /** * 发生hash冲突时,检索效率就会低了,所以hash算法很关键,唯一的最好 * @param key * @return */
  2. static DataItem search(int key) {
  3. int idx = hashCode(key);
  4. while(null != hashArray[idx]) {
  5. //如果存在了哈希冲突(即哈希值已经被占用了)
  6. if(hashArray[idx].key == key) {
  7. //如果hash相同的索引key值一样则检索到了
  8. return hashArray[idx];
  9. }
  10. //hash冲突,没有检索到,则线性推测查找
  11. idx++;
  12. //环绕检索,下一个索引位置
  13. idx = hashCode(idx);
  14. }
  15. return null;
  16. }

完整的哈希检索、插入程序示例

  1. package org.byron4j.dsaa;
  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import java.util.Collections;
  5. /** * hash 表数据结构实例详解 * <pre> * 在哈希表中,数据以数组格式存储,其中每个数据值都有自己唯一的索引 * 哈希是一种将一系列键值转换成数组的一系列索引的技术 * </pre> * @author BYRON.Y.Y * */
  6. public class HashTableExample {
  7. private static int SIZE = 20;
  8. private static DataItem[] hashArray = new DataItem[20];
  9. public static void main(String[] args) {
  10. System.out.println(Arrays.asList(hashArray));
  11. /*insert(new DataItem(100, 1)); insert(new DataItem(100, 2)); insert(new DataItem(100, 42)); insert(new DataItem(100, 62)); insert(new DataItem(100, 82)); insert(new DataItem(100, 102)); insert(new DataItem(100, 122)); insert(new DataItem(100, 142));*/
  12. //打乱顺序测试hash
  13. insert(new DataItem(100, 1));
  14. insert(new DataItem(100, 2));
  15. insert(new DataItem(100, 102));
  16. insert(new DataItem(100, 122));
  17. insert(new DataItem(100, 42));
  18. insert(new DataItem(100, 82));
  19. insert(new DataItem(100, 62));
  20. insert(new DataItem(100, 142));
  21. insert(new DataItem(100, 162));
  22. insert(new DataItem(100, 182));
  23. insert(new DataItem(100, 202));
  24. insert(new DataItem(100, 222));
  25. insert(new DataItem(100, 242));
  26. insert(new DataItem(100, 282));
  27. insert(new DataItem(100, 262));
  28. insert(new DataItem(100, 302));
  29. insert(new DataItem(100,322));
  30. insert(new DataItem(100, 342));
  31. insert(new DataItem(100,362));
  32. insert(new DataItem(100, 382));
  33. System.out.println(Arrays.asList(hashArray));
  34. }
  35. static class DataItem{
  36. int data;
  37. int key;
  38. public DataItem(int data, int key) {
  39. super();
  40. this.data = data;
  41. this.key = key;
  42. }
  43. @Override
  44. public String toString() {
  45. return "DataItem [key=" + key + "]";
  46. }
  47. }
  48. /**简易Hash方法,取模*/
  49. static int hashCode(int key){
  50. return key % SIZE;
  51. }
  52. /** * 发生hash冲突时,检索效率就会低了,所以hash算法很关键,唯一的最好 * @param key * @return */
  53. static DataItem search(int key) {
  54. int idx = hashCode(key);
  55. while(null != hashArray[idx]) {
  56. //如果存在了哈希冲突(即哈希值已经被占用了)
  57. if(hashArray[idx].key == key) {
  58. //如果hash相同的索引key值一样则检索到了
  59. return hashArray[idx];
  60. }
  61. //hash冲突,没有检索到,则线性推测查找
  62. idx++;
  63. //环绕检索,下一个索引位置
  64. idx = hashCode(idx);
  65. }
  66. return null;
  67. }
  68. /** * 插入新值到hash表 * <pre> * hash后,发现坑位没有被占,则占有该坑位; * hash后,发现该坑位被占了: * Step1: key和新插入的key不等,则使用线性推测方式,按队列顺序往后打探下一个坑位的情况(这是一个循环表顺序) * Step2: 循环打探坑位:发现新坑位则占住 * </pre> * @param item */
  69. static void insert(DataItem item) {
  70. boolean standFlag = false;
  71. //获取hash索引
  72. int idx = hashCode(item.key);
  73. if( null != hashArray[idx] ) {
  74. if( hashArray[idx].key != item.key ) {
  75. //【被占】---》 则使用线性推测方式处理,找到空位进入
  76. while( null != hashArray[idx] && hashArray[idx].key != item.key ) {
  77. idx = hashCode( ++idx );
  78. if( null == hashArray[idx] ) {
  79. hashArray[idx] = item;
  80. standFlag = true;
  81. }
  82. }
  83. }
  84. }else {
  85. //hash索引处为empty,则坑可用,直接存储
  86. hashArray[idx] = item;
  87. standFlag = true;
  88. }
  89. if( !standFlag ) {
  90. System.err.println("插入失败!");
  91. }
  92. }
  93. }

运行结果如下:

  1. [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]
  2. [DataItem [key=382], DataItem [key=1], DataItem [key=2], DataItem [key=102], DataItem [key=122], DataItem [key=42], DataItem [key=82], DataItem [key=62], DataItem [key=142], DataItem [key=162], DataItem [key=182], DataItem [key=202], DataItem [key=222], DataItem [key=242], DataItem [key=282], DataItem [key=262], DataItem [key=302], DataItem [key=322], DataItem [key=342], DataItem [key=362]]

发表评论

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

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

相关阅读

    相关 数据结构

    > 最近看PHP数组底层结构,用到了哈希表,所以还是老老实实回去看结构,在这里去总结一下。 1.哈希表的定义   这里先说一下哈希表的定义:哈希表是一种根据关键码去寻找

    相关 C# Hashtable

    一 哈希表的定义: 它使用键来访问集合中的元素。当您使用键访问元素时,则使用哈希表,而且您可以识别一个有用的键值。哈希表中的每一项都有一个键/值对。键用于访问集合中的项目。

    相关 数据结构

    1.哈希表的定义   这里先说一下哈希表的定义:哈希表是一种根据关键码去寻找值的数据映射结构,该结构通过把关键码映射的位置去寻找存放值的地方,说起来可能感觉有点复杂,我想