AVL樹中單,雙旋轉的解釋
阿新 • • 發佈:2018-12-27
AVL樹是所謂的帶有平衡條件的二叉查詢樹.解釋一下這裡的兩個條件:1)首先,二叉查詢樹要求一個樹的根節點必然大於(或小於)其左子樹中的所有節點, 同時必然小於(或大於)其右子樹中的所有節點,也就是說,如果按照中序遍歷二叉查詢樹, 它必然是嚴格遞增(或遞減)的.2)AVL樹的平衡條件要求任何一顆子樹,其左右子樹的高度差不超過1.我們要求一顆樹是AVL樹,必須嚴格符合以上的兩個條件.
想象一個插入節點的過程, 由於是二叉查詢樹, 那麼在插入節點之後必然滿足二叉查詢樹的條件, 但是, 卻可能打破了AVL樹本身特有的平衡條件.其中可能有4種情況,但是考慮映象對稱的緣故,本質上只有兩種可能,下面分別進行分析:
1) 插入節點是父節點的左節點,而父節點是祖父節點的左節點,也就是說, 祖父孫三代節點形成的是一個"線型"的關係,比如插入節點3後形成如下的子樹:
7/5/3 可以看出,即使已經破壞了AVL樹的平衡條件,按照中序去遍歷該樹還是得到一個遞增序列:357的, 因此如果要符合AVL樹的平衡條件, 那麼這裡需要做的就是將節點3"往上提", 這樣節點7的左右子樹就不會出現高度差大於1的情況了.同時,將3"往上提"的同時需要保持二叉查詢樹的條件, 那麼就需要將節點3的父節點往上轉,而3的祖父節點成為父節點的右結點:
7 5/==>/ \53 7/3
可以看到,插入節點3後, 通過將3的父節點上提, 3的祖父節點成為父節點的右結點,重新滿足了AVL樹的兩個平衡條件.
這個旋轉過程的程式碼如下:
AVLTree* SingleRotateWithLeft(AVLTree* pNode)
{
AVLTree* pNode1;
pNode1 = pNode->pLeft;
pNode->pLeft = pNode1->pRight;
pNode1->pRight = pNode;
// 結點的位置變了, 要更新結點的高度值 pNode->nHeight = Max(Height(pNode->pLeft), Height(pNode->pRight)) +1;
pNode1->nHeight = Max(Height(pNode1->pLeft), pNode->nHeight) +1;
return pNode1;
}
2)插入節點是父節點的右節點,而父節點是祖父節點的左節點,也就是說, 祖父孫三代形成的是一個"之字型"的關係,比如插入節點3後形成如下的子樹:
4/2
\
3 可以看到,單純的將2上提已經不能解決平衡破壞問題了, 我們需要將節點3往上提兩次,最後3變成了這顆樹的根節點:
443 /// \
2==>3==>24
\ /32 首先, 將3上提一層, 父節點2成為3的左結點;再次3上提一層, 父節點4成為3的右結點.這實際上是由兩次單旋轉過程來組成的,程式碼如下:
AVLTree* DoubleRotateWithLeft(AVLTree* pNode)
{
pNode->pLeft = SingleRotateWithRight(pNode->pLeft);
return SingleRotateWithLeft(pNode);
}
想象一個插入節點的過程, 由於是二叉查詢樹, 那麼在插入節點之後必然滿足二叉查詢樹的條件, 但是, 卻可能打破了AVL樹本身特有的平衡條件.其中可能有4種情況,但是考慮映象對稱的緣故,本質上只有兩種可能,下面分別進行分析:
1) 插入節點是父節點的左節點,而父節點是祖父節點的左節點,也就是說, 祖父孫三代節點形成的是一個"線型"的關係,比如插入節點3後形成如下的子樹:
7/5/3 可以看出,即使已經破壞了AVL樹的平衡條件,按照中序去遍歷該樹還是得到一個遞增序列:357的, 因此如果要符合AVL樹的平衡條件, 那麼這裡需要做的就是將節點3"往上提", 這樣節點7的左右子樹就不會出現高度差大於1的情況了.同時,將3"往上提"的同時需要保持二叉查詢樹的條件, 那麼就需要將節點3的父節點往上轉,而3的祖父節點成為父節點的右結點:
7
這個旋轉過程的程式碼如下:
AVLTree* SingleRotateWithLeft(AVLTree* pNode)
{
AVLTree* pNode1;
pNode1 = pNode->pLeft;
pNode->pLeft = pNode1->pRight;
pNode1->pRight = pNode;
// 結點的位置變了, 要更新結點的高度值 pNode->nHeight
pNode1->nHeight = Max(Height(pNode1->pLeft), pNode->nHeight) +1;
return pNode1;
}
2)插入節點是父節點的右節點,而父節點是祖父節點的左節點,也就是說, 祖父孫三代形成的是一個"之字型"的關係,比如插入節點3後形成如下的子樹:
4/2
\
3 可以看到,單純的將2上提已經不能解決平衡破壞問題了, 我們需要將節點3往上提兩次,最後3變成了這顆樹的根節點:
443
2==>3==>24
\ /32 首先, 將3上提一層, 父節點2成為3的左結點;再次3上提一層, 父節點4成為3的右結點.這實際上是由兩次單旋轉過程來組成的,程式碼如下:
AVLTree* DoubleRotateWithLeft(AVLTree* pNode)
{
pNode->pLeft = SingleRotateWithRight(pNode->pLeft);
return SingleRotateWithLeft(pNode);
}