hashMap 将链表转换为红黑树 treeifyBin()详解

结点添加完成之后判断此时结点个数是否大于 TREEIFY_THRESHOLD 临界值 8,如果大于则将链表转换为红黑树,转换红黑树的方法 treeifyBin,整体代码如下: ```java if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st //转换为红黑树 tab表示数组名 hash表示哈希值 treeifyBin(tab, hash); ``` treeifyBin 方法如下所示: ```java /* 替换指定哈希表的索引处桶中的所有链接结点,除非表太小,否则将修改大小。 Node<K,V>[] tab = tab 数组名 int hash = hash表示哈希值 */ final void treeifyBin(Node<K,V>[] tab, int hash) { int n, index; Node<K,V> e; /* 如果当前数组为空或者数组的长度小于进行树形化的阈值(MIN_TREEIFY_CAPACITY = 64),就去扩容。而不是将结点变为红黑树。 目的:如果数组很小,那么转换红黑树,然后遍历效率要低一些。这时进行扩容,那么重新计算哈希值,链表长度有可能就变短了,数据会放到数组中,这样相对来说效率高一些。 */ if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) //扩容方法 resize(); else if ((e = tab[index = (n - 1) & hash]) != null) { /* 1)执行到这里说明哈希表中的数组长度大于阈值64,开始进行树形化 2)e = tab[index = (n - 1) & hash]表示将数组中的元素取出赋值给e,e是哈希表中指定位置桶里的链表结点,从第一个开始 */ // hd:红黑树的头结点 tl:红黑树的尾结点 TreeNode<K,V> hd = null, tl = null; do { // 新创建一个树的结点,内容和当前链表结点e一致 TreeNode<K,V> p = replacementTreeNode(e, null); if (tl == null) hd = p; // 将新创键的p结点赋值给红黑树的头结点 else { p.prev = tl; // 将上一个结点p赋值给现在的p的前一个结点 tl.next = p; // 将现在结点p作为树的尾结点的下一个结点 } tl = p; /* e = e.next 将当前结点的下一个结点赋值给e,如果下一个结点不等于null 则回到上面继续取出链表中结点转换为红黑树 */ } while ((e = e.next) != null); /* 让桶中的第一个元素即数组中的元素指向新建的红黑树的结点,以后这个桶里的元素就是红黑树 而不是链表数据结构了 */ if ((tab[index] = hd) != null) hd.treeify(tab); } } ``` 小结:上述操作一共做了如下几件事: 1. 根据哈希表中元素个数确定是扩容还是树形化。 2. 如果是树形化遍历桶中的元素,创建相同个数的树形结点,复制内容,建立起联系。 3. 然后让桶中的第一个元素指向新创建的树根结点,替换桶的链表内容为树形化内容。