哈希表

谁践踏了优雅 2023-01-13 04:14 169阅读 0赞

哈希表

  • 概念
  • 哈希函数设计
  • 冲突
    • 调节负载因子
  • 冲突解决
    • 闭散列
    • 开散列/哈希桶
  • 实现自己的哈希表:

概念

理想的搜索方法:不经过任何比较,一次直接从表中得到想要的搜索元素。
构造某种存储结构,通过某种函数(hashfunc)使元素的存储位置与他的关键key之间建立一一映射的关系,在查找的时候,可以很快找到该元素。

哈希方法中使用的转换函数称为哈希(散列)函数,构造出的数据结构称为哈希表(HashTable)(后者称为散列表)

哈希函数设计

常见的哈希函数:
1、直接定制法:
Hash(key)= A*key+B
优点:简单均匀
2、除留余数法——(常用)
Hash(key) = key%p(p<=m)
3、

冲突

冲突的发生是必然的,我们要做的是降低冲突率
例如使用除留余数法,会出现相同的余数的情况,(出现相同的哈希地址),这种情况称为哈希冲突(哈希碰撞)
避免冲突的方法:
1、设计好的哈希函数
2、负载因子的调节

调节负载因子

负载因子的计算是通过:
填入表中的元素 / 散列表的长度在这里插入图片描述
已知哈希表中的关键字个数是不可变的,那么我们只能调整哈希表中数组的大小。

冲突解决

闭散列

闭散列:也叫开放地址法,当发生冲突的时候,如果哈希表未被填满,那么就说明哈希表中还有空位,就将key放在冲突位置的“下一个”空位中。

开散列/哈希桶

开散列法,又叫链地址法,首先通过关键码集合用散列函数计算地址,将相同地址关键码放在同一子集合中,每个子集合称一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存在哈希表中。

简单理解就是:
一个数组,数组中存存链表的头结点,发生冲突的元素放在链表中。

注意:
假如元素发生聚集,那么就会退回成链表,所以需要我们合理解决冲突。
通常情况下我们认为哈希表的冲突率不高,冲突个数是可控的,每个桶中的链表长度是一个常数,所以通常意义上,我们认为哈希表的插入/删除/查找的时间复杂度是O(1)

实现自己的哈希表:

结点:

  1. package HashTable;
  2. public class Node {
  3. int key;
  4. Node next;
  5. public Node(int key) {
  6. this.key = key;
  7. }
  8. @Override
  9. public String toString() {
  10. return "Node{" +
  11. "val=" + key +
  12. ", next=" + next +
  13. '}';
  14. }
  15. }

MyHashTable:

  1. package HashTable;
  2. public class MyHashTable {
  3. //存头结点的数组
  4. Node[] array;
  5. int size;
  6. public MyHashTable() {
  7. array = new Node[11];
  8. size = 0;
  9. }
  10. //冲突因子
  11. private double LOAD_FACTOR = 0.75;
  12. //插入——头插
  13. public boolean insert(int key) {
  14. if (find(key)) {
  15. return false;
  16. }
  17. int index = key % array.length;
  18. Node node = new Node(key);
  19. node.next = array[index];
  20. array[index] = node;
  21. size++;
  22. if ((double) size / array.length > LOAD_FACTOR) {
  23. grow();
  24. }
  25. return true;
  26. }
  27. //扩容
  28. //2倍扩容
  29. private void grow() {
  30. Node[] newArray = new Node[array.length * 2];
  31. for (Node head : array) {
  32. Node cur = head;
  33. while (cur != null) {
  34. int index = cur.key % newArray.length;
  35. Node next = cur.next;
  36. cur.next = newArray[index];
  37. newArray[index] = cur;
  38. cur = next;
  39. }
  40. }
  41. array = newArray;
  42. }
  43. //删除
  44. public boolean remove(int key) {
  45. int index = key % array.length;
  46. Node cur = array[index];
  47. Node prev = null;
  48. while (cur != null) {
  49. if (key == cur.key) {
  50. if (prev != null) {
  51. prev.next = cur.next;
  52. } else {
  53. array[index] = array[index].next;
  54. }
  55. size--;
  56. return true;
  57. }
  58. prev = cur;
  59. cur = cur.next;
  60. }
  61. return false;
  62. }
  63. //查找
  64. public boolean find(int key) {
  65. int index = key % array.length;
  66. for (Node cur = array[index]; cur != null; cur = cur.next) {
  67. if (cur.key == key) {
  68. return true;
  69. }
  70. }
  71. return false;
  72. }
  73. }

Test:

  1. package HashTable;
  2. import java.util.Random;
  3. public class Test {
  4. public static void main(String[] args) {
  5. Random random = new Random(2020412);
  6. MyHashTable hashTable = new MyHashTable();
  7. for (int i = 0; i < 10000; i++) {
  8. int key = random.nextInt();
  9. if (key >= 0 && !hashTable.find(key)) {
  10. hashTable.insert(key);
  11. }
  12. }
  13. int min = Integer.MAX_VALUE;
  14. int max = Integer.MIN_VALUE;
  15. int sum = 0;
  16. for (int i = 0; i < hashTable.array.length; i++) {
  17. Node cur = hashTable.array[i];
  18. int count = 0;
  19. while (cur != null) {
  20. count++;
  21. cur = cur.next;
  22. }
  23. if (count < min) {
  24. min = count;
  25. }
  26. if (count > max) {
  27. max = count;
  28. }
  29. sum += count;
  30. }
  31. System.out.println(hashTable.size);
  32. System.out.println(hashTable.array.length);
  33. System.out.println(max);
  34. System.out.println(min);
  35. System.out.println((double) sum / hashTable.array.length);
  36. }
  37. }

在这里插入图片描述

发表评论

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

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

相关阅读

    相关

    什么是哈希表    哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的[数据结构][Link 1]。也就是说,它通过把关键码

    相关

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

    相关

    我们知道,通过对数组进行直接寻址(Direct Addressing),可以在 O(1) 时间内访问数组中的任意元素。所以,如果存储空间允许,可以提供一个数组,为每个可能的关键

    相关

    哈希表是种数据结构,它可以提供快速的插入操作和查找操作。第一次接触哈希表时,它的优点多得让人难以置信。不论哈希表中有多少数据,插入和删除(有时包括侧除)只需要接近常量的时间即0

    相关

    一、简介 如果所有的键都是小整数,那么我们可以用一个数组来实现无序的符号表,将键作为数组的索引i而数组中i(键)处储存的就是对应的值。 这样就可以快速地访问任意键的值,

    相关

    【一】哈希表 > 他通过把关键码值映射到表中的一个位置来访问记录,以加快查找的速度。这个映射函数就是散列函数。 ![watermark_type_ZmFuZ3poZW5na