Skip to content

Hash散列

一、定义

哈希散列(Hashing)是一种重要的数据结构和算法,它被广泛应用于计算机科学和工程领域。哈希散列通过将任意长度的输入数据映射为固定长度的输出,将数据快速地存储和检索,同时保证数据的完整性和安全性。

二、原理

哈希散列的核心是哈希函数,它是一种将输入数据映射为固定长度的输出的算法。哈希函数的输出通常称为哈希值或散列码。好的哈希函数应该具备以下特性:

  1. 一致性:对于相同的输入,哈希函数应该始终产生相同的输出。
  2. 高效性:计算哈希值的时间应该很短。
  3. 低碰撞率:哈希函数应该将不同的输入均匀地映射到哈希空间中,以尽量减少碰撞的发生。

三、冲突解决

冲突是指不同的输入数据被映射到了相同的哈希值上。为了解决冲突,我们需要使用冲突解决方法,常见的方法包括:

  1. 链表法:在散列表的每个槽中存储一个链表,冲突的键值对被存储在同一个槽对应的链表中。
  2. 开放地址法:当发生冲突时,通过一定的算法(如线性探测、二次探测、双重散列等)寻找其他可用的槽位来存储冲突的键值对。
  3. 再哈希法(Rehashing):当发生冲突时,通过应用另一个散列函数来计算新的哈希值,然后将键值对存储到新的位置。这个新的位置通常与原始哈希值的一定偏移量相关联。再哈希法可以避免某些特定的冲突序列,但需要保证新的哈希函数满足一致性、高效性和均匀性的要求。
  4. Cuckoo Hashing:Cuckoo Hashing是一种高效的解决哈希冲突的方法,它通过使用两个散列表来存储数据。当发生冲突时,它会尝试将冲突的键重新哈希到另一个表中,如果另一个表中的位置已经被占用,那么会触发一系列的重新哈希操作,直到找到空闲的位置或达到最大重新哈希次数为止。Cuckoo Hashing通常具有良好的平均性能,但可能会导致插入操作的时间复杂度变为O(n),其中n是哈希表中的元素数量。
  5. 线性探测再哈希(Linear Probing with Rehashing):线性探测再哈希是一种结合了线性探测和再哈希法的冲突解决方法。当发生冲突时,它首先尝试在散列表中寻找下一个空闲的位置,如果找到则插入,如果散列表已满则触发再哈希操作来扩展散列表的大小。
  6. 分离链接法(Separate Chaining):分离链接法是一种使用链表来解决冲突的方法,它与传统的链表法类似,但是在每个槽中存储的是一个链表的头指针而不是整个链表。这样可以节省内存空间,并且在处理冲突时只需操作链表的指针而不需要移动数据,因此性能较好。

这些方法都有各自的优缺点,选择合适的冲突解决方法取决于应用的具体需求和性能要求。在实际应用中,可能会根据数据分布的特点和实际情况选择最合适的方法。

四、应用

哈希散列被广泛应用于各种场景:

  1. 散列表(Hash Table):散列表是一种基于哈希散列实现的数据结构,用于快速存储和检索数据。它通过哈希函数将键映射到索引位置,并在该位置存储对应的值。这样,在大多数情况下,查找、插入和删除操作的时间复杂度可以达到常数级别,即O(1)。
  2. 数据完整性检查:哈希函数在密码学中扮演着重要角色,用于验证数据的完整性。通过计算数据的哈希值并将其与预期的哈希值进行比较,可以检测出数据是否被篡改。
  3. 密码学:哈希函数被用于密码学中的各种算法,如消息摘要算法(MD5、SHA-1、SHA-256等)。它们用于生成消息的数字摘要,用于验证数据的完整性和生成数字签名。

五、实现

5.1 基于红黑树实现

/**
 * @Description hashMap
 * @Author lcy
 * @Date 2021/1/12 9:27
 */
public class HashMap<K,V> {

    /**
     * 红色节点
     */
    private static final boolean RED = true;

    /**
     * 黑色节点
     */
    private static final boolean BLACK = false;

    /**
     * 排序接口实现
     */
    protected Comparator<K> comparator = (o1,o2) -> {
        if (o1 != null && o2 != null) {
            if (o1.hashCode() == o2.hashCode() && o1.equals(o2)) {
                return 0;
            } else {
                return o1.hashCode() - o2.hashCode();
            }
        } else {
            throw new ServiceException("key could not be null");
        }
    };

    /**
     * 大小
     */
    private int size;

    /**
     * hash数组
     */
    private Node<K,V>[] table;

    /**
     * 默认数组长度,2的4次方
     */
    private static final int DEFAULT_CAPACITY = 1 << 4;

    /**
     * 装填因子
     */
    private static final float DEFAULT_LOAD_FACTORY = 0.75f;

    public HashMap(){
        table = new Node[DEFAULT_CAPACITY];
    }

    public HashMap(int capacity){
        table = new Node[capacity];
    }

    /**
     * 添加map
     * @param key   key
     * @param value value
     * @author lcy
     * @date 2021/1/5 16:17
     **/
    public V put(K key,V value){
        int hash = hash(key);
        int index = index(hash);

        //红黑树根节点
        Node<K,V> root = table[index];
        if (root == null) {
            root = new Node<>(key,value,null);
            table[index] = root;
            size++;
            changeBlack(root);
            return null;
        }

        Node<K,V> node = root;
        Node<K,V> parent;
        int cmp;
        Node<K,V> tmpNode;
        boolean isSearch = false;
        do {
            parent = node;
            if (hash > node.hash) {
                cmp = 1;
            } else if (hash < node.hash) {
                cmp = -1;
            } else if (Tools.equals(key,node.key)) {
                cmp = 0;
                //值不相等,进一步判断
            } else if (key != null && node.key != null &&
                    key.getClass() == node.key.getClass() && key instanceof Comparable
                    && (cmp = ((Comparable)key).compareTo(node.key)) != 0) {
                //hash相等,不具备可比较性
            } else if (isSearch) {
                cmp = System.identityHashCode(key) - System.identityHashCode(node.key);
            } else {
                if ((node.left != null && (tmpNode = node(node.left,key)) != null)
                        || node.right != null && (tmpNode = node(node.right,key)) != null) {
                    node = tmpNode;
                    cmp = 0;
                } else {
                    //不存在key
                    isSearch = true;
                    cmp = System.identityHashCode(key) - System.identityHashCode(node.key);
                }
            }
            if (cmp > 0) {
                node = node.right;
            } else if (cmp < 0) {
                node = node.left;
            } else {
                node.key = key;
                V oldValue = node.value;
                node.value = value;
                return oldValue;
            }

            //else {
            //    cmp = compare(key,node.key,hash,node.hash);
            //    //hashCode相等,值也相等,包含两个值都为null的情况
            //    if (!Tools.equals(key,node.key)) {
            //        //红黑树根节点
            //        int newIndex = (index + (1 << hashIndex)) & (table.length - 1);
            //        node = table[newIndex];
            //        hashIndex += 1;
            //        System.out.println(node);
            //        if (node == null) {
            //            node = new Node<>(key,value,null);
            //            table[newIndex] = node;
            //            size++;
            //            changeBlack(node);
            //            return null;
            //        } else {
            //            continue;
            //        }
            //    }
            //    node.key = key;
            //    V oldValue = node.value;
            //    node.value = value;
            //    return oldValue;
            //}
        } while (node != null);

        Node<K,V> newNode = new Node<>(key,value,parent);
        if (cmp > 0) {
            parent.right = newNode;
        } else {
            parent.left = newNode;
        }

        size++;
        afterAdd(newNode);
        return newNode.value;
    }

    /**
     * 判断key是否存在
     * @param key key
     * @return boolean
     * @author lcy
     * @date 2021/1/5 16:17
     **/
    public boolean containsKey(K key){
        return node(key) != null;
    }

    /**
     * 判断value是否存在
     * @param value value
     * @return boolean
     * @author lcy
     * @date 2021/1/5 16:17
     **/
    public boolean containsValue(V value){

        if (isEmpty()) {
            return false;
        }

        Queue<Node<K,V>> queue = new LinkedBlockingQueue<>();
        //遍历数组,数组里的红黑树层序遍历判断value是否存在
        for (Node<K,V> kvNode : table) {
            if (kvNode == null) {
                continue;
            }
            queue.offer(kvNode);
            while (!queue.isEmpty()) {
                Node<K,V> node = queue.poll();
                if (Tools.equals(node.value,value)) {
                    return true;
                }

                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
        }

        return false;
    }

    /**
     * 根据key获取value
     * @param key key
     * @return boolean
     * @author lcy
     * @date 2021/1/5 16:17
     **/
    public V get(K key){
        Node<K,V> node = node(key);
        return node == null ? null : node.value;
    }

    /**
     * 返回长度
     */
    public int size(){
        return size;
    }

    /**
     * 判断是否为空
     * @return boolean
     * @author lcy
     * @date 2020/9/3 20:58
     **/
    public boolean isEmpty(){
        return size == 0;
    }

    /**
     * 遍历打印map数据
     * @author lcy
     * @date 2021/1/12 19:10
     **/
    public void traversal(){
        if (isEmpty()) {
            return;
        }

        Queue<Node<K,V>> queue = new LinkedBlockingQueue<>();
        //遍历数组,数组里的红黑树层序遍历判断value是否存在
        for (Node<K,V> kvNode : table) {
            if (kvNode == null) {
                continue;
            }
            queue.offer(kvNode);
            while (!queue.isEmpty()) {
                Node<K,V> node = queue.poll();

                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
                System.out.print("[key={" + node.key + "},value={" + node.value + "},");

            }
        }
    }

    /**
     * 遍历打印map里红黑树数据
     * @author lcy
     * @date 2021/1/12 19:10
     **/
    public void print(){
        if (isEmpty()) {
            return;
        }

        //遍历数组,数组里的红黑树层序遍历判断value是否存在
        for (int i = 0; i < table.length; i++) {
            Node<K,V> kvNode = table[i];
            System.out.println("------------------index(" + i + ")-------------------");
            BinaryTrees.print(new BinaryTreeInfo() {

                @Override public Object root(){
                    return kvNode;
                }

                @Override public Object left(Object node){
                    return ((Node<K,V>)node).left;
                }

                @Override public Object right(Object node){
                    return ((Node<K,V>)node).right;
                }

                @Override public Object string(Object node){
                    return node;
                }
            });
            System.out.println();
            System.out.println("------------------index(" + i + ")-------------------");
        }
    }

    /**
     * 清除数二叉树
     * @author lcyb
     * @date 2020/9/3 20:56
     **/
    public void clear(){
        if (size == 0) {
            return;
        }

        size = 0;
        Arrays.fill(table,null);
    }

    /**
     * 删除指定对象
     * @param key 需要删除的对象
     * @author lcy
     * @date 2020/9/3 21:01
     **/
    public V remove(K key){
        return remove(node(key));
    }

    /**
     * 删除指定对象
     * @param deleteNode 需要删除的对象
     * @author lcy
     * @date 2020/9/3 21:01
     **/
    private V remove(Node<K,V> deleteNode){
        if (deleteNode == null) {
            return null;
        }
        size--;

        if (deleteNode.hasTwoChildren()) {
            //获取后继节点
            Node<K,V> successor = successor(deleteNode);
            if (successor != null) {
                //替换节点值为后继节点值
                deleteNode.key = successor.key;
                deleteNode.value = successor.value;
                deleteNode.hash = successor.hash;
            }
            //删除节点
            deleteNode = successor;
        }

        int index = index(deleteNode.hash);
        Node<K,V> replaceNode = deleteNode.left != null ? deleteNode.left : deleteNode.right;

        if (replaceNode != null) {
            replaceNode.parent = deleteNode.parent;
            if (deleteNode.parent == null) {
                table[index] = replaceNode;
            } else if (deleteNode.isLeftChild()) {
                deleteNode.parent.left = replaceNode;
            } else {
                deleteNode.parent.right = replaceNode;
            }
            ////删除节点后的操作
            //afterRemove(deleteNode,replaceNode);
            //删除节点后的操作
            afterRemove(replaceNode);
        } else if (deleteNode.parent == null) {
            table[index] = null;
            ////删除节点后的操作
            //afterRemove(deleteNode,null);
            //删除节点后的操作
            afterRemove(deleteNode);
        } else {
            if (deleteNode.isLeftChild()) {
                deleteNode.parent.left = null;
            } else {
                deleteNode.parent.right = null;
            }
            ////删除节点后的操作
            //afterRemove(deleteNode,null);
            //删除节点后的操作
            afterRemove(deleteNode);
        }

        //if (deleteNode.hasTwoChildren()) {
        //    //获取前驱节点、后继节点
        //    Node<K,V> successor = successor(deleteNode);
        //    //替换节点值为后继节点值
        //    deleteNode.key = successor.key;
        //    //替换节点值为后继节点值
        //    deleteNode.key = successor.key;
        //    //替换值
        //    parent = successor.parent;
        //    deleteNode = successor;
        //}
        ////删除结点
        //changeNode(parent,deleteNode);

        //afterRemove(deleteNode);

        return deleteNode.value;
    }

    /**
     * 扩容
     * @author lcy
     * @date 2021/1/21 16:09
     **/
    private void resize(){
        if (Float.intBitsToFloat(size) / Float.intBitsToFloat(table.length) <= DEFAULT_LOAD_FACTORY) {
            return;
        }

        //扩容
        Node<K,V>[] newTable = Arrays.copyOf(table,table.length >>1);


    }

    /**
     * 查找当前节点的后继节点(中序遍历的后一个节点)
     * @param node 传入节点值
     * @return com.lcy.study.algoithm.tree.set.RedBlackNode<K,V>
     * @author lcy
     * @date 2020/10/19 17:43
     **/
    private Node<K,V> successor(Node<K,V> node){
        //当前节点
        Node<K,V> tmpNode = table[index(node.hash)];

        Node<K,V> prev = null;
        Stack<Node<K,V>> stack = new Stack<>();

        //当节点不为空时
        while (tmpNode != null || !stack.isEmpty()) {

            //左子树入栈
            while (tmpNode != null) {
                stack.push(tmpNode);
                tmpNode = tmpNode.left;
            }
            //出栈
            tmpNode = stack.pop();

            if (prev == node) {
                return tmpNode;
            }

            prev = tmpNode;
            if (tmpNode.right != null) {
                tmpNode = tmpNode.right;
            } else {
                tmpNode = null;
            }
        }
        return null;
    }

    /**
     * 根据key生成对应的hash
     * @param key key
     * @return int
     * @author lcy
     * @date 2021/1/12 9:50
     **/
    private int hash(K key){
        if (key == null) {
            return 0;
        } else {
            int hash = key.hashCode();
            //int类型为32位,无符号右移16位异或上原来的值,即高低位都进行计算,保证hash函数的分布均匀
            return hash ^ (hash >>> 16);
        }
    }

    /**
     * 根据key生成对应的hash
     * @param key key
     * @return int
     * @author lcy
     * @date 2021/1/12 9:50
     **/
    private int hashAgain(K key){
        if (key == null) {
            return 0;
        } else {
            int hash = key.hashCode();
            return 5 * hash % 5;
        }
    }

    /**
     * 根据key生成对应的数组下标
     * @param key key
     * @return int
     * @author lcy
     * @date 2021/1/12 9:50
     **/
    private int index(K key){
        return hash(key) & (table.length - 1);
    }

    /**
     * 根据hash值生成对应的数组下标
     * @param hash hash
     * @return int
     * @author lcy
     * @date 2021/1/12 9:50
     **/
    private int index(int hash){
        return hash & (table.length - 1);
    }

    /**
     * 节点染色
     * @param node  传入节点值
     * @param color 颜色
     * @return com.lcy.study.algoithm.tree.set.Node<K,V>
     * @author lcy
     * @date 2020/11/25 9:38
     **/
    private Node<K,V> changeColor(Node<K,V> node,boolean color){
        if (node == null) {
            return null;
        }
        //节点染色
        node.color = color;
        return node;
    }

    /**
     * 节点染色
     * @param node 传入节点值
     * @return com.lcy.study.algoithm.tree.set.Node<K,V>
     * @author lcy
     * @date 2020/11/25 9:38
     **/
    private Node<K,V> changeRed(Node<K,V> node){
        return changeColor(node,RED);
    }

    /**
     * 节点染色
     * @param node 传入节点值
     * @return com.lcy.study.algoithm.tree.set.Node<K,V>
     * @author lcy
     * @date 2020/11/25 9:38
     **/
    private Node<K,V> changeBlack(Node<K,V> node){
        return changeColor(node,BLACK);
    }

    /**
     * 获取当前节点的颜色
     * @param node 节点对象
     * @return boolean
     * @author lcy
     * @date 2020/11/25 14:09
     **/
    private boolean colorOf(Node<K,V> node){
        return node != null ? node.color : BLACK;
    }

    /**
     * 判断节点是否为黑色
     * @param node 节点值
     * @return boolean
     * @author lcy
     * @date 2020/11/25 14:12
     **/
    private boolean isBlack(Node<K,V> node){
        return colorOf(node) == BLACK;
    }

    /**
     * 判断节点是否为黑色
     * @param node 节点值
     * @return boolean
     * @author lcy
     * @date 2020/11/25 14:12
     **/
    private boolean isRed(Node<K,V> node){
        return colorOf(node) == RED;
    }

    /**
     * 比较key
     * @param key1  key1
     * @param key2  key2
     * @param hash1 key1的hash1
     * @param hash2 key2的hash2
     * @return int
     * @author lcy
     * @date 2021/1/12 10:11
     **/
    private int compare(K key1,K key2,int hash1,int hash2){
        int cmp = hash1 - hash2;
        //说明hashcode不相等,返回差值
        if (cmp != 0) {
            return cmp;
        }
        //hashCode相等,值也相等,包含两个值都为null的情况
        if (Tools.equals(key1,key2)) {
            return 0;
        }
        System.out.println(key1 + ":" + key2 + ":" + hash1 + ":" + hash2);
        //值不相等,进一步判断
        if (key1 != null && key2 != null) {
            String key1Class = key1.getClass().getName();
            String key2Class = key2.getClass().getName();
            //通过compareTo方法计算两个类名的差值
            cmp = key1Class.compareTo(key2Class);
            //类名不相等说明不是同一个对象,返回差值
            if (cmp != 0) {
                return cmp;
            }
            //如果类相等,且继承了比较器,使用比较器的比较方法
            if (key1 instanceof Comparable) {
                return ((Comparable)key1).compareTo(key2);
            }
        }
        //key1和key2可能有一个为null。比较内存地址的hash值
        return 0;
    }

    /**
     * 根据对象获取节点值
     * @param key 需要查找的对象
     * @return com.lcy.study.algoithm.tree.set.RedBlackNode<K,V>
     * @author lcy
     * @date 2020/11/12 16:18
     **/
    public Node<K,V> node(K key){
        //获取hash桶里的值
        Node<K,V> node = table[index(key)];
        return node == null ? null : node(node,key);
    }

    /**
     * 根据对象获取节点值
     * @param node 需要查找的节点
     * @param key  需要查找的对象
     * @return com.lcy.study.algoithm.tree.set.RedBlackNode<K,V>
     * @author lcy
     * @date 2020/11/12 16:18
     **/
    public Node<K,V> node(Node<K,V> node,K key){

        int hash = hash(key);

        Stack<Node<K,V>> stack = new Stack<>();
        if (node != null) {
            stack.push(node);
        }
        int cmp;
        while (!stack.isEmpty()) {
            node = stack.pop();
            if (hash > node.hash) {
                stack.push(node.right);
                //node = node.right;
            } else if (hash < node.hash) {
                stack.push(node.left);
                //node = node.left;
                //equals相等
            } else if (Tools.equals(key,node.key)) {
                return node;
                //值不相等,进一步判断
            } else if (key != null && node.key != null &&
                    key.getClass() == node.key.getClass() && key instanceof Comparable
                    && (cmp = ((Comparable)key).compareTo(node.key)) != 0) {
                stack.push(cmp > 0 ? node.right : node.left);
                //hash相等,不具备可比较性
            } else {
                if (node.left != null) {
                    stack.push(node.left);
                }
                if (node.right != null) {
                    stack.push(node.right);
                }
            }
        }
        return null;
    }

    protected void afterAdd(Node<K,V> node){

        Stack<Node<K,V>> stack = new Stack<>();
        stack.push(node);

        while (!stack.isEmpty()) {
            node = stack.pop();
            Node<K,V> parent = node.parent;
            //如果是根节点
            if (parent == null) {
                //变成黑色
                changeBlack(node);
                continue;
            }

            //如果父节点是黑色--维持红黑树平衡,不需要操作
            if (isBlack(parent)) {
                continue;
            }

            //获取uncle节点--叔父节点
            Node<K,V> uncle = parent.sibling();
            //祖父节点--祖父节点一定染成红色
            Node<K,V> grandParent = changeRed(parent.parent);

            //叔父节点是红色
            if (isRed(uncle)) {
                //父节点和叔父节点染成黑色
                changeBlack(parent);
                changeBlack(uncle);
                //将祖父节点当成新添加的节点处理
                stack.push(grandParent);
                continue;
            }

            if (parent.isLeftChild()) {
                if (node.isLeftChild()) {
                    //LL--父节点染成黑色,祖父节点染成红色
                    changeBlack(parent);

                } else {
                    //LR--当前节点和祖父节点染成黑色,父节点染成红色
                    //父节点左旋转,祖父节点右旋转
                    changeBlack(node);
                    rotateLeft(parent);
                }
                rotateRight(grandParent);
            } else {
                if (node.isLeftChild()) {
                    //RL--当前节点和祖父节点染成黑色,父节点染成红色
                    //父节点右旋转,祖父节点左旋转
                    changeBlack(node);
                    rotateRight(parent);
                } else {
                    //RR--父节点染成黑色,祖父节点染成黑色,左旋转
                    changeBlack(parent);
                }
                rotateLeft(grandParent);
            }
        }

    }

    protected void afterRemove(Node<K,V> node){

        Stack<Node<K,V>> stack = new Stack<>();
        stack.push(node);

        while (!stack.isEmpty()) {
            //二叉搜索树删除以后的操作,如果删除的节点是度为2的节点,即有两个子节点,node为该节点的后继节点。
            node = stack.pop();
            //如果替换的节点是红色
            //如果是删除的节点是红色节点,直接删除。如果是用于取代删除节点的子节点是红色,进行染色。然后直接返回。
            if (isRed(node)) {
                //改成黑色,保持4阶B树和红黑树性质,根节点一定要有黑色,因为删除了黑色节点,必须重新生成一个黑色。
                changeBlack(node);
                continue;
            }
            Node<K,V> parent = node.parent;
            //如果黑色节点是根节点--不需要处理
            if (parent == null) {
                continue;
            }

            //兄弟节点--如果是叶子节点,parent已经不指向node了。即原本指向node节点的指针已经为null。
            //但是如果是下溢的情况,parent递归调用,因为parent的父节点还是它,所以要再增加一个不为空的情况判断。
            boolean left = parent.left == null || node.isLeftChild();
            //如果node节点是左子节点,取右子节点
            Node<K,V> siblingNode = left ? parent.right : parent.left;

            //如果被删除的子节点在左边
            if (left) {
                //如果被删除的子节点在左边
                //如果兄弟节点是红色,将父节点旋转,将兄弟节点转成黑色
                if (isRed(siblingNode)) {
                    //染色
                    changeBlack(siblingNode);
                    changeRed(parent);
                    //旋转
                    rotateLeft(parent);
                    //兄弟节点改变
                    siblingNode = parent.right;
                }
            } else {
                //如果被删除的子节点在右边
                //如果兄弟节点是红色,将父节点旋转,将兄弟节点转成黑色
                if (isRed(siblingNode)) {
                    //染色
                    changeBlack(siblingNode);
                    changeRed(parent);
                    //旋转
                    rotateRight(parent);
                    //兄弟节点改变
                    siblingNode = parent.left;
                }
            }
            //兄弟节点是黑色,一定是黑色
            //如果兄弟节点的子节点都是黑色
            if (isBlack(siblingNode.left) && isBlack(siblingNode.right)) {
                //如果都不为黑色,说明没有子节点。因为没有子节点,父节点要向下合并。即染色
                boolean isParentBlack = isBlack(parent);
                changeBlack(parent);
                changeRed(siblingNode);
                //如果父节点是黑色,说明上面的节点还存在下溢
                if (isParentBlack) {
                    //相当于二叉搜索树的叶子节点
                    stack.push(parent);
                }
            } else {
                if (left) {
                    //兄弟节点的子节点不都为黑色
                    //如果兄弟节点的子节点为黑色,即不为红色,对兄弟节点进行左旋转。
                    if (isBlack(siblingNode.right)) {
                        rotateRight(siblingNode);
                        siblingNode = parent.right;
                    }
                    //对父节点进行右旋转
                    rotateLeft(parent);

                } else {
                    //兄弟节点的子节点不都为黑色
                    //如果兄弟节点的子节点为黑色,即不为红色,对兄弟节点进行左旋转。
                    if (isBlack(siblingNode.left)) {
                        rotateLeft(siblingNode);
                        siblingNode = parent.left;
                    }
                    //对父节点进行右旋转
                    rotateRight(parent);
                }

                //旋转以后中心节点的颜色为parent的颜色,新的子节点颜色为黑色
                changeColor(siblingNode,colorOf(parent));
                changeBlack(siblingNode.left);
                changeBlack(siblingNode.right);
            }
        }

    }

    /**
     * 左旋转
     * @param node 需要旋转的节点
     * @author lcy
     * @date 2020/11/18 16:21
     **/
    protected void rotateLeft(Node<K,V> node){
        //左旋转node节点的右节点--parentNode
        Node<K,V> parentNode = node.right;
        //需要node节点的右子树改为当前parentNode的左子树
        node.right = parentNode.left;
        //父节点值替换
        if (node.right != null) {
            node.right.parent = node;
        }
        //parent节点的左节点为node节点
        parentNode.left = node;
        //父节点替换
        parentNode.parent = node.parent;
        //node节点的父节点指向--旋转以后子树根节点变换
        if (node.isLeftChild()) {
            parentNode.parent.left = parentNode;
        } else if (node.isRightChild()) {
            parentNode.parent.right = parentNode;
        } else {
            //如果是根节点,取随便一个节点的hash值然后计算下标。因为红黑树里的key的下标都是一致
            table[index(parentNode.hash)] = parentNode;
        }
        node.parent = parentNode;
    }

    /**
     * 右旋转
     * @param node 需要旋转的节点
     * @author lcy
     * @date 2020/11/18 16:21
     **/
    protected void rotateRight(Node<K,V> node){
        //左旋转node节点的右节点--parentNode
        Node<K,V> parentNode = node.left;
        //需要node节点的右子树改为当前parentNode的左子树
        node.left = parentNode.right;
        //父节点值替换
        if (node.left != null) {
            node.left.parent = node;
        }
        //parent节点的左节点为node节点
        parentNode.right = node;
        //父节点替换
        parentNode.parent = node.parent;
        //node节点的父节点指向--旋转以后子树根节点变换
        if (node.isLeftChild()) {
            parentNode.parent.left = parentNode;
        } else if (node.isRightChild()) {
            parentNode.parent.right = parentNode;
        } else {
            //如果是根节点,取随便一个节点的hash值然后计算下标。因为红黑树里的key的下标都是一致
            table[index(parentNode.hash)] = parentNode;
        }
        node.parent = parentNode;
    }

    /**
     * 树节点内部类
     * @author lcy
     * @date 2020/9/7 10:22
     **/
    protected static class Node<K,V> {

        /**
         * key的hash值
         */
        int hash;

        /**
         * 当前节点key--比较值
         */
        K key;

        /**
         * 当前节点value
         */
        V value;

        /**
         * 左节点值
         */
        Node<K,V> left;

        /**
         * 右节点值
         */
        Node<K,V> right;

        /**
         * 父节点值
         */
        Node<K,V> parent;

        /**
         * 节点颜色,红色为true,黑色为false。新添加的默认为红色节点
         */
        boolean color = RED;

        public Node(K key,V value,Node<K,V> parent){
            this.key = key;
            int hash = key == null ? 0 : key.hashCode();
            this.hash = hash ^ (hash >>> 16);
            this.value = value;
            this.parent = parent;
        }

        /**
         * 判断是否有左右子树
         * @return boolean
         * @author lcy
         * @date 2020/10/16 15:46
         **/
        public boolean hasTwoChildren(){
            return left != null && right != null;
        }

        /**
         * 判断是否左子树
         * @return boolean
         * @author lcy
         * @date 2020/11/18 15:23
         **/
        public boolean isLeftChild(){
            return parent != null && parent.left == this;
        }

        /**
         * 判断是否右子树
         * @return boolean
         * @author lcy
         * @date 2020/11/18 15:23
         **/
        public boolean isRightChild(){
            return parent != null && parent.right == this;
        }

        /**
         * 返回兄弟节点
         * @return Node<K,V>
         * @author lcy
         * @date 2020/11/18 15:23
         **/
        public Node<K,V> sibling(){

            //如果是左子节点,返回父节点的右子节点
            if (isLeftChild()) {
                return parent.right;
            }
            //如果是右子节点,返回父节点的左子节点
            if (isRightChild()) {
                return parent.left;
            }
            //如果是根节点,返回null
            return null;
        }

        @Override public String toString(){
            return "(" + (color ? "red" : "black") + ")" + key
                    //+ ",value={" + value + "}"
                    ;
        }
    }

}

六、总结

哈希散列是一种强大的数据结构和算法,它提供了高效的数据存储和检索机制,并且可以保证数据的完整性和安全性。通过合适的哈希函数和冲突解决方法,我们可以在大规模数据处理中获得出色的性能。然而,设计一个好的哈希函数并不是一件容易的事情,需要考虑到多方面的因素,如输入数据的特点、哈希空间的大小等。因此,在实际应用中,我们需要综合考虑各种因素,选择合适的哈希函数和冲突解决方法,以满足特定场景的需求。