哈希及 Java 实现

1、哈希

哈希(Hash):也称散列,是一种时间换空间的算法思想。

哈希函数(哈希算法):设置一定的计算规则,将任意长度的输入,变换成固定长度的输出

  1. 关键码值:元素中能起标识作用的数据,作为哈希函数的输入。

  2. 哈希值:哈希函数的输出。

    关键码值(key)  -->  【哈希函数】  -->  哈希值(hash)
    

1.1、哈希表

哈希表(Hash Table):一种数据结构。

基于哈希函数建立的表。

  1. 映射过程基于关键码值(key)计算出哈希值(hash),映射到表中的某个位置
  2. 映射位置:有两种方案。
    1. hash 直接作为存放位置。
    2. 基于 hash 计算存放位置。

1.2、哈希冲突

哈希冲突:也称哈希碰撞。

根据不同的输入,计算出了相同的哈希值

常见解决方法

  1. 开放寻址法:基于产生冲突的地址(H0),重新计算直到得出可用地址(Hi)。
    1. 计算公式Hi = (H0 + di) % m
    2. 寻址方式:根据 m 的不同取值。
      • 线性探测再散列:1,2,3,...,m-1
      • 平方探测再散列:1,2,-2,4,-4,...,k2,-k2
      • 随机探测再散列:伪随机数
  2. 再哈希法:构造多个哈希函数,产生冲突时使用另一个函数计算,直到得出可用地址。
  3. 链地址法(拉链法):在产生冲突的位置上,形成链表。
  4. 建立公共溢出区:将哈希表分为基本表和溢出表,凡是冲突的元素就放入溢出表。

2、Java 哈希

2.1、集合

2.1.1、存储结构

(参考 HashMap 源码)哈希表 = 数组 + 位桶

  1. 结点类:哈希表中的基本元素,称为 bucket(位桶)。

    1. 哈希值
    2. 关键码值、元素值
    3. 后继结点
  2. 数组bucket 类型的数组,即哈希表。

    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        
        final K key;
        V value;
        
        Node<K,V> next;
    }
    
    transient Node<K,V>[] table;
    

2.1.2、哈希冲突

Java 基于链地址法解决哈希冲突。

(Java 1.8+ 还引入了红黑树)

image

2.2、检索机制

哈希集合中检索元素遵守的机制(包括增删改查)

2.2.1、涉及方法

👉 浅谈 equals() 和 hashCode()

  1. hashCode():计算对象哈希值,用于确定元素存储位置。
  2. equals():比较对象是否相等,用于正确检索数据。

2.2.2、流程示例

插入元素 x 的大致流程

(代码已简化处理,具体请看源码)

  1. 扰动函数:将对象的 hashCode() 进一步处理。

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    
  2. 计算存储位置(n - 1) & hash,等价于 hash % n

    Node<K,V>[] tab = table;	// 存储元素的哈希表
    int n = tab.size;	// 当前元素个数
    
    int i = (n - 1) & hash;		// 存储位置
    
  3. 判断待插入位置是否为空。

    1. :将元素放到数组下标处。

      tab[i] = newNode(hash, key, value, null);
      
    2. :遍历链表,逐个元素比较是否相等(hash 和 equals() 都相等)。

      1. 发现相等:说明已存在相同 key 的记录,不会重复添加。
      2. 遍历到链尾:说明不存在重复记录,完成元素插入操作。

关于哈希在 Java 中的实现,

具体查看 👉 漫谈 HashMap

posted @ 2022-04-20 13:58  Jaywee  阅读(66)  评论(0编辑  收藏  举报

👇