HashMap源码浅读二

今天分享一下对HashMap中treeify方法的简单理解:
该方法实现了TreeNode类对象,将该对象的打头链表转换为树结构,小伙伴们都知道,HashMap的底层是由数组+链表+红黑树,而1.8的HashMap的一大特点便是新增了红黑树。基础参考**—>**浅读一

老规矩,怎么理解知识点,当然是直接上代码跟着我的注释理思路:

final void treeify(Node<K,V>[] tab) {//Node<K,V>[] 定义了参数数组
            TreeNode<K,V> root = null;//这里小伙伴应该可以理解吧-->创建了树的根节点root
            for (TreeNode<K,V> x = this, next; x != null; x = next) {//这里的话可能会有模糊,不着急一点一点的看,这里的for是不是将链表遍历了呢,而x则是指向当前节点,next则是指向下一节点
                next = (TreeNode<K,V>)x.next;//指向下一个节点
                x.left = x.right = null;//这里就比较简单了,就是将当前节点的左右节点都定义为null
                if (root == null) {//这里就用到了第二行根节点root,如果根节点为null
                    x.parent = null;//那就设定当前节点的父节点为空
                    x.red = false;//red 红色   false 否定   这里是将当前节点的红色属性定义为false  也就是说当前节点为黑色节点
                    root = x;//并将当前节点赋给根节点  
                }//上述做个总结:当前节点的父节点为null,那么当前节点便是父节点,同时将其定义为黑节点
                else {//else  那就是说  接下来的操作是基于 root父节点不为空,也就是说当前节点x不是父节点而是子节点的情况
                    K k = x.key;//key是什么  hashmap是不是<K,V>键值对格式?答案是肯定的  这里是拿到当前链表节点的Key值
                    int h = x.hash;//那这里就是拿到当前链表节点的Hash值了
                    Class<?> kc = null;//这里是先定义一个key所属的Class
                    for (TreeNode<K,V> p = root;;) {//for  又开始遍历了  ***注意***:这里没有定义上限边界,也就是说只能在内部跳出,下面我们会看到   **注意:** p 是树节点
                        int dir, ph;//单看这里只是定义了两个int对象   遗留:ph ,dir 接着往下看
                        K pk = p.key;//p.key  当前树节点的key被拿到
                        if ((ph = p.hash) > h)//当前节点的hash付给了ph 那也就是说ph是当前树节点的hash值 而h是链节点的hash值  整合: 如果当前树节点hash值大于当前链节点的hash值
                            dir = -1;// ph已经知道  dir是什么  不慌  接着往下看
                        else if (ph < h)//如果当前树节点hash小于当前链节点的hash
                            dir = 1;//不慌  再看
                        else if ((kc == null &&//如果两个节点的key的hash值相等
                                  (kc = comparableClassFor(k)) == null) //如果当前链表节点的key实现了comparable接口,并且当前树节点和链表节点是相同Class的实例
                                  || (dir = compareComparables(kc, k, pk)) == 0)//通过comparable的方式再比较两者
                            dir = tieBreakOrder(k, pk);//最后再通过tieBreakOrder比较一次
							//到这里应该明白了  dir表示的是方向左右 不清楚的 可以代入再走一遍思维
                        TreeNode<K,V> xp = p;//这里是保存了当前的树节点

						//如果dir小于等于0   那么表示当前链表节点是在树节点的左侧,但不一定是该树节点的左子节点,也可能是左子节点的右子节点,或者循环往下更深层次  到这里迷糊不清楚的  可以学习一下树结构
                        //如果dir大于零  那么当前链节点在当前树节点的右侧,但不一定是当前树节点的右子节点,同上
                        //如果当前树节点不是叶子节点,那么最终会以当前树节点的左子节点或者右子节点 为起始节点  再从GOTO1 处开始 重新寻找自己(当前链表节点)的位置
         				//如果当前树节点就是叶子节点,那么根据dir的值,就可以把当前链表节点放置到当前树节点的左或者右侧了。
         				//放置之后,还需要重新把树进行平衡,平衡之后,就可以针对下一个链表节点进行处理
                        if ((p = (dir <= 0) ? p.left : p.right) == null) {  
                            x.parent = xp;//当前链表节点 作为 当前树节点的子节点
                            if (dir <= 0)
                                xp.left = x;//  作为左子节点
                            else
                                xp.right = x;// 作为右子节点
                            root = balanceInsertion(root, x);// 用balanceInsertion方法重新进行平衡
                            break;//跳出循环
                        }
                    }
                }
            }
            moveRootToFront(tab, root);
        }

到此为止,便是将打头链表转为红黑树的方法整理了一遍,如果记不住treeify方法的话,就记住树化方法,名如其意。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值