Dynamic array implements chain address method hash table

Usually the input space of a hash function is much larger than the output space, so theoretically hash conflicts are inevitable. For example, if the input space is all integers and the output space is the array capacity, there must be multiple integers mapped to the same array index.

Common methods to resolve hash conflicts include: chain address method and open addressing method.

Note:Whether it is open addressing or chain address method,they can only guarantee the hash The table can function normally when collisions occur, but it cannot reduce the occurrence of hash collisions. Common hashing algorithms are: DM5, sha-1, sha-2 and sha-3.

In the original hash table, each bucket can only store one key-value pair. "Separate chaining address" converts a single element into a linked list, uses key-value pairs as linked list nodes, and stores all conflicting key-value pairs in the same linked list.​ 

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();
    }
}

Guess you like

Origin blog.csdn.net/qq_35207086/article/details/132455252