AVL树及其C++实现

来源:互联网 发布:达内java五虎将 编辑:程序博客网 时间:2024/06/06 07:11

介绍

AVL树是根据它的发明者G.M. Adelson-Velsky 和 E.M. Landis命名的。

AVL树是高度平衡的二叉树,它的特点是:AVL树中任何结点的两个子树的高度最大差别为1。


AVL树的查找、插入和删除操作在平均和最坏情况下都是O(logn)。

如果在AVL树中插入或删除结点后,使得高度之差大于1,此时,AVL树的平衡状态就被破坏,它就不是一颗平衡二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。学AVL树,重点的地方也就是它的旋转算法。



————————————————————————————————————————————————————————————————————————————

算法实现

树的定义

树的结点

template<class T>class AVLTreeNode{    public:        T key;    // 关键字(键值)        int height;    // 高度        AVLTreeNode *left;    // 左孩子        AVLTreeNode *right;    // 右孩子            AVLTreeNode(T value, AVLTreeNode *l, AVLTreeNode *r) :            key(value) ,left(l),right(r) {}};
树的类
template<class T>class AVLTree{    private:        AVLTreeNode<T> *root;    // 根结点        public:        // 外部接口          AVLTree();         ~AVLTree();                 // 获取树的高度        int height();        // 比较两个值的大小         int max(int a, int b);                // 前序遍历        void preOrder();        // 中序遍历        void inOrder();        // 后序遍历        void postOrder();                // (递归实现)查找AVL树中键值为key的结点        AVLTreeNode<T>* search(T key);        // (非递归实现)查找AVL树中键值为key的结点        AVLTreeNode<T>* iterativeSearch(T key);                // 查找最小结点:返回最小结点的键值        T minimum();        // 查找最大结点:返回最大结点的键值        T maximum();                // 将结点插入到AVL树中        void insert(T key);        // 删除结点        void remove(T key);                // 销毁AVL树        void destroy();                // 打印AVL树        void print();        private:        // 内部接口         // 获取树的高度        int height(AVLTreeNode<T> *tree);                // 前序遍历        void preOrder(AVLTreeNode<T> *tree) const;        // 中序遍历        void inOrder(AVLTreeNode<T> *tree) const;        // 后序遍历        void postOrder(AVLTreeNode<T> *tree) const;                // (递归实现)查找AVL树中键值为key的结点        AVLTreeNode<T>* search(AVLTreeNode<T> *x, T key) const;        // (非递归实现)查找AVL树中键值为key的结点        AVLTreeNode<T>* iterativeSearch(AVLTreeNode<T> *x, T key) const;                // 返回最小结点         AVLTreeNode<T>* minimum(AVLTreeNode<T> *tree);        // 返回最大结点         AVLTreeNode<T>* maximum(AVLTreeNode<T> *tree);                // 将结点插入到AVL树中        AVLTreeNode<T>* insert(AVLTreeNode<T>* &tree, T key);        // 删除结点,并返回被删除的结点         AVLTreeNode<T>* remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z);                // 销毁AVL树        void destroy(AVLTreeNode<T>* &tree);                // 打印AVL树        void print(AVLTreeNode<T> *tree,T key,int direction);                // LL:左左对应的情况(左单旋转)        AVLTreeNode<T>* leftLeftRotation(AVLTreeNode<T> *k2);        // RR:右右对应的情况(右单旋转)        AVLTreeNode<T>* rightRightRotation(AVLTreeNode<T> *k1);        // LR:左右对应的情况(左双旋转)        AVLTreeNode<T>* leftRightRotation(AVLTreeNode<T> *k3);        // RL:右左对应的情况(右双旋转)        AVLTreeNode<T>* rightLeftRotation(AVLTreeNode<T> *k1);    };

树的高度

采用维基百科上的定义:树的高度为最大层次,即空的二叉树的高度是0,非空树的高度等于它的最大层次(根的层次为1,根的子节点为第2层,依次类推)。

template<class T>int AVLTree<T>::height(AVLTreeNode<T> *tree){if(tree!=NULL)return tree->height;return 0;}template<class T>int AVLTree<T>::height(){return height(root);}

旋转

如果在AVL树中进行插入或删除结点后,可能导致AVL树失去平衡。这种失去平衡可以概括为4种姿态:LL(左左)、LR(左右)、RR(右右)、和RL(右左)。

下面给出它们的示意图:

它们各自的定义如下:

1)LL:插入或删除一个结点后,根节点的左子树的左子树还有非空结点,导致根的左子树的高度比根的右子树的高度大2,AVL树因此失去平衡。

例如,在上面LL情况中,由于根节点(8)的左子树(4)的左子树(2)还有非空子节点,而根节点(8)的右子树(12)没有子节点;导致根节点(8)的左子树(4)的高度比根节点(8)的右子树(12)高2。

2)LR:插入或删除一个结点后,根节点的左子树的右子树还有非空结点,导致根的左子树的高度比根的右子树的高度大2,AVL树因此失去平衡。

例如,在上面LR情况中,由于根节点(8)的左子树(4)的右子树(6)还有非空子节点,而根节点(8)的右子树(12)没有子节点;导致根节点(8)的左子树(4)的高度比根节点(8)的右子树(12)高2。

3)RL:插入或删除一个结点后,根节点的右子树的左子树还有非空结点,导致根的右子树的高度比根的左子树的高度大2,AVL树因此失去平衡。

例如,在上面RL情况中,由于根节点(8)的右子树(12)的左子树(10)还有非空子节点,而根节点(8)的左子树(4)没有子节点;导致根节点(8)的右子树(12)的高度比根节点(8)的左子树高2。

4)RR:插入或删除一个结点后,根节点的右子树的右子树还有非空结点,导致根的右子树的高度比根的左子树的高度大2,AVL树因此失去平衡。

例如,在上面RR情况中,由于根节点(8)的右子树(12)的右子树(14)还有非空子节点,而根节点(8)的左子树(4)没有子节点;导致根节点(8)的右子树(12)的高度比根节点(8)的左子树高2。


在AVL树失去平衡之后,可以通过相应的旋转使其恢复平衡,对应的旋转方法如下:

1)LL的旋转

LL失去平衡的情况,可以通过一次旋转让AVL树恢复平衡,如下图:

可以理解为:LL旋转是围绕失去平衡的AVL根节点进行的,也就是节点k2;而且由于是LL情况,就用手抓着左孩子(即k1)使劲摇,使得k1变成根节点,k2变成k1的右子树,k1的右子树变成k2的左子树。

旋转代码:

template<class T>AVLTreeNode<T>* AVLTree<T>::leftLeftRotation(AVLTreeNode<T> *k2){AVLTreeNode<T> *k1;k1 = k2->left;k2->left = k1->right;k1->right = k2;k2->height = max(height(k2->left), height(k2->right)) + 1;k1->height = max(height(k1->left), k2->height) + 1;return k1;}

2)RR的旋转

理解了LL之后,RR就相当容易理解了。RR是LL对称的情况,示意图如下:


旋转代码:

template<class T>AVLTreeNode<T>* AVLTree<T>::rightRightRotation(AVLTreeNode<T> *k1){AVLTreeNode<T> *k2;k2 = k1->right;k1->right = k2->left;k2->left = k1;k1->height = max(height(k1->left), height(k1->right)) + 1;k2->height = max(k1->height, height(k2->right)) + 1;return k2; }


3)LR的旋转

LR失去平衡的情况,需要经过两次旋转才能让AVL树恢复平衡,如下图所示:

第一次旋转是围绕k1进行RR旋转,第二次是围绕k3进行LL旋转。


旋转代码:

template <class T>AVLTreeNode<T>* AVLTree<T>::leftRightRotation(AVLTreeNode<T>* k3){k3->left = rightRightRotation(k3->left);return leftLeftRotation(k3);}

4)RL的旋转

RL是与LR对称的情况,示意图如下:

第一次旋转是围绕k3进行的LL旋转,第二次是围绕k1进行的RR旋转。


旋转代码:

template <class T>AVLTreeNode<T>* AVLTree<T>::rightLeftRotation(AVLTreeNode<T>* k1){k1->right = leftLeftRotation(k1->right);return rightRightRotation(k1);}

插入

template<class T>AVLTreeNode<T>* AVLTree<T>::insert(AVLTreeNode<T>* &tree, T key){if(tree==NULL){// 新建结点 tree = new AVLTreeNode<T>(key, NULL, NULL);if(tree==NULL){cout<<"ERROR: create avltree node failed!"<<endl;return NULL;}}else if(key<tree->key){tree->left = insert(tree->left, key);// 插入结点后,若AVL树失去平衡,则进行相应的调节if(height(tree->left)-height(tree->right)==2){if(key<tree->left->key)tree = leftLeftRotation(tree);elsetree = leftRightRotaion(tree);} }else{tree->right = insert(tree->right, key);// 插入结点后,若AVL树失去平衡,则进行相应的调节if(height(tree->right)-height(tree->left)==2){if(key>tree->right->key)tree = rightRightRotation(tree);elsetree = rightLeftRotaion(tree);} }tree->height = max(height(tree->left), height(tree->right)) + 1;return tree;}template<class T>void AVLTree<T>::insert(T key){insert(root,key);}

删除

template<class T>AVLTreeNode<T>* AVLTree<T>::remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z){// 根为空 或者 没有要删除的结点if(tree==NULL || z==NULL)return NULL;if(z->key<tree->key){tree->left = remove(tree->left, z);// 删除结点后,若AVL树失去平衡,则进行相应调节if(height(tree->right)-height(tree->left)==2){AVLTreeNode<T> *r = tree->right;if(height(r->left)>height(r->right))tree = rightLeftRotation(tree);elsetree = rightRightRotation(tree);} } else if(z->key>tree->key){tree->right = remove(tree->right, z);if(height(tree->left)-height(tree->right)==2){AVLTreeNode<T> *r = tree->left;if(height(r->left)<height(r->right))tree = leftRightRotation(tree);elsetree = leftLeftRotation(tree);}}else// tree是对应要删除的结点 {// tree的左右孩子都非空 if((tree->left!=NULL)&&(tree->right!=NULL)){if(height(tree->left)>height(tree->right)){// 如果tree的左子树比右子树高;                // 则(01)找出tree的左子树中的最大节点                //   (02)将该最大节点的值赋值给tree。                //   (03)删除该最大节点。                // 这类似于用"tree的左子树中最大节点"做"tree"的替身;                // 采用这种方式的好处是:删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。                AVLTreeNode<T> *max = maximum(tree->left);                tree->key = max->key;                tree->left = remove(tree->left, max);}else{// 如果tree的左子树不比右子树高(即它们相等,或右子树比左子树高1)                // 则(01)找出tree的右子树中的最小节点                //   (02)将该最小节点的值赋值给tree。                //   (03)删除该最小节点。                // 这类似于用"tree的右子树中最小节点"做"tree"的替身;                // 采用这种方式的好处是:删除"tree的右子树中最小节点"之后,AVL树仍然是平衡的。                AVLTreeNode<T> *min = minimum(tree->right);                tree->key = min->key;tree->right = remove(tree->right, min); }}else{AVLTreeNode<T> *tmp = tree;tree = (tree->left!=NULL) ? tree->left : tree->right;delete tmp;}}return tree;}template<class T>void AVLTree<T>::remove(T key){    AVLTreeNode<T> *z;    if((z=search(root,key))!=NULL)        root = remove(root,z);}

关于AVL树的前序遍历、中序遍历、后序遍历、最大值、最小值、查找、打印、销毁等接口与二叉查找树基本一样,这些已经介绍过了就不再单独介绍了。


完整实现

头文件:AVLTree.h

#ifndef AVL_TREE#define AVL_TREE#include<iomanip>#include<iostream>using namespace std;template<class T>class AVLTreeNode{    public:        T key;    // 关键字(键值)        int height;    // 高度        AVLTreeNode *left;    // 左孩子        AVLTreeNode *right;    // 右孩子            AVLTreeNode(T value, AVLTreeNode *l, AVLTreeNode *r) :            key(value) ,left(l),right(r) {}};template<class T>class AVLTree{    private:        AVLTreeNode<T> *root;    // 根结点        public:        // 外部接口          AVLTree();         ~AVLTree();                 // 获取树的高度        int height();        // 比较两个值的大小         int max(int a, int b);                // 前序遍历        void preOrder();        // 中序遍历        void inOrder();        // 后序遍历        void postOrder();                // (递归实现)查找AVL树中键值为key的结点        AVLTreeNode<T>* search(T key);        // (非递归实现)查找AVL树中键值为key的结点        AVLTreeNode<T>* iterativeSearch(T key);                // 查找最小结点:返回最小结点的键值        T minimum();        // 查找最大结点:返回最大结点的键值        T maximum();                // 将结点插入到AVL树中        void insert(T key);        // 删除结点        void remove(T key);                // 销毁AVL树        void destroy();                // 打印AVL树        void print();        private:        // 内部接口         // 获取树的高度        int height(AVLTreeNode<T> *tree);                // 前序遍历        void preOrder(AVLTreeNode<T> *tree) const;        // 中序遍历        void inOrder(AVLTreeNode<T> *tree) const;        // 后序遍历        void postOrder(AVLTreeNode<T> *tree) const;                // (递归实现)查找AVL树中键值为key的结点        AVLTreeNode<T>* search(AVLTreeNode<T> *x, T key) const;        // (非递归实现)查找AVL树中键值为key的结点        AVLTreeNode<T>* iterativeSearch(AVLTreeNode<T> *x, T key) const;                // 返回最小结点         AVLTreeNode<T>* minimum(AVLTreeNode<T> *tree);        // 返回最大结点         AVLTreeNode<T>* maximum(AVLTreeNode<T> *tree);                // 将结点插入到AVL树中        AVLTreeNode<T>* insert(AVLTreeNode<T>* &tree, T key);        // 删除结点,并返回被删除的结点         AVLTreeNode<T>* remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z);                // 销毁AVL树        void destroy(AVLTreeNode<T>* &tree);                // 打印AVL树        void print(AVLTreeNode<T> *tree,T key,int direction);                // LL:左左对应的情况(左单旋转)        AVLTreeNode<T>* leftLeftRotation(AVLTreeNode<T> *k2);        // RR:右右对应的情况(右单旋转)        AVLTreeNode<T>* rightRightRotation(AVLTreeNode<T> *k1);        // LR:左右对应的情况(左双旋转)        AVLTreeNode<T>* leftRightRotation(AVLTreeNode<T> *k3);        // RL:右左对应的情况(右双旋转)        AVLTreeNode<T>* rightLeftRotation(AVLTreeNode<T> *k1);    };template<class T>AVLTree<T>::AVLTree(): root(NULL){}template<class T>AVLTree<T>::~AVLTree(){    destroy(root);}template<class T>int AVLTree<T>::height(AVLTreeNode<T> *tree){    if(tree!=NULL)        return tree->height;    return 0;}template<class T>int AVLTree<T>::height(){    return height(root);}template<class T>int AVLTree<T>::max(int a, int b){    return a>b ? a : b;}template<class T>AVLTreeNode<T>* AVLTree<T>::leftLeftRotation(AVLTreeNode<T> *k2){    AVLTreeNode<T> *k1;        k1 = k2->left;    k2->left = k1->right;    k1->right = k2;        k2->height = max(height(k2->left), height(k2->right)) + 1;    k1->height = max(height(k1->left), k2->height) + 1;        return k1;}template<class T>AVLTreeNode<T>* AVLTree<T>::rightRightRotation(AVLTreeNode<T> *k1){    AVLTreeNode<T> *k2;        k2 = k1->right;    k1->right = k2->left;    k2->left = k1;        k1->height = max(height(k1->left), height(k1->right)) + 1;    k2->height = max(k1->height, height(k2->right)) + 1;        return k2; }template <class T>AVLTreeNode<T>* AVLTree<T>::leftRightRotation(AVLTreeNode<T>* k3){    k3->left = rightRightRotation(k3->left);        return leftLeftRotation(k3);}template <class T>AVLTreeNode<T>* AVLTree<T>::rightLeftRotation(AVLTreeNode<T>* k1){    k1->right = leftLeftRotation(k1->right);        return rightRightRotation(k1);}template<class T>AVLTreeNode<T>* AVLTree<T>::insert(AVLTreeNode<T>* &tree, T key){    if(tree==NULL)    {        // 新建结点         tree = new AVLTreeNode<T>(key, NULL, NULL);        if(tree==NULL)        {            cout<<"ERROR: create avltree node failed!"<<endl;            return NULL;        }    }    else if(key<tree->key)    {        tree->left = insert(tree->left, key);        // 插入结点后,若AVL树失去平衡,则进行相应的调节        if(height(tree->left)-height(tree->right)==2)        {            if(key<tree->left->key)                tree = leftLeftRotation(tree);            else                tree = leftRightRotation(tree);        }     }    else    {        tree->right = insert(tree->right, key);        // 插入结点后,若AVL树失去平衡,则进行相应的调节        if(height(tree->right)-height(tree->left)==2)        {            if(key>tree->right->key)                tree = rightRightRotation(tree);            else                tree = rightLeftRotation(tree);        }     }        tree->height = max(height(tree->left), height(tree->right)) + 1;        return tree;}template<class T>void AVLTree<T>::insert(T key){    insert(root,key);}template<class T>AVLTreeNode<T>* AVLTree<T>::remove(AVLTreeNode<T>* &tree, AVLTreeNode<T> *z){    // 根为空 或者 没有要删除的结点    if(tree==NULL || z==NULL)        return NULL;    if(z->key<tree->key)    {        tree->left = remove(tree->left, z);        // 删除结点后,若AVL树失去平衡,则进行相应调节        if(height(tree->right)-height(tree->left)==2)        {            AVLTreeNode<T> *r = tree->right;            if(height(r->left)>height(r->right))                tree = rightLeftRotation(tree);            else                tree = rightRightRotation(tree);        }     }     else if(z->key>tree->key)    {        tree->right = remove(tree->right, z);        if(height(tree->left)-height(tree->right)==2)        {            AVLTreeNode<T> *r = tree->left;            if(height(r->left)<height(r->right))                tree = leftRightRotation(tree);            else                tree = leftLeftRotation(tree);        }    }    else    // tree是对应要删除的结点     {        // tree的左右孩子都非空         if((tree->left!=NULL)&&(tree->right!=NULL))        {            if(height(tree->left)>height(tree->right))            {                // 如果tree的左子树比右子树高;                // 则(01)找出tree的左子树中的最大节点                //   (02)将该最大节点的值赋值给tree。                //   (03)删除该最大节点。                // 这类似于用"tree的左子树中最大节点"做"tree"的替身;                // 采用这种方式的好处是:删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。                AVLTreeNode<T> *max = maximum(tree->left);                tree->key = max->key;                tree->left = remove(tree->left, max);            }            else            {                // 如果tree的左子树不比右子树高(即它们相等,或右子树比左子树高1)                // 则(01)找出tree的右子树中的最小节点                //   (02)将该最小节点的值赋值给tree。                //   (03)删除该最小节点。                // 这类似于用"tree的右子树中最小节点"做"tree"的替身;                // 采用这种方式的好处是:删除"tree的右子树中最小节点"之后,AVL树仍然是平衡的。                AVLTreeNode<T> *min = minimum(tree->right);                tree->key = min->key;                tree->right = remove(tree->right, min);             }        }        else        {            AVLTreeNode<T> *tmp = tree;            tree = (tree->left!=NULL) ? tree->left : tree->right;            delete tmp;        }    }        return tree;}template<class T>void AVLTree<T>::remove(T key){    AVLTreeNode<T> *z;    if((z=search(root,key))!=NULL)        root = remove(root,z);}template<class T>void AVLTree<T>::preOrder(AVLTreeNode<T> *tree) const{    if(tree!=NULL)    {        cout<<tree->key<<" ";        preOrder(tree->left);        preOrder(tree->right);    }}template<class T>void AVLTree<T>::preOrder(){    preOrder(root);}template<class T>void AVLTree<T>::inOrder(AVLTreeNode<T> *tree) const{    if(tree!=NULL)    {        inOrder(tree->left);        cout<<tree->key<<" ";        inOrder(tree->right);    }}template<class T>void AVLTree<T>::inOrder(){    inOrder(root);}template<class T>void AVLTree<T>::postOrder(AVLTreeNode<T> *tree) const{    if(tree!=NULL)    {        postOrder(tree->left);        postOrder(tree->right);        cout<<tree->key<<" ";    }}template<class T>void AVLTree<T>::postOrder(){    postOrder(root);}template<class T>AVLTreeNode<T>* AVLTree<T>::search(AVLTreeNode<T> *x, T key) const{    if(x==NULL || x->key==key)        return x;    if(key<x->key)        return search(x->left, key);    else        return search(x->right, key);}template<class T>AVLTreeNode<T>* AVLTree<T>::search(T key){    return search(root, key);}template<class T>AVLTreeNode<T>* AVLTree<T>::iterativeSearch(AVLTreeNode<T> *x, T key) const{    while(x!=NULL && x->key!=key)    {        if(key<x->key)            x = x->left;        else            x = x->right;    }    return x;}template<class T>AVLTreeNode<T>* AVLTree<T>::iterativeSearch(T key){    return iterativeSearch(root, key);}template<class T>AVLTreeNode<T>* AVLTree<T>::minimum(AVLTreeNode<T> *tree){    if(tree==NULL)        return NULL;    while(tree->left!=NULL)        tree = tree->left;    return tree;}template<class T>T AVLTree<T>::minimum(){    AVLTreeNode<T> *p = minimum(root);    if(p!=NULL)        return p->key;    return (T)NULL;}template<class T>AVLTreeNode<T>* AVLTree<T>::maximum(AVLTreeNode<T> *tree){    if(tree==NULL)        return NULL;    while(tree->right!=NULL)        tree = tree->right;    return tree;}template<class T>T AVLTree<T>::maximum(){    AVLTreeNode<T> *p = maximum(root);    if(p!=NULL)        return p->key;    return (T)NULL;}template<class T>void AVLTree<T>::destroy(AVLTreeNode<T> *&tree){    if(tree==NULL)        return ;    if(tree->left!=NULL)        destroy(tree->left);    if(tree->right!=NULL)        destroy(tree->right);    delete tree;}template<class T>void AVLTree<T>::destroy(){    destroy(root);}template<class T>void AVLTree<T>::print(AVLTreeNode<T> *tree, T key, int direction){    if(tree!=NULL)    {        if(direction==0)            cout<<setw(2)<<tree->key<<"is root"<<endl;        else            cout<<setw(2)<<tree->key<<"is"<<setw(2)<<key<<"'s"<<setw(12)<<(direction==1 ? "right child" : "left child")<<endl;        print(tree->left, tree->key, -1);        print(tree->right, tree->key, 1);    }}template<class T>void AVLTree<T>::print(){    if(root!=NULL)        print(root, root->key, 0);}#endif

测试文件:AVLTreeTest.cpp

#include<iostream>#include "AVLTree.h"using namespace std;static int arr[] = {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};int main(){int i,len;AVLTree<int> *tree = new AVLTree<int>();cout<<"依次添加:";len = sizeof(arr)/sizeof(arr[0]);for(i=0;i<len;++i){cout<<arr[i]<<" ";tree->insert(arr[i]);}cout<<"\n前序遍历:";tree->preOrder();cout<<"\n中序遍历:";tree->inOrder();cout<<"\n后序遍历:";tree->postOrder();cout<<"\n高度: "<<tree->height()<<endl;    cout<<"最小值: "<<tree->minimum()<<endl;    cout<<"最大值: "<<tree->maximum()<<endl;    cout<<"树的详细信息: "<<endl;    tree->print();        i = 8;    cout<<"\n删除根节点:"<<i;    tree->remove(i);        cout<<"\n高度: "<<tree->height()<<endl;    cout<<"中序遍历:";    tree->inOrder();    cout<<"\n树的详细信息: "<<endl;    tree->print();        // 销毁二叉树tree->destroy();return 0; }

测试程序示意图:

(1)添加3,2:

(2)添加1:

(3)添加4:

(4)添加5:

(5)... ....

(6)添加完所有数据后,得到的AVL树如下:



(7)删除节点8:


程序运行结果如下:



参考资料:

感谢作者如果天空不死 :AVL树

0 0
原创粉丝点击