據結構與算法(十) AVL樹

平衡二叉樹來源

二叉搜索樹的複雜度分析java

和高度有關node

O(h) = O(logn)spa

最壞複雜度是從小到大添加節點 (和鏈表差很少)code

O(h) = O(n)cdn

如何二叉搜索樹退化成鏈表??blog

讓添加刪除搜索的複雜度維持在logn進程

平衡(Balance)

當節點固定時,左右字數高度就越接近,這可二叉樹就越平衡it

理想平衡

最理想的平衡,例如 徹底二叉樹,滿二叉樹io

如何改進二叉搜索樹

由於沒法改變添加刪除順序(用戶操做決定),因此在每次操做以後,讓二叉樹達到平衡狀態。function

  • 用最少的調整次數達到適度的平衡既可。

平衡二叉搜索樹(Balanced Binary Search Tree)

簡稱BBST

常見的平衡二叉搜索樹有

  • AVL樹
    • Windows NT內核中管飯使用
  • 紅黑樹
    • C++ STL(map set)
    • Java中的TreeMap、TreeSet、HashMap、HashSet
    • Linux 的進程調度
    • Ngix的timer

通常稱他們爲:自平衡的二叉搜索樹(Self-Balance Binary Search Tree)

AVL樹

介紹:

最先發明的自平衡二叉樹之一

取名爲G.M.Adelson-Velsky和E.M.Landis(來自蘇聯的科學家) 兩我的的名字稱呼

平衡因子:某節點的左右子樹高度差

特色:

  • 每一個節點的左右高度差不超過1
  • 搜索、添加、刪除的時間複雜度爲O(logn)

LL- 右旋轉(單旋)

  • 注意維護T三、二、3的 parent的屬性

  • 以及更新二、3的高度

LL右旋轉.gif

RR-左旋轉

  • 注意維護T三、三、4的 parent的屬性

  • 以及更新三、4的高度

RR左旋轉

LR-RR左旋轉,LL右旋轉(雙旋)

  • 首先對 LR的進行中的2 進行 RR左旋轉

  • 對旋轉後對3進行LL右旋轉

    參考上方LL右旋轉

RL-LL右旋轉,RR左旋轉(雙旋)

  • 參考上方LR-RR左旋轉,LL右旋轉(雙旋)。方法便是LR的對稱
刪除致使失衡
  • 只可能致使父節點或者祖先節點(只有一個)失衡(緣由是由於 失衡因子= 子節點相減)
LL\RR\LR\RL狀況:
  • 極端狀況 全部的祖先節點都會失衡 共(logn)次調整
解決方式:

在刪除後進行平衡操做

刪除

讓父節點恢復失衡後,可能致使更高節點的祖先接點失衡(最多須要log(n)次調整)

添加:

添加會致使全部祖先節點都失衡

處理:只要讓最低失衡節點回復平衡,整棵樹就回復平衡(O(n))

解決方式:

添加後進行平衡操做

時間複雜度

搜索:平均時間複雜度O(logn)

添加:平均時間複雜度O(logn) O(1)次旋轉

刪除:平均時間複雜度O(logn) O(logn)次旋轉

平衡代碼:

private void rebalance(Node<E> grand) {
  // 獲取子節點最高的節點
  Node<E> parent = ((AVLNode<E>)grand).tallChild();
  // 獲取子節點的子節點中最高的節點
  Node<E> node = ((AVLNode<E>)parent).tallChild();
  // 判斷旋轉狀況
  if (parent.isLeftChild() ) { //L
    if (node.isLeftChild()) { //LL
      rotateRight(grand);
    }else { //LR
      rotateLeft(parent);
      rotateRight(grand);
    }
  }else { //R
    if (node.isLeftChild()) { //RL
      rotateRight(parent);
      rotateLeft(grand);
    }else { //RR
      rotateLeft(grand);
    }
  }
}

// RR 右旋轉
private void rotateLeft(Node<E> grand) {
  Node<E> parent = grand.right;
  Node<E> child = parent.left;
  grand.right = child;
  parent.left = grand;

  afterRotate(grand, parent, child);
}
// LL 左旋轉
private void rotateRight(Node<E> grand) {

  Node<E> parent = grand.left;
  Node<E> child = parent.right;

  grand.left = child;
  parent.right = grand;
  afterRotate(grand, parent, child);

}
// 旋轉後更新操做(更新parent節點),更新高度等;
private void afterRotate(Node<E> grand,Node<E> parent, Node<E> child) {
  parent.parent = grand.parent;

  if (grand.isLeftChild()) {
    grand.parent.left = parent;	
  }else if (grand.isRightChild()){
    grand.parent.right = parent;
  }else {
    root = parent;
  }
  if (child != null) {
    child.parent = grand;
  }
  grand.parent = parent;

  updateHeight(grand);
  updateHeight(parent);
}
複製代碼

喜歡的能夠關注下個人公衆號,會在第一時間更新

相關文章
相關標籤/搜索