HashMap底层剖析

1、基础知识铺垫

1.1 哈希表

我们知道

  • 数组更利于元素的查找
  • 链表更利于元素的插入和删除
    那么有没有一种数据结构可以同时具有数组和链表的优点呢?即能快速地查找又能高效地插入删除元素?很明显,本文的主角“哈希表”就能很好的满足这个要求。
    那么哈希表是怎么做到两者的优点兼具的呢?这主要归功于它独特的数据结构。哈希表是由一块地址连续的数组空间构成的,其中每个数组都是一个链表,数组的作用在于快速寻址查找,链表的作用在于快速插入和删除元素,因此,哈希表可以被认为就是链表的数组,下图是一个哈希表的简单示意图:
    在这里插入图片描述一般而言,我们在存储元素的时候,会用到“散列方法”,它的作用就是尽量均衡地将元素分配到数组空间中,避免出现某个数组空间中的链表元素大大超过其它数组空间中链表元素个数的情况。
    至于“散列方法”,这里不做进一步讨论。

1.2 红黑树

(1)基本简介

  • 定义
    二叉查找树是一棵空树,或者是具有下列性质的二叉树:
    1、若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
    2、若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
    3、左、右子树也分别为二叉排序树;
    4、没有键值相等的节点。

  • 特征:
    1、节点是红色或黑色。
    2、根是黑色。
    3、所有叶子都是黑色(叶子是NIL节点)。
    4、每个红色节点必须有两个黑色的子节点。(从叶子到根之间不能有两个连续红色节点)
    5、从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
    在这里插入图片描述

(2)变色和旋转

为什么需要变色和旋转?帮助维护红黑树的性质,保持红黑树的平衡。

左旋:

在这里插入图片描述如图以x为中心,其父节点为a,左边兄弟节点为b,左子节点为c,右子节点为d

左旋就是保证x和右子节点d不变,逆时针旋转与x节点的直接相关的左边节点,也就是a,b,c
左旋的过程是将x的父节点a,左边兄弟节点b 逆时针旋转,
原来的x左节点c被x的父节点替代,
原来x的左子节点c逆时针方向平移后变成x的原父节点a的右子节点。

 //这里 p 代表 x
private void rotateLeft(Entry<K,V> p) {
    if (p != null) {
        Entry<K,V> r = p.right; // p 是上图中的 x,r 就是 y
        p.right = r.left;       // 左旋后,x 的右子树变成了 y 的左子树 β 
        if (r.left != null)         
            r.left.parent = p;  //β 确认父亲为 x
        r.parent = p.parent;        //y 取代 x 的第一步:认 x 的父亲为爹
        if (p.parent == null)       //要是 x 没有父亲,那 y 就是最老的根节点
            root = r;
        else if (p.parent.left == p) //如果 x 有父亲并且是它父亲的左孩子,x 的父亲现在认 y 为左孩子,不要 x 了
            p.parent.left = r;
        else                            //如果 x 是父亲的右孩子,父亲就认 y 为右孩子,抛弃 x
            p.parent.right = r;
        r.left = p;     //y 逆袭成功,以前的爸爸 x 现在成了它的左孩子
        p.parent = r;
    }
}

右旋

在这里插入图片描述如图以x为中心,其父节点为a,右边兄弟节点为b,左子节点为d,右子节点为c
右旋就是保证x和左子节点d不变,顺时针旋转与x直接相关的右边节点,也就是a,b,c
右旋的过程是将x的父节点a,右边兄弟节点b,还有右子节点c顺时针旋转。
原来的x右节点c被x的父节点替代,
原来的x的右子节点c顺时针方向平移后变成x的原父节点a的左子节点。

private void rotateRight(Entry<K,V> p) {
    if (p != null) {
        Entry<K,V> l = p.left;
        p.left = l.right;
        if (l.right != null) l.right.parent = p;
        l.parent = p.parent;
        if (p.parent == null)
            root = l;
        else if (p.parent.right == p)
            p.parent.right = l;
        else p.parent.left = l;
        l.right = p;
        p.parent = l;
    }
}

参考博文:
https://blog.csdn.net/u011240877/article/details/53329023
https://blog.csdn.net/tuke_tuke/article/details/51588156
https://www.bilibili.com/video/BV1zU4y1H77f?from=search&seid=9512103280616491587
https://www.cnblogs.com/geektcp/p/11520014.html
https://www.jianshu.com/p/034315b201b6
1、JDK8.0底层【数组+链表+红黑树】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值