哈希表

哈希表

哈希表是一种使用哈希函数组织数据,以支持快速插入和搜索的数据结构。

有两种不同类型的哈希表:哈希集合哈希映射

  • 哈希集合是集合数据结构的实现之一,用于存储非重复值。
  • 哈希映射是映射数据结构的实现之一,用于存储 (key, value) 键值对。

hashcode

使用 y = x % 5 作为哈希函数:

  • 插入:通过哈希函数解析键,将它们映射到相应的桶中。
    例如,1987 分配给桶 2,而 24 分配给桶 4 。
  • 搜索:通过相同的哈希函数解析键,并仅在特定存储桶中搜索。
    如果搜索 1987,将使用相同的哈希函数将 1987 映射到 2 。因此在桶 2 中搜索,并在那个桶中成功找到了 1987 。
    例如,如果搜索 23,将映射 23 到 3,并在桶 3 中搜索。发现 23 不在桶 3 中,这意味着 23 不在哈希表中。

哈希集合 java.util.HashSet

在 Java 中引入哈希集合

	Set<Integer> hashSet = new HashSet<>(); 

哈希映射 java.util.HashMap

在 Java 中引入哈希集合

	Map<String,Integer> hashMap =  new HashMap<>();

设计原则

  1. 一致性:如果 a == b,则 hash(a) == hash(b)
  2. 高效性:计算高效简便
  3. 均匀性:哈希值均匀分布

Java 标准类库中的 HashCode

  • 测试代码
public class Main {

    public static void main(String[] args) {
        int a = 28;
        System.out.println(((Integer) a).hashCode());
        int b = -28;
        System.out.println(((Integer) b).hashCode());

        double d = 28.0;
        System.out.println(((Double) d).hashCode());

        String s = "leifchen";
        System.out.println(s.hashCode());

        User user = new User("leifchen", 28);
        System.out.println(user.hashCode());
        User user2 = new User("LeifChen", 28);
        System.out.println(user2.hashCode());
        System.out.println(user.equals(user2));
    }
}
  • 结果
28
-28
1077673984
1791826212
-287961287
-287961287
true

自定义实现哈希表

import java.util.TreeMap;

/**
 * 哈希表
 */
public class HashTable<K, V> {

    private static final int UPPER_TOL = 10;
    private static final int LOWER_TOL = 2;
    private final int[] capacity = {53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
            49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
            12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741};

    private TreeMap<K, V>[] hashTable;
    private int mod;
    private int size;
    private int capacityIndex = 0;

    public HashTable() {
        this.mod = capacity[capacityIndex];
        size = 0;
        hashTable = new TreeMap[mod];
        for (int i = 0; i < mod; i++) {
            hashTable[i] = new TreeMap<>();
        }
    }

    public int getSize() {
        return size;
    }

    public void add(K key, V value) {
        TreeMap<K, V> map = hashTable[hash(key)];
        if (map.containsKey(key)) {
            map.put(key, value);
        } else {
            map.put(key, value);
            size++;

            if (size >= UPPER_TOL * mod && capacityIndex + 1 < capacity.length) {
                capacityIndex++;
                resize(capacity[capacityIndex]);
            }
        }
    }

    public V remove(K key) {
        TreeMap<K, V> map = hashTable[hash(key)];
        V ret = null;
        if (map.containsKey(key)) {
            ret = map.remove(key);
            size--;

            if (size < LOWER_TOL * mod && capacityIndex - 1 >= 0) {
                capacityIndex--;
                resize(capacity[capacityIndex]);
            }
        }

        return ret;
    }

    public V get(K key) {
        return hashTable[hash(key)].get(key);
    }

    public void set(K key, V value) {
        TreeMap<K, V> map = hashTable[hash(key)];
        if (!map.containsKey(key)) {
            throw new IllegalArgumentException(key + " doesn't exist!");
        }
        map.put(key, value);
    }

    public boolean contains(K key) {
        return hashTable[hash(key)].containsKey(key);
    }

    /**
     * 计算哈希值
     */
    private int hash(K key) {
        return (key.hashCode() & 0x7fffffff % mod);
    }

    /**
     * 动态扩容
     */
    private void resize(int newMod) {
        TreeMap<K, V>[] newHashTable = new TreeMap[newMod];
        for (int i = 0; i < newMod; i++) {
            newHashTable[i] = new TreeMap<>();
        }

        int oldMod = mod;
        this.mod = newMod;
        for (int i = 0; i < oldMod; i++) {
            TreeMap<K, V> map = hashTable[i];
            for (K key : map.keySet()) {
                newHashTable[hash(key)].put(key, map.get(key));
            }
        }

        this.hashTable = newHashTable;
    }
}

参考

[1] LeetCode
[2] Code

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值