数据结构之AVL树

来源:互联网 发布:淘宝网怎么绑定信用卡 编辑:程序博客网 时间:2024/05/16 10:04

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

旋转

如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。这种失去平衡的可以概括为4种姿态:LL(左左),LR(左右),RR(右右)和RL(右左)。下面给出它们的示意图:

1) LL:LeftLeft,也称为”左左”。插入或删除一个节点后,根节点的左子树的左子树还有非空子节点,导致”根的左子树的高度”比”根的右子树的高度”大2,导致AVL树失去了平衡。
例如,在上面LL情况中,由于”根节点(8)的左子树(4)的左子树(2)还有非空子节点”,而”根节点(8)的右子树(12)没有子节点”;导致”根节点(8)的左子树(4)高度”比”根节点(8)的右子树(12)”高2。

(2) LR:LeftRight,也称为”左右”。插入或删除一个节点后,根节点的左子树的右子树还有非空子节点,导致”根的左子树的高度”比”根的右子树的高度”大2,导致AVL树失去了平衡。
例如,在上面LR情况中,由于”根节点(8)的左子树(4)的左子树(6)还有非空子节点”,而”根节点(8)的右子树(12)没有子节点”;导致”根节点(8)的左子树(4)高度”比”根节点(8)的右子树(12)”高2。

(3) RL:RightLeft,称为”右左”。插入或删除一个节点后,根节点的右子树的左子树还有非空子节点,导致”根的右子树的高度”比”根的左子树的高度”大2,导致AVL树失去了平衡。
例如,在上面RL情况中,由于”根节点(8)的右子树(12)的左子树(10)还有非空子节点”,而”根节点(8)的左子树(4)没有子节点”;导致”根节点(8)的右子树(12)高度”比”根节点(8)的左子树(4)”高2。

(4) RR:RightRight,称为”右右”。插入或删除一个节点后,根节点的右子树的右子树还有非空子节点,导致”根的右子树的高度”比”根的左子树的高度”大2,导致AVL树失去了平衡。
例如,在上面RR情况中,由于”根节点(8)的右子树(12)的右子树(14)还有非空子节点”,而”根节点(8)的左子树(4)没有子节点”;导致”根节点(8)的右子树(12)高度”比”根节点(8)的左子树(4)”高2。

前面说过,如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。AVL失去平衡之后,可以通过旋转使其恢复平衡,下面分别介绍”LL(左左),LR(左右),RR(右右)和RL(右左)”这4种情况对应的旋转方法。

2.1 LL的旋转

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

/* * LL:左左对应的情况(左单旋转)。 * * 返回值:旋转后的根节点 */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.2 RR的旋转

理解了LL之后,RR就相当容易理解了。RR是与LL对称的情况!RR恢复平衡的旋转方法如下:

/* * RR:右右对应的情况(右单旋转)。 * * 返回值:旋转后的根节点 */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( height(k2->right), k1->height) + 1;    return k2;}

2.3 LR的旋转

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

/* * LR:左右对应的情况(左双旋转)。 * * 返回值:旋转后的根节点 */template <class T>AVLTreeNode<T>* AVLTree<T>::leftRightRotation(AVLTreeNode<T>* k3){    k3->left = rightRightRotation(k3->left);    return leftLeftRotation(k3);}

2.4 RL的旋转

RL是与LR的对称情况!RL恢复平衡的旋转方法如下:

/* * RL:右左对应的情况(右双旋转)。 * * 返回值:旋转后的根节点 */template <class T>AVLTreeNode<T>* AVLTree<T>::rightLeftRotation(AVLTreeNode<T>* k1){    k1->right = leftLeftRotation(k1->right);    return rightRightRotation(k1);}

完整代码

#ifndef _AVL_TREE_HPP_#define _AVL_TREE_HPP_#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), height(0),left(l),right(r) {}};template <class T>class AVLTree {    private:        AVLTreeNode<T> *mRoot;    // 根结点    public:        AVLTree();        ~AVLTree();        // 获取树的高度        int height();        // 获取树的高度        int max(int a, int b);        // 前序遍历"AVL树"        void preOrder();        // 中序遍历"AVL树"        void inOrder();        // 后序遍历"AVL树"        void postOrder();        // (递归实现)查找"AVL树"中键值为key的节点        AVLTreeNode<T>* search(T key);        // (非递归实现)查找"AVL树"中键值为key的节点        AVLTreeNode<T>* iterativeSearch(T key);        // 查找最小结点:返回最小结点的键值。        T minimum();        // 查找最大结点:返回最大结点的键值。        T maximum();        // 将结点(key为节点键值)插入到AVL树中        void insert(T key);        // 删除结点(key为节点键值)        void remove(T key);        // 销毁AVL树        void destroy();        // 打印AVL树        void print();    private:        // 获取树的高度        int height(AVLTreeNode<T>* tree) ;        // 前序遍历"AVL树"        void preOrder(AVLTreeNode<T>* tree) const;        // 中序遍历"AVL树"        void inOrder(AVLTreeNode<T>* tree) const;        // 后序遍历"AVL树"        void postOrder(AVLTreeNode<T>* tree) const;        // (递归实现)查找"AVL树x"中键值为key的节点        AVLTreeNode<T>* search(AVLTreeNode<T>* x, T key) const;        // (非递归实现)查找"AVL树x"中键值为key的节点        AVLTreeNode<T>* iterativeSearch(AVLTreeNode<T>* x, T key) const;        // 查找最小结点:返回tree为根结点的AVL树的最小结点。        AVLTreeNode<T>* minimum(AVLTreeNode<T>* tree);        // 查找最大结点:返回tree为根结点的AVL树的最大结点。        AVLTreeNode<T>* maximum(AVLTreeNode<T>* tree);        // 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);        // 将结点(z)插入到AVL树(tree)中        AVLTreeNode<T>* insert(AVLTreeNode<T>* &tree, T key);        // 删除AVL树(tree)中的结点(z),并返回被删除的结点        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);};/*  * 构造函数 */template <class T>AVLTree<T>::AVLTree():mRoot(NULL){}/*  * 析构函数 */template <class T>AVLTree<T>::~AVLTree() {    destroy(mRoot);}/* * 获取树的高度 */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(mRoot);}/* * 比较两个值的大小 */template <class T>int AVLTree<T>::max(int a, int b) {    return a>b ? a : b;}/* * 前序遍历"AVL树" */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(mRoot);}/* * 中序遍历"AVL树" */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(mRoot);}/* * 后序遍历"AVL树" */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(mRoot);}/* * (递归实现)查找"AVL树x"中键值为key的节点 */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(mRoot, key);}/* * (非递归实现)查找"AVL树x"中键值为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(mRoot, key);}/*  * 查找最小结点:返回tree为根结点的AVL树的最小结点。 */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(mRoot);    if (p != NULL)        return p->key;    return (T)NULL;}/*  * 查找最大结点:返回tree为根结点的AVL树的最大结点。 */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(mRoot);    if (p != NULL)        return p->key;    return (T)NULL;}/* * LL:左左对应的情况(左单旋转)。 * * 返回值:旋转后的根节点 */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;}/* * RR:右右对应的情况(右单旋转)。 * * 返回值:旋转后的根节点 */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( height(k2->right), k1->height) + 1;    return k2;}/* * LR:左右对应的情况(左双旋转)。 * * 返回值:旋转后的根节点 */template <class T>AVLTreeNode<T>* AVLTree<T>::leftRightRotation(AVLTreeNode<T>* k3){    k3->left = rightRightRotation(k3->left);    return leftLeftRotation(k3);}/* * RL:右左对应的情况(右双旋转)。 * * 返回值:旋转后的根节点 */template <class T>AVLTreeNode<T>* AVLTree<T>::rightLeftRotation(AVLTreeNode<T>* k1){    k1->right = leftLeftRotation(k1->right);    return rightRightRotation(k1);}/*  * 将结点插入到AVL树中,并返回根节点 * * 参数说明: *     tree AVL树的根结点 *     key 插入的结点的键值 * 返回值: *     根节点 */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) // 应该将key插入到"tree的左子树"的情况    {        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 if (key > tree->key) // 应该将key插入到"tree的右子树"的情况    {        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);        }    }    else //key == tree->key)    {        cout << "添加失败:不允许添加相同的节点!" << endl;    }    tree->height = max( height(tree->left), height(tree->right)) + 1;    return tree;}template <class T>void AVLTree<T>::insert(T key){    insert(mRoot, key);}/*  * 删除结点(z),返回根节点 * * 参数说明: *     tree AVL树的根结点 *     z 待删除的结点 * 返回值: *     根节点 */template <class T>AVLTreeNode<T>* AVLTree<T>::remove(AVLTreeNode<T>* &tree, AVLTreeNode<T>* z){    // 根为空 或者 没有要删除的节点,直接返回NULLif (tree==NULL || z==NULL)        return NULL;    if (z->key < tree->key)        // 待删除的节点在"tree的左子树"中    {        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的右子树"中    {        tree->right = remove(tree->right, z);        // 删除节点后,若AVL树失去平衡,则进行相应的调节。        if (height(tree->left) - height(tree->right) == 2)        {            AVLTreeNode<T> *l =  tree->left;            if (height(l->right) > height(l->left))                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 = maximum(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(mRoot, key)) != NULL)        mRoot = remove(mRoot, z);}/*  * 销毁AVL树 */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(mRoot);}/* * 打印"二叉查找树" * * key        -- 节点的键值  * direction  --  0,表示该节点是根节点; *               -1,表示该节点是它的父结点的左孩子; *                1,表示该节点是它的父结点的右孩子。 */template <class T>void AVLTree<T>::print(AVLTreeNode<T>* tree, T key, int direction){    if(tree != NULL)    {        if(direction==0)    // tree是根节点            cout << setw(2) << tree->key << " is root" << endl;        else                // tree是分支节点            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 (mRoot != NULL)        print(mRoot, mRoot->key, 0);}#endif

测试代码

/** * C 语言: AVL树 * * @author skywang * @date 2013/11/07 */#include <iostream>#include "start.h"using namespace std;static int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};#define TBL_SIZE(a) ( (sizeof(a)) / (sizeof(a[0])) )int main(){    int i,ilen;    AVLTree<int>* tree=new AVLTree<int>();    cout << "== 依次添加: ";    ilen = TBL_SIZE(arr);    for(i=0; i<ilen; i++)    {        cout << arr[i] <<" ";        tree->insert(arr[i]);    }    cout << "\n== 前序遍历: ";    tree->preOrder();    cout << "\n== 中序遍历: ";    tree->inOrder();    cout << "\n== 后序遍历: ";    tree->postOrder();    cout << endl;    cout << "== 高度: " << 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() ;    cout << "\n== 中序遍历: " ;    tree->inOrder();    cout << "\n== 树的详细信息: " << endl;    tree->print();    // 销毁二叉树    tree->destroy();    system("pause");    return 0;}

References

AVL树(二)之 C++的实现 - 如果天空不死 - 博客园

效果如下

这里写图片描述

这里写图片描述

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 住酒店手机id被劫持了怎么办 孩子老是送玩具给别的小朋友怎么办 老板总想和我谈人生怎么办gl 导师让用师姐的数据写论文怎么办 签了平面模特协议想违约怎么办 福州96年以前社保手册丢了怎么办 被老师缴的手机弄没了怎么办 户口在成都医保在德阳生孩子怎么办 微课掌上通看不到孩子班级圈怎么办 微课掌上通的录音错误是怎么办 微课视频录制ppt里面音乐怎么办 老师在街上和别人吵起来了怎么办 手机录屏传到爱剪辑变成竖屏怎么办 尔雅通识课程考试忘记做了怎么办 尔雅通识课过了课程完成时间怎么办 微信账号没冻结登录不了怎么办 微信解封电话号码没有电话号怎么办 ps中智能对象不能直接编辑怎么办 工资低奖金高银行流水不够怎么办 我水费交了自来水公司不给开怎么办 艺考文化分数差4分二本怎么办 学信网手机号换了密码忘记了怎么办 自考毕业证学信网上查不到怎么办 苹果手机自带浏览器证书过期怎么办 手机连接工行证书介质失贩怎么办 老公要带与小三生的孩子回家怎么办 小三怀孕打胎后还是很爱老公怎么办 小三怀孕开不到引产证明怎么办 如何处理老公和小三有了孩子怎么办 老公出轨回归后还和小三联系怎么办 丈夫出轨想挽回这段婚姻该怎么办 最新版ppt没保存就关闭了怎么办 杂志社不给寄论文版面费发票怎么办 学区房因为户籍没满一年怎么办 没学历没技术的年轻人该怎么办? 二十岁没有学历没有技术该怎么办 单位派我去进修我没去怎么办 老师在教育学生学生跑出教室怎么办 孩子遇到校园暴力回来不敢说怎么办 学位网没有英文认证出国留学怎么办 4-5岁幼儿记忆不好该怎么办