设计一个HashSet [hash函数 + 存数据的数组 + hash冲突]

340 阅读1分钟

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第11篇文章,设计一个HashSet [hash函数 + 存数据的数组 + hash冲突] - 掘金 (juejin.cn)

前言

hashSet拆分即hash & set,设计hash需要确定hash函数 + 存数据的数组 + hash冲突的解决办法。对于set,hash的key天然的不重复,所以直接用key作为set的元素即保证不重复性。

一、设计hash集合

image.png

二、hash函数+数组+拉链法

1、常规设计

// 设计一个hashSet
public class MyHashSet {
    Node[] table;
    private final static int N = 769;// 取一个质数作为数组长度,减少冲突。

    public MyHashSet() {
        table = new Node[N];
        // 设置头节点,统一操作。
        for (int i = 0; i < N; i++) table[i] = new Node();
    }
    // 三个操作都是:找key映射到的头节点,然后链表寻找是否有对应的key.
    public void add(int key) {
        int h = hash(key);

        Node p = table[h];
        while (p.next != null) {
            // 有此key,就不用再添加了。
            if (key == p.next.key) return;

            p = p.next;
        }
        Node n = new Node();
        n.key = key;

        p.next = n;
    }

    public void remove(int key) {
        int h = hash(key);

        Node p = table[h];
        while (p.next != null) {
            // 有此key,才把其移除掉,并break出去。
            if (p.next.key == key) {
                p.next = p.next.next;

                break;
            }
            p = p.next;
        }
    }

    public boolean contains(int key) {
        int h = hash(key);

        Node p = table[h];
        while (p.next != null) {
            // 找到就返回。
            if (p.next.key == key) return true;

            p = p.next;
        }
        return false;
    }
    // 对key进行扰乱,再对质数取余。
    private int hash(int key) {
        key = (key >>> 16) ^ key;

        return key % N;
    }

    // hash冲突时,用拉链法解决。
    class Node {
        int key;
        Node next;
    }
}

2、常见的数组hash

class MyHashSet {
    final static int N = 1000000;
    int[] fx = new int[N + 1];
    public MyHashSet() {

    }
    
    public void add(int key) {
        fx[key] = 1;
    }
    
    public void remove(int key) {
        // 是1就变0,是0就不管。
        fx[key] = 0;
    }
    
    public boolean contains(int key) {
        return fx[key] == 1;
    }
}

总结

1)hash三要素:hash函数 + 存数据的数组 + hash冲突的解决方式。

2)hash函数有很多,比如线性法/平方法,hash冲突的方式也有很多,拉链法/线性探测法/平方探测法等等,以后算法能力提高了,还可以用红黑树数据结构来解决冲突,降低搜索时间复杂度。

参考文献

[1] LeetCode 设计一个hash集合