动态数组实现链地址法哈希表

通常情况下哈希函数的输入空间远大于输出空间,因此理论上哈希冲突是不可避免的。比如,输入空间为全体整数,输出空间为数组容量大小,则必然有多个整数映射至同一数组索引。

解决哈希冲突方法常见有:链地址法、开放寻址法。

注意无论是开放寻址还是链地址法,它们只能保证哈希表可以在发生冲突时正常工作,但无法减少哈希冲突的发生。常见的哈希算法有:DM5、sha-1、sha-2和sha-3。

在原始哈希表中,每个桶仅能存储一个键值对。「链式地址 separate chaining」将单个元素转换为链表,将键值对作为链表节点,将所有发生冲突的键值对都存储在同一链表中。 

package com.wei.mybatisflex.demo;

import java.util.ArrayList;
import java.util.List;

/**
 * 链式地址哈希表
 */
public class HashMapChaining {
    int size; // 键值对数量
    int capacity; // 哈希表容量
    double loadThres; // 触发扩容的负载因子阈值=(键值对数量/哈希表容量) 标准为: 0.75
    int extendRatio; // 扩容倍数
    List<List<Pair>> buckets; // 桶数组,这里用动态数组List<Pair>代替链表,一个桶就是一个链表。

    /**
     * 键值对定义
     */
    class Pair{
        private int key;
        private String val;

        public Pair(int key, String val) {
            this.key = key;
            this.val = val;
        }
    }

    /* 构造方法 */
    public HashMapChaining() {
        size = 0;
        capacity = 4;
        loadThres = 2 / 3.0;
        extendRatio = 2;
        buckets = new ArrayList<>(capacity);
        for (int i = 0; i < capacity; i++) {
            buckets.add(new ArrayList<>());
        }
    }

    /* 哈希函数 */
    int hashFunc(int key) {
        return key % capacity;
    }

    /* 负载因子 */
    double loadFactor() {
        return (double) size / capacity;
    }

    /* 查询操作 */
    String get(int key) {
        int index = hashFunc(key);
        List<Pair> bucket = buckets.get(index);
        // 遍历桶,若找到 key 则返回对应 val
        for (Pair pair : bucket) {
            if (pair.key == key) {
                return pair.val;
            }
        }
        // 若未找到 key 则返回 null
        return null;
    }
    /* 添加操作 */
    void put(int key, String val) {
        // 当负载因子超过阈值时,执行扩容
        if (loadFactor() > loadThres) {
            extend();
        }
        int index = hashFunc(key);
        List<Pair> bucket = buckets.get(index);
        // 遍历桶,若遇到指定 key ,则更新对应 val 并返回
        for (Pair pair : bucket) {
            if (pair.key == key) {
                pair.val = val;
                return;
            }
        }
        // 若无该 key ,则将键值对添加至尾部
        Pair pair = new Pair(key, val);
        bucket.add(pair);
        size++;
    }
    /* 删除操作 */
    void remove(int key) {
        int index = hashFunc(key);
        List<Pair> bucket = buckets.get(index);
        // 遍历桶,从中删除键值对
        for (Pair pair : bucket) {
            if (pair.key == key) {
                bucket.remove(pair);
                size--;
                break;
            }
        }
    }

    /* 扩容哈希表 */
    void extend() {
        // 暂存原哈希表
        List<List<Pair>> bucketsTmp = buckets;
        // 初始化扩容后的新哈希表
        capacity *= extendRatio;
        buckets = new ArrayList<>(capacity);
        for (int i = 0; i < capacity; i++) {
            buckets.add(new ArrayList<>());
        }
        size = 0;
        // 将键值对从原哈希表搬运至新哈希表
        for (List<Pair> bucket : bucketsTmp) {
            for (Pair pair : bucket) {
                put(pair.key, pair.val);
            }
        }
    }

    /* 打印哈希表 */
    void print() {
        for (List<Pair> bucket : buckets) {
            List<String> res = new ArrayList<>();
            for (Pair pair : bucket) {
                res.add(pair.key + " -> " + pair.val);
            }
            System.out.println(res);
        }
    }
    /**
     * 测试
     */
    public static void main(String[] args) {
        HashMapChaining hashMapChaining = new HashMapChaining();
        hashMapChaining.put(123, "23");
        hashMapChaining.put(124, "24");
        hashMapChaining.put(125, "25");
        hashMapChaining.put(126, "26");


        System.out.println("哈希表展示如下:");
        hashMapChaining.print();
        System.out.println("==================");
        String s = hashMapChaining.get(123);
        System.out.println("k=123对应的val值是:"+s);
        System.out.println("==================");
        hashMapChaining.put(124, "99");
        System.out.println("把key=124的值换成99");
        hashMapChaining.print();
        System.out.println("==================");
        hashMapChaining.remove(124);
        System.out.println("删除key=124所对应的值:");
        hashMapChaining.print();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_35207086/article/details/132455252