AVL Tree
1.AVL树本质上是一棵二叉搜索树
2.AVL树带有平衡条件:每个节点左右子树的高度之差(平衡因子)的绝对值最多为1。如果在任何时候他们相差多余1,则重新平衡以恢复此属性。查找,插入,删除,在平均和最差情况下都需要O(log n)的时间。
为什么有了二叉搜索树,还需要AVL树?
对于二叉搜索树,他的插入,查找,删除的平均时间都是O(log n),而最糟糕的情况则为O(n)。
我们来看下最糟糕的情况,如果插入的数依次是10,8,7,6,5,会形成左侧图所示的这样一棵树。这样一棵树可以说与链表无异,此时插入,查找,删除的时间都为O(log n),并不能体现出二叉搜索树的优势。
而如果是平衡二叉树,当平衡被打破时,则会自己修复平衡,形成右图所示的树。
如何恢复平衡?
当树的平衡被打破时,我们通过一个或多个树的旋转来重新平衡树。
旋转有四个情况:左旋,右旋,左右(先左旋后右旋),右左(先右旋后左旋)。
左旋(LeftRotation)
如下图所示,左侧图是旋转之前的树,右侧图是旋转后的重新形成的一棵AVL树。我们可以发现,左图在k2结点处平衡被打破,原因是k2结点与其兄弟结点的高度差为2,大于了1。当然,如果树中有某一个结点的平衡被打破,他的父辈结点的平衡肯定会被打破。
我们可以理解为旋转是围绕“失去平衡的根结点”进行的。对于左旋,可以这样理解:当插入或删除一个结点,右子树(需要调整的根结点,此时的k2)的右边引起了树的不平衡(即右边的右边)。则这个时候应该左旋。
在该情况下,右子树的高度与左子树高度的差大于了1,要想保持平衡,则需要将右边的结点“移”到左边去,以达到左右子树高度差不大于1的平衡状态。同时,在旋转的过程中还要保持其二叉搜索树的性质:父亲结点的键值大于左孩子而小于右孩子。
这时候,我们使k2成为根结点,再使k1成为k2的左结点,使k2的左结点成为k1的右节点。这样既调整了树的高度,又没有打破二叉搜索树的性质(可以自行分析一下)。
代码
template <typename Object>
TreeNode<Object>*AVLTree<Object>::leftLeftRotation(TreeNode<Object> *t) {
//t为此时需要调整的节点
TreeNode<Object>* tmp=t->right;
t->right=tmp->left;
tmp->left=t;
t->height=max(getHeight(t->left),getHeight(t->right))+1;
tmp->height=max(getHeight(t->left),getHeight(t->right))+1;
return tmp;
}
右旋(RightRotation)
右旋与左旋操作大同小异。可记为不平衡树由左子树(需要调节的结点,此时为k2)的左边引起时(即左边的左边),通过右旋来恢复平衡。
代码
template <typename Object>
TreeNode<Object>* AVLTree<Object>::rightRightRotation(TreeNode<Object> *t) {
TreeNode<Object>*tmp=t->left;
t->left=tmp->right;
tmp->right=t;
t->height=max(getHeight(t->left),getHeight(t->right))+1;
tmp->height=max(getHeight(tmp->left),getHeight(t->right))+1;
return tmp;
}
左右(LeftRightRotation)
在这种情况下,需要经过两次旋转才能恢复平衡。可记为左子树(需要被修正的跟结点,此处为k2)的右边引起了不平衡时,(即左边的右边),先左旋,再右旋。
代码
template <typename Object>
TreeNode<Object>* AVLTree<Object>::leftRightRotation(TreeNode<Object> *t) {
t->left=leftLeftRotation(t->left);
return rightRightRotation(t);
}
右左(RightLeftRotation)
右左与左右对称,也需要两次旋转才能恢复平衡。可记为,当右子树(需要被调整的根节点,此处为k2)的左边引起不平衡时(即右边的左边左),先右旋,再左旋。
代码
template <typename Object>TreeNode<Object>* AVLTree<Object>::rightLeftRotation(TreeNode<Object> *t) {
t->right=rightRightRotation(t->right);
return leftLeftRotation(t);
}
基本操作
AVL Tree的基本操作分别时插入,删除,查找,打印,销毁树。其中查找,打印,销毁与普通的二叉搜索树并没有区别,因为这前两个操作并不影响树的平衡,销毁操作则不需要考虑树的平衡,直接删除所有结点即可。而插入和删除则不同,每当插入或者删除一个元素时,树的平衡都可能会被破坏,如果被破坏,此时就要采取相应的旋转操作来恢复树的平衡。
我们判断树的平衡是通过每个结点的高度,因此,结点中需要新增一个height属性。其中,我们定义叶子结点高度为0。
结点的定义
template <typename Object>struct TreeNode{
TreeNode<Object> *left;
TreeNode<Object> *right;
Object element;
int height;
TreeNode(const Object& theElement,TreeNode<Object>*Left,TreeNode<Object>*Right):
element(theElement),left(Left),right(Right){}
};
树的定义
template <typename Object>class AVLTree{
TreeNode<Object>*root;
public:
AVLTree();
~AVLTree();
AVLTree(const AVLTree<Object>&);
const AVLTree<Object>&operator=(const AVLTree<Object>&);
bool contain(const Object&);
void insert(const Object&);
void remove(const Object&);
const Object& findMin();
const Object& findMax();
bool empty()const;
void clear();
void printTree();
private:
TreeNode<Object>* contain(const Object&,TreeNode<Object>*);
TreeNode<Object>* insert(const Object&,TreeNode<Object>*&);
void remove(const Object&,TreeNode<Object>*&);
TreeNode<Object>* findMin(TreeNode<Object>*);
TreeNode<Object>* findMax(TreeNode<Object>*);
void clear(TreeNode<Object>*&);
TreeNode<Object>* clone(TreeNode<Object>*);
void printTree(TreeNode<Object>*);
TreeNode<Object>*leftLeftRotation(TreeNode<Object>*);
TreeNode<Object>*rightRightRotation(TreeNode<Object>*);
TreeNode<Object>*leftRightRotation(TreeNode<Object>*);
TreeNode<Object>*rightLeftRotation(TreeNode<Object>*);
int getHeight(TreeNode<Object>*);
};
插入
AVL Tree的插入比二叉搜索树多了一个地方:如果插入以后影响了树的平衡,则通过旋转来恢复平衡。
template <typename Object>
TreeNode<Object>* AVLTree<Object>::insert(const Object &obj,TreeNode<Object>*&t) {
if(t==NULL)t=new TreeNode<Object>(obj,NULL,NULL);
else if(obj<t->element){
t->left=insert(obj,t->left);
if(getHeight(t->left)-getHeight(t->right)==2){
if(obj<t->left->element)
t=rightRightRotation(t);//左边长则右旋
else
t=leftRightRotation(t);//左边的右边长则先左旋再右旋
}
}
else{
t->right=insert(obj,t->right);
if(getHeight(t->right)-getHeight(t->left)==2)
if(obj>t->right->element)
t=leftLeftRotation(t);//右边长则左旋
else
t=rightLeftRotation(t);//右边的左边长则先右旋在左旋
}
t->height=max(getHeight(t->left),getHeight(t->right))+1;//获得新的高度
return t;
}
删除
在删除时,我们采用与BST中删除同样的策略,懒惰删除。
为了有利于保持树的平衡性,如果被删结点的左子树高度大于右子树,则用被删除结点的左子树上的键值最大的结点来代替当前结点,然后删除;反之,则用被删除结点的右子树上的键值最小的结点来代替当前结点,然后删除。同时,删除的时候我们也需要判断树的平衡是否被破坏,若被破坏,通过相应的旋转来恢复平衡。
template <typename Object>
void AVLTree<Object>::remove(const Object &obj, TreeNode<Object> *&t) {
if(t==NULL)return;
if(obj<t->element){
remove(obj,t->left);
if(getHeight(t->right)-getHeight(t->left)==2){
TreeNode<Object>*r=t->right;
if(getHeight(r->left)>getHeight(r->right))
t=rightLeftRotation(t);
else
t=leftLeftRotation(t);
}
}
else if(obj>t->element){
remove(obj,t->right);
if(getHeight(t->left)-getHeight(t->right)==2){
TreeNode<Object>*l=t->left;
if(getHeight(l->right)>getHeight(l->left))
t=leftRightRotation(t);
else
t=rightRightRotation(t);
}
}
else{
if(t->left!=NULL&&t->right!=NULL){
if(getHeight(t->left)>getHeight(t->right)){
TreeNode<Object>*max=findMax(t->left);
t->element=max->element;
remove(max->element,t->left);
}
else{
TreeNode<Object>*min=findMin(t->right);
t->element=min->element;
remove(min->element,t->right);
}
}
else{
TreeNode<Object>*tmp=t;
t=(t->left==NULL)?t->right:t->left;
delete tmp;
}
}
}
完整代码
#ifndef AVLTREE_H
#define AVLTREE_H
#include <iostream>
#include <algorithm>
using namespace std;
template <typename Object>struct TreeNode{
TreeNode<Object> *left;
TreeNode<Object> *right;
Object element;
int height;
TreeNode(const Object& theElement,TreeNode<Object>*Left,TreeNode<Object>*Right):
element(theElement),left(Left),right(Right){}
};
template <typename Object>class AVLTree{
TreeNode<Object>*root;
public:
AVLTree();
~AVLTree();
AVLTree(const AVLTree<Object>&);
bool contain(const Object&);
void insert(const Object&);
void remove(const Object&);
const Object& findMin();
const Object& findMax();
bool empty()const;
void clear();
const AVLTree<Object>&operator=(const AVLTree<Object>&);
void printTree();
int getHeight();
private:
TreeNode<Object>* contain(const Object&,TreeNode<Object>*);
TreeNode<Object>* insert(const Object&,TreeNode<Object>*&);
void remove(const Object&,TreeNode<Object>*&);
TreeNode<Object>* findMin(TreeNode<Object>*);
TreeNode<Object>* findMax(TreeNode<Object>*);
void clear(TreeNode<Object>*&);
TreeNode<Object>* clone(TreeNode<Object>*);
void printTree(TreeNode<Object>*);
TreeNode<Object>*leftLeftRotation(TreeNode<Object>*);
TreeNode<Object>*rightRightRotation(TreeNode<Object>*);
TreeNode<Object>*leftRightRotation(TreeNode<Object>*);
TreeNode<Object>*rightLeftRotation(TreeNode<Object>*);
int getHeight(TreeNode<Object>*);
};
template <typename Object>AVLTree<Object>::AVLTree():root(NULL) {}
template <typename Object>AVLTree<Object>::AVLTree(const AVLTree<Object> &rhs):root(NULL) {
root=clone(rhs.root);
}
template <typename Object>AVLTree<Object>::~AVLTree() {
clear();
}
template <typename Object>int AVLTree<Object>::getHeight() { return getHeight(root);}
template <typename Object>int AVLTree<Object>::getHeight(TreeNode<Object> *t) {
if(t) return t->height;
return 0;
}
template <typename Object>void AVLTree<Object>::remove(const Object &obj) {
remove(obj,root);
}
template <typename Object>void AVLTree<Object>::remove(const Object &obj, TreeNode<Object> *&t) {
if(t==NULL)return;
if(obj<t->element){
remove(obj,t->left);
if(getHeight(t->right)-getHeight(t->left)==2){
TreeNode<Object>*r=t->right;
if(getHeight(r->left)>getHeight(r->right))
t=rightLeftRotation(t);
else
t=leftLeftRotation(t);
}
}
else if(obj>t->element){
remove(obj,t->right);
if(getHeight(t->left)-getHeight(t->right)==2){
TreeNode<Object>*l=t->left;
if(getHeight(l->right)>getHeight(l->left))
t=leftRightRotation(t);
else
t=rightRightRotation(t);
}
}
else{
if(t->left!=NULL&&t->right!=NULL){
if(getHeight(t->left)>getHeight(t->right)){
TreeNode<Object>*max=findMax(t->left);
t->element=max->element;
remove(max->element,t->left);
}
else{
TreeNode<Object>*min=findMin(t->right);
t->element=min->element;
remove(min->element,t->right);
}
}
else{
TreeNode<Object>*tmp=t;
t=(t->left==NULL)?t->right:t->left;
delete tmp;
}
}
}
template <typename Object>const Object& AVLTree<Object>::findMin() {
return findMin(root)->element;
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::findMin(TreeNode<Object> *t) {
if(t==NULL)return NULL;
while (t->left)
t=t->left;
return t;
}
template <typename Object>const Object& AVLTree<Object>::findMax() {
return findMax(root)->element;
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::findMax(TreeNode<Object> *t) {
if(t==NULL) return NULL;
while(t->right)
t=t->right;
return t;
}
template <typename Object>bool AVLTree<Object>::contain(const Object &obj) {
return contain(obj,root)==NULL? false:true;
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::contain(const Object &obj, TreeNode<Object> *t) {
if(t==NULL||t->element==obj)return t;
if(obj<t->element) return contain(obj,t->left);
else return contain(obj,t->right);
}
template <typename Object>void AVLTree<Object>::insert(const Object &obj) {
insert(obj,root);
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::insert(const Object &obj,TreeNode<Object>*&t) {
if(t==NULL)t=new TreeNode<Object>(obj,NULL,NULL);
else if(obj<t->element){
t->left=insert(obj,t->left);
if(getHeight(t->left)-getHeight(t->right)==2){
if(obj<t->left->element)
t=rightRightRotation(t);//左边长则右旋
else
t=leftRightRotation(t);//左边的右边长则先左旋再右旋
}
}
else{
t->right=insert(obj,t->right);
if(getHeight(t->right)-getHeight(t->left)==2)
if(obj>t->right->element)
t=leftLeftRotation(t);//右边长则左旋
else
t=rightLeftRotation(t);//右边的左边长则先右旋在左旋
}
t->height=max(getHeight(t->left),getHeight(t->right))+1;
return t;
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::leftLeftRotation(TreeNode<Object> *t) {
TreeNode<Object>* tmp=t->right;
t->right=tmp->left;
tmp->left=t;
t->height=max(getHeight(t->left),getHeight(t->right))+1;
tmp->height=max(getHeight(t->left),getHeight(t->right))+1;
return tmp;
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::rightRightRotation(TreeNode<Object> *t) {
TreeNode<Object>*tmp=t->left;
t->left=tmp->right;
tmp->right=t;
t->height=max(getHeight(t->left),getHeight(t->right))+1;
tmp->height=max(getHeight(tmp->left),getHeight(t->right))+1;
return tmp;
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::leftRightRotation(TreeNode<Object> *t) {
t->left=leftLeftRotation(t->left);
return rightRightRotation(t);
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::rightLeftRotation(TreeNode<Object> *t) {
t->right=rightRightRotation(t->right);
return leftLeftRotation(t);
}
template <typename Object>void AVLTree<Object>::clear() {
clear(root);
}
template <typename Object>void AVLTree<Object>::clear(TreeNode<Object> *&t) {
if(t==NULL) return;
if(t->left) clear(t->left);
if(t->right) clear(t->right);
delete t;
}
template <typename Object>void AVLTree<Object>::printTree() {
printTree(root);
}
template <typename Object>void AVLTree<Object>::printTree(TreeNode<Object> *t) {
if(t){
std::cout<<t->element<<" ";
printTree(t->left);
printTree(t->right);
}
}
template <typename Object>TreeNode<Object>* AVLTree<Object>::clone(TreeNode<Object> *t) {
if(t==NULL) return NULL;
return new TreeNode<Object>(t->element,clone(t->left),clone(t->right));
}
template <typename Object>const AVLTree<Object>& AVLTree<Object>::operator=(const AVLTree<Object> &t) {
if(this!=&t) {
clear();
root = clone(t.root);
}
return *this;
}
template <typename Object>bool AVLTree<Object>::empty() const {
return root==NULL;
}
#endif //AVLTREE_H