【資料結構】AVL樹詳解
阿新 • • 發佈:2019-01-02
1.什麼是AVL樹
AVL樹又稱平衡二叉搜尋樹,它能保證二叉樹高度相對平衡,儘量降低二叉樹的高度,提高搜尋效率。單純的二叉搜尋樹在最壞的情況下插入查詢刪除等操作時間複雜度會是O(N), 例如:所以,AVL樹就能避免這種情況,使得增刪查改的時間複雜度為O(lgN). (ps:這裡的lgN指的是log以2為底的N。)那麼AVL樹是怎麼做到的呢,看看它的特點你就大概知道了: 1> 左子樹和右子樹的高度之差的絕對值不超過1 2.>樹中的每個左子樹和右子樹都是AVL樹 3.>每個節點都有一個平衡因子(balance factor--bf),任一節點的平衡因子是-1,0,1。(每個節點的平衡因子等於右子樹的高度減去左子 樹的高度 ) . 思考這樣一個問題,既然保證了二叉樹的高度之差不超過1就能降低時間複雜度,那直接保證左右子樹高度相同豈不是更好?當然是不行的,假如這棵樹只有兩個節點,那要怎麼辦呢?所以,我們只能保證高度差不能超過1 。
2.如何構建AVL樹
右單旋與左單旋類似,就是節點的名稱我改變了一下,方便大家理解程式碼。 3>需要左右雙旋
可以看到,左右雙旋其實是先以p為軸左旋一次,再以g為軸右旋一次。但實際上如果左右旋只調用兩個單旋是會出現問題的。沒錯,問題就出在平衡因子上。按照上面說單旋時的結點位置變化情況,我們可以畫一張圖來表示右左單旋最終結點的變化情況。
4>需要右左雙旋: 與左右雙旋類似,右左雙旋也是先右旋後左旋,對平衡因子的處理也跟左右雙旋很類似,根據它結點最終的位置確定平衡因子。
3.如何插入
1>如果根節點為空,直接插入賦給根節點 2>通過關鍵碼先找到插入的位置,如果找到了與給定關鍵碼相同的碼,則插入失敗(key結構和key+value結構都不允許樹中出現重複關鍵碼,會導致查找出錯) 3>插入,插到左邊平衡因子減一,插到右邊加一 4>檢查是否平衡,不平衡則調節至平衡(具體程式碼裡有註釋做了相關解釋)4.檢查AVL樹是否平衡
#include<iostream>
using namespace std;
template<class K,class V>
struct AVLtreeNode //結點結構體
{
typedef AVLtreeNode<K, V> Node;
Node* _left;
Node* _right;
Node* _parent;
K _key;
V _value;
int _bf;
AVLtreeNode(const K& key,const V& value)
:_key(key)
, _value(value)
, _left(NULL)
, _right(NULL)
, _parent(NULL)
, _bf(0) //平衡因子
{}
};
template<class K,class V>
class AVLtree
{
typedef AVLtreeNode<K, V> Node;
public:
AVLtree()
:_root(NULL)
{}
bool Insert(const K& key, const V& value)
{
if (NULL == _root)
{
_root = new Node(key, value);
return true;
}
Node* cur = _root;
Node* parent = NULL;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key>key)
{
parent = cur;
cur = cur->_left;
}
else
{
return false;
}
}
if (parent->_key < key)
{
Node* tmp = new Node(key, value);
parent->_right = tmp;
tmp->_parent = parent;
parent->_bf++;
}
if (parent->_key>key)
{
Node* tmp = new Node(key, value);
parent->_left = tmp;
tmp->_parent = parent;
parent->_bf--;
}
while (parent)
{
if (parent->_bf == 0) //原來是1或者-1,那插入以後不會對樹的高度有影響;
{
return true;
}
else if (parent->_bf == 1 || parent->_bf == -1) //原來是0,對樹的高度有影響
{
Node* pparent = parent->_parent;
if (pparent != NULL)
{
if (pparent->_left == parent)// 左樹上高度增加
pparent->_bf--;
else //右樹上高度增加
pparent->_bf++;
}
parent = pparent;
}
else //平衡因子是2/-2,從1或者-1變過來,不滿足平衡樹,需要旋轉
{
if (parent->_bf == 2) //右樹過高
{
if (parent->_right->_bf == 1) //需要左旋結構
{
_RotateL(parent);
return true;
}
else if (parent->_right->_bf = -1) //需要右左旋結構
{
_RotateRL(parent);
return true;
}
}
else //平衡因子為-2
{
if (parent->_left->_bf == -1) //需要右單旋的結構
{
_RotateR(parent);
return true;
}
else if (parent->_left->_bf == 1) //需要左右旋的結構
{
_RotateLR(parent);
return true;
}
}
}
}
}
bool IsBalance()
{
return _IsBalance(_root);
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
protected:
bool _IsBalance(Node* root)
{
if (NULL == root)
return true;
int bf = _Depth(root->_right) - _Depth(root->_left);
if (bf == root->_bf)
return true;
else
{
cout << root->_key << "平衡因子異常" << endl;
return false;
}
return _IsBalance(root->_left);
return _IsBalance(root->_right);
}
int _Depth(Node* root)
{
if (NULL == root)
return 0;
int left = _Depth(root->_left)+1;
int right = _Depth(root->_right) + 1;
return left > right ? left : right;
}
void _InOrder(Node* root)
{
if (NULL == root)
return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
void _RotateL(Node* parent) //左單旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
subRL->_parent = parent;
Node* pparent = parent->_parent;
subR->_left = parent;
parent->_parent = subR;
if (NULL == pparent)
{
_root = subR;
subR->_parent = NULL;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subR;
subR->_parent = pparent;
}
else
{
pparent->_right = subR;
subR->_parent = pparent;
}
}
parent->_bf = subR->_bf = 0;
}
void _RotateR(Node* parent) //右單旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
if (subLR)
subLR->_parent = parent;
Node* pparent = parent->_parent;
subL->_right = parent;
parent->_parent = subL;
if (pparent == NULL)
{
_root = subL;
subL->_parent = NULL;
}
else
{
if (pparent->_left == parent)
{
pparent->_left = subL;
subL->_parent = pparent;
}
else
{
pparent->_right = subL;
subL->_parent = pparent;
}
}
parent->_bf = subL->_bf = 0;
}
void _RotateRL(Node* parent) //右左雙旋
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf; //必須記錄下來,旋轉後發生改變
_RotateR(subR);
_RotateL(parent);
if (bf == 0) //插入後子樹根節點為0,高度沒有受到影響,則調整後父節點和祖父結點的平衡因子為0
{
parent->_bf = subRL->_bf=subR->_bf = 0;
}
else if (bf == 1) //插入後右樹高,右樹給了subR的左邊,所以subR的平衡因子為0,左樹高度低於右樹,給了parent的右樹所以parent的平衡因子為1
{
parent->_bf = -1;
subR->_bf = subRL->_bf = 0;
}
else if (bf == -1)//插入後左樹高,右樹給了subR的左邊,所以subR的平衡因子為1,左樹高度低於右樹,給了parent的右樹所以parent的平衡因子為0
{
parent->_bf = subRL->_bf = 0;
subR->_bf = 1;
}
}
void _RotateLR(Node* parent) //左右雙旋
{
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
_RotateL(subL);
_RotateR(parent);
if (bf == 0)
parent->_bf =subLR->_bf= subL->_bf = 0;
else if (bf == 1)
{
parent->_bf = subLR->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1)
{
parent->_bf = 1;
subL->_bf = subLR->_bf = 0;
}
}
private:
Node* _root;
};
void TestAVLtree()
{
AVLtree<int, int> tree;
int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
tree.Insert(a[i], i);
cout << "isbalance?"<<tree.IsBalance() <<"插入"<< a[i] << endl;
}
tree.InOrder();
tree.IsBalance();
AVLtree<int, int> tree1;
int a1[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
for (size_t i = 0; i < sizeof(a1) / sizeof(a1[0]); i++)
{
tree1.Insert(a1[i], i);
cout << "isbalance?" << tree1.IsBalance() << "插入" << a1[i] << endl;
}
tree1.InOrder();
}
如果有沒寫清楚或者寫錯了的地方請多指教