Hash連結串列轉換為紅黑樹,和樹轉換為連結串列的條件

SpoonBlog發表於2022-03-24

連結串列轉換位紅黑樹

兩個條件,必須同時滿足兩個條件才能進行轉換

  • 條件1:單個連結串列長度大於等於8
  • 條件2:hashMap的總長度大於64個、且樹化的節點位置不能為空
    從原始碼看
    條件一:
    在putVal()方法中,可知當binCount大於7即節點數大於8時進行
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
 // ...省略
  for (int binCount = 0; ; ++binCount) {
    if ((e = p.next) == null) {
      p.next = newNode(hash, key, value, null);
// TREEIFY_THRESHOLD == 8 當binCount大於等於7時 即結點數大於八時進行
      if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
        treeifyBin(tab, hash);
      break;
    }
  }
//...省略
}

條件二:
對於treeifyBin()方法

    final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
// MIN_TREEIFY_CAPACITY= 64 當資料長度小於64是進行擴容 大於64才進行樹化
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
// 且樹化的節點位置不能為空
        else if ((e = tab[index = (n - 1) & hash]) != null) {
//... 省略
  }
}

紅黑樹退化為連結串列

兩種情況

  • 第一 樹內節點數小於等於6
  • 第二:根節點為空,根節點的左右子樹為空,根節點的左子樹的左子樹為空
// 條件一 在樹的空間調整程式碼中
     final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
//...省略
            for (TreeNode<K,V> e = b, next; e != null; e = next) {
                next = (TreeNode<K,V>)e.next;
                e.next = null;
                if ((e.hash & bit) == 0) {
                    if ((e.prev = loTail) == null)
                        loHead = e;
                    else
                        loTail.next = e;
                    loTail = e;
                    ++lc;
                }
                else {
                    if ((e.prev = hiTail) == null)
                        hiHead = e;
                    else
                        hiTail.next = e;
                    hiTail = e;
                    ++hc;
                }
            }

            if (loHead != null) {
  // lc 記錄的是存放在原本位置不變的資料的個數
  //UNTREEIFY_THRESHOLD = 6  untreeify() 樹的退化操作
                if (lc <= UNTREEIFY_THRESHOLD)
                    tab[index] = loHead.untreeify(map);
                else {
                    tab[index] = loHead;
                    if (hiHead != null) // (else is already treeified)
                        loHead.treeify(tab);
                }
            }
//... 省略
}

//條件二 在移除樹節點的方法內 removeTreeNode()
final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
                                  boolean movable) {
// 進行對根節點,左右子樹,左左子樹的判斷然後進行進行退化操作
   if (root == null || root.right == null ||
                  (rl = root.left) == null || rl.left == null) {
                  tab[index] = first.untreeify(map);  // too small
                  return;
              }
}


相關文章