AVL Tree --平衡二叉树

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
发布了18 篇原创文章 · 获赞 15 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/Juicewyh/article/details/83957445
今日推荐