提示信息

深入了解哈希表及冲突解决:Java模拟实现

无言 已关注

哈希表是一种非常高效的数据结构,通过一个称为哈希函数的函数将键映射到存储桶或槽中,从而实现快速的数据存取。然而,由于不同的键可能会哈希到相同的值——这种现象称为“冲突”——因此需要有效的冲突解决策略。以下是关于哈希表的深入分析以及如何在Java中模拟实现,包括常见的冲突解决方法。

哈希表基础

  1. 哈希函数:用于将输入(键)转换为整数(哈希值),再将其取模数组大小以得到数组索引。
  2. 负载因子:表示当前哈希表的填充程度,通常用已存元素个数除以数组大小来表示。当负载因子超过某个阈值时,通常需要调整(如扩容)。

冲突解决策略

  1. 链地址法(分离链接法)

    • 每个桶(数组中的每个位置)维护一个链表,所有哈希到同一个值的元素都存储在该链表中。
  2. 开放地址法(开放定址法)

    • 所有元素都存储在数组中,通过探测序列来解决冲突,常用的探测方法有线性探测、二次探测和双重哈希。

Java模拟实现

下面是用Java实现上述两种常用冲突解决方法的示例代码:

1. 链地址法
  1. import java.util.LinkedList;
  2. class HashTableChaining<K, V> {
  3. private class Node {
  4. K key;
  5. V value;
  6. Node(K key, V value) {
  7. this.key = key;
  8. this.value = value;
  9. }
  10. }
  11. private LinkedList<Node>[] table;
  12. private int size;
  13. private static final int DEFAULT_CAPACITY = 10;
  14. public HashTableChaining() {
  15. table = new LinkedList[DEFAULT_CAPACITY];
  16. for (int i = 0; i < table.length; i++) {
  17. table[i] = new LinkedList<>();
  18. }
  19. size = 0;
  20. }
  21. private int hash(K key) {
  22. return (key.hashCode() & 0x7fffffff) % table.length;
  23. }
  24. public void put(K key, V value) {
  25. int index = hash(key);
  26. for (Node node : table[index]) {
  27. if (node.key.equals(key)) {
  28. node.value = value;
  29. return;
  30. }
  31. }
  32. table[index].add(new Node(key, value));
  33. size++;
  34. }
  35. public V get(K key) {
  36. int index = hash(key);
  37. for (Node node : table[index]) {
  38. if (node.key.equals(key)) {
  39. return node.value;
  40. }
  41. }
  42. return null;
  43. }
  44. public boolean remove(K key) {
  45. int index = hash(key);
  46. LinkedList<Node> bucket = table[index];
  47. for (Node node : bucket) {
  48. if (node.key.equals(key)) {
  49. bucket.remove(node);
  50. size--;
  51. return true;
  52. }
  53. }
  54. return false;
  55. }
  56. public int size() {
  57. return size;
  58. }
  59. }
2. 开放地址法(线性探测)
  1. class HashTableOpenAddressing<K, V> {
  2. private class Node {
  3. K key;
  4. V value;
  5. Node(K key, V value) {
  6. this.key = key;
  7. this.value = value;
  8. }
  9. }
  10. private Node[] table;
  11. private int size;
  12. private static final int DEFAULT_CAPACITY = 10;
  13. private static final double LOAD_FACTOR = 0.75;
  14. public HashTableOpenAddressing() {
  15. table = new Node[DEFAULT_CAPACITY];
  16. size = 0;
  17. }
  18. private int hash(K key, int probe) {
  19. return (key.hashCode() & 0x7fffffff + probe) % table.length;
  20. }
  21. public void put(K key, V value) {
  22. if (size >= LOAD_FACTOR * table.length) {
  23. resize();
  24. }
  25. int probe = 0;
  26. int index = hash(key, probe);
  27. while (table[index] != null && !table[index].key.equals(key)) {
  28. probe++;
  29. index = hash(key, probe);
  30. }
  31. if (table[index] == null) {
  32. size++;
  33. }
  34. table[index] = new Node(key, value);
  35. }
  36. public V get(K key) {
  37. int probe = 0;
  38. int index = hash(key, probe);
  39. while (table[index] != null && !table[index].key.equals(key)) {
  40. probe++;
  41. index = hash(key, probe);
  42. }
  43. return table[index] != null ? table[index].value : null;
  44. }
  45. public boolean remove(K key) {
  46. int probe = 0;
  47. int index = hash(key, probe);
  48. while (table[index] != null && !table[index].key.equals(key)) {
  49. probe++;
  50. index = hash(key, probe);
  51. }
  52. if (table[index] != null) {
  53. table[index] = null;
  54. size--;
  55. return true;
  56. }
  57. return false;
  58. }
  59. private void resize() {
  60. Node[] oldTable = table;
  61. table = new Node[oldTable.length * 2];
  62. size = 0;
  63. for (Node node : oldTable) {
  64. if (node != null) {
  65. put(node.key, node.value);
  66. }
  67. }
  68. }
  69. public int size() {
  70. return size;
  71. }
  72. }

小结

  1. 链地址法适合在负载因子较高时使用,因为影响的是链表长度,不是整体结构。
  2. 开放地址法在负载因子低时性能更优,但是探测可能耗费更多时间。

在实际使用中,选择合适的哈希表实现和参数设置(如哈希函数、负载因子)是关键,以达到优化性能的目的。Java中的HashMap类本质上也是采用了链地址法的方式实现的。

    遇到难题? "AI大模型GPT4.0、GPT" 是你的私人解答专家! 点击按钮去提问......
无言 关注 已关注

最近一次登录:2024-11-20 21:11:29   

暂时还没有签名,请关注我或评论我的文章
×
免费图表工具,画流程图、架构图