树(四):平衡二叉树(AVL) C++实现

树系列文章:
树(一):二叉树(BiTree) 创建+销毁+前中后层遍历(递归+非递归)C++

树(二):线索二叉树(ThreadBiTree) 线索化及其非递归遍历C++

树(三):二叉排序树(BST) C++实现

树(四):平衡二叉树(AVL) C++实现

树(五):哈夫曼树(HuffmanTree) C++实现


前言

AVL树相当于是在BST(二叉搜索树)的基础上进行了改进,因为简单的BST并不能保证一个较高的查找成功率,最坏情况下可能会编程链表形式,也就是O(n)的时间复杂度;如果能让左子树与右子树的高度绝对值小于等于1,那么可以将查找成功率变为最大,并且复杂度变为O(logn)。

由于AVL树的编写较为复杂,我们这里只展示AVL树的核心代码,完整的代码可以参考这一篇文章:
AVL之C++实现


树节点的旋转

可以说只要搞懂了AVL节点的旋转规律,也就搞懂了AVL树,整个AVL树在代码中本质上只涉及左旋(RR)和右旋(LL)。LR旋转和RL旋转也只是在前两种旋转的基础上做了一些改变。

  • RR旋转
//RR 左旋
TreeNode *AVLTree::RR(TreeNode *root)
{
    TreeNode* rchild = root->right;
    root->right = rchild->left;
    rchild->left = root;
    root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
    rchild->height = std::max(getHeight(rchild->left), getHeight(rchild->right)) + 1;
    return rchild;
}
  • LL旋转

//LL 右旋
TreeNode *AVLTree::LL(TreeNode *root)
{
    TreeNode* lchild = root->left;
    root->left = lchild->right;
    lchild->right = root;
    root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
    lchild->height = std::max(getHeight(lchild->left), getHeight(lchild->right)) + 1;
    return lchild;
}

RL与LR实质上也就是上面两种旋转的结合

  • LR旋转
//LR 先左旋再右旋,左旋后整个树实际上也就变成了LL的模样
TreeNode* AVLTree::LR(TreeNode* root)
{
    root->left = RR(root->left);
    return LL(root);
}

  • RL旋转
//RL旋 先右旋再左旋,右旋后整个树实质上也就变成了RR的模样
TreeNode* AVLTree::RL(TreeNode* root)
{
    root->right = LL(root->right);
    return RR(root);
}

  • AVL树的插入
TreeNode* AVLTree::insertNode(TreeNode *root, int val)
{
    if (!root)
    {
        TreeNode* node = new TreeNode(val);
        return node;    
    }

    if (root->val == val)
    {
        return root; //AVL树中已经有该节点,不能够再插入
    }
    else if (val > root->val)
    {
        //向右插入
        root->right = insertNode(root->right, val);
        //插入新节点后如果失去平衡则调整
        if (getHeight(root->right) - getHeight(root->left) == 2)
        {
            TreeNode* t = root->right;
            if (getHeight(t->left) > getHeight(t->right))
                root = RL(root);
            else
                root = RR(root);
        }
    }else if (val < root->val)
    {
        //向左插入
        root->left = insertNode(root->left, val);
        //插入新节点后如果失去平衡则调整
        if (getHeight(root->left) - getHeight(root->right) == 2)
        {
            TreeNode* t = root->left;
            if (getHeight(t->left) > getHeight(t->right))
                root = LL(root);
            else
                root = LR(root);
        }
    }
    root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
    return root;
}


  • AVL树的 删除
TreeNode *AVLTree::deleteNode(TreeNode *root, int key)
{
    if (!root)//该节点并不存在
        return nullptr;

    if (key < root->val)
    {
        //key在root左侧
        root->left = deleteNode(root->left, key);
        if (getHeight(root->right) - getHeight(root->left) == 2)
        {
            TreeNode* t = root->right;
            if (getHeight(t->right) > getHeight(t->left))
                root = RR(root);
            else
                root = RL(root);
        }
    }else if (key > root->val)
    {
        //key在root右侧
        root->right = deleteNode(root->right, key);
        if (getHeight(root->left) - getHeight(root->right) == 2)
        {
            TreeNode* t = root->left;
            if (getHeight(t->left) > getHeight(t->right))
                root = LL(root);
            else
                root = LR(root);
        }
    }else
    {
        //找到要删除的节点key
        if (root->left && root->right)
        {
            if (getHeight(root->left) > getHeight(root->right))//从更高的子树开始删除,可以保证删除之后AVL仍然平衡
            {
                TreeNode* t = root->left;
                while(t->right)
                    t = t->right;
                root->val = t->val;
                root->left = deleteNode(root->left, t->val);
            }else
            {
                TreeNode* t = root->right;
                while(t->left)
                    t = t->left;
                root->val = t->val;
                root->right = deleteNode(root->right, t->val);
            }
        }else
        {
            TreeNode* t = root;
            root = root->left ? root->left : root->right;
            delete t;
            return root;
        }
    }

    root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
    return root;
}



1.LL旋转

插入之前树结构如下:
在这里插入图片描述
插入0之后:
在这里插入图片描述
LL旋转后:
在这里插入图片描述

2.LR旋转

基础树结构如下:
在这里插入图片描述
插入3之后:
在这里插入图片描述
LR旋转:先左旋,再右旋
先让根节点的左孩子左旋:
在这里插入图片描述
再让根节点右旋:
在这里插入图片描述

3.RR旋转

基本树结构如下:
在这里插入图片描述
插入7, 9 之后:
在这里插入图片描述
RR旋转后:
在这里插入图片描述

4.RL旋转

基本树结构如下:
在这里插入图片描述
插入4之后:
在这里插入图片描述
RL旋转:先右旋再左旋

先对根节点右孩子进行右旋:
在这里插入图片描述
然后对根节点进行左旋:
在这里插入图片描述

AVL程序代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <sstream>
using namespace std;

/*********************************AVL(平衡二叉树)**************************************/
/*********************************类申明**************************************/
struct TreeNode
{
    int val;
    int height;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int val) : val(val), height(1), left(NULL), right(NULL) {}
};

class AVLTree
{
    TreeNode *_root;
public:
    AVLTree();
    AVLTree(string s);
    ~AVLTree();

    void preTraverse(TreeNode *);              //前序遍历
    void inTraverse(TreeNode *);               //中序遍历AVL树,结果应由大到小
    TreeNode *search(TreeNode *, int val);     //查询操作,找到则返回节点,否则返回NULL
    TreeNode *getRoot() const { return _root; }
    TreeNode* insertNode(TreeNode *, int val);         //插入节点操作
    TreeNode *deleteNode(TreeNode *, int val); //删除操作
    void insertNode(int val);         //插入节点操作
    void deleteNode(int val); //删除操作

    //AVL树特有的成员变量
    TreeNode *RR(TreeNode *);    //左旋
    TreeNode *LL(TreeNode *);   //右旋
    TreeNode *LR(TreeNode *);   //先左旋再右旋
    TreeNode *RL(TreeNode *);   //先右旋再左旋
    int getHeight(TreeNode *);           //求树的高度
private:
    void destroyAVLTree(TreeNode *);
};

/*********************************类成员定义**************************************/

AVLTree::AVLTree()
:_root(nullptr)
{
    cout << "AVLTree()" << endl;
}

AVLTree::AVLTree(string s)
    : _root(NULL)
{
    cout << "AVLTree()" << endl;
    stringstream ss(s);
    int val;
    while (ss >> val)
        _root = insertNode(_root, val);
}

AVLTree::~AVLTree()
{
    if (_root)
    {
        destroyAVLTree(_root);
        cout << "~AVLTree()" << endl;
    }
}

void AVLTree::destroyAVLTree(TreeNode *root)
{
    if (!root)
        return;
    else
    {
        destroyAVLTree(root->left);
        destroyAVLTree(root->right);
        delete root;
        root = NULL;
    }
}

void AVLTree::preTraverse(TreeNode *TreeNode)
{
    if (TreeNode)
    {
        cout << TreeNode->val << " ";
        preTraverse(TreeNode->left);
        preTraverse(TreeNode->right);
    }
}

void AVLTree::inTraverse(TreeNode *TreeNode)
{
    if (TreeNode)
    {
        inTraverse(TreeNode->left);
        cout << TreeNode->val << " ";
        inTraverse(TreeNode->right);
    }
}

TreeNode *AVLTree::search(TreeNode *p, int val)
{
    if (!p)
        return NULL;
    else if (val < p->val)
        return search(p->left, val);
    else if (val > p->val)
        return search(p->right, val);
    else
        return p;
}


int AVLTree::getHeight(TreeNode *root)
{
    if (!root)
        return 0;
    else
        return root->height;
}

TreeNode *AVLTree::RR(TreeNode *root)
{
    TreeNode* rchild = root->right;
    root->right = rchild->left;
    rchild->left = root;
    root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
    rchild->height = std::max(getHeight(rchild->left), getHeight(rchild->right)) + 1;
    return rchild;
}

TreeNode *AVLTree::LL(TreeNode *root)
{
    TreeNode* lchild = root->left;
    root->left = lchild->right;
    lchild->right = root;
    root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
    lchild->height = std::max(getHeight(lchild->left), getHeight(lchild->right)) + 1;
    return lchild;
}

TreeNode* AVLTree::LR(TreeNode* root)
{
    root->left = RR(root->left);
    return LL(root);
}

TreeNode* AVLTree::RL(TreeNode* root)
{
    root->right = LL(root->right);
    return RR(root);
}


TreeNode* AVLTree::insertNode(TreeNode *root, int val)
{
    if (!root)
    {
        TreeNode* node = new TreeNode(val);
        return node;    
    }

    if (root->val == val)
    {
        return root; //AVL树中已经有该节点,不能够再插入
    }
    else if (val > root->val)
    {
        //向右插入
        root->right = insertNode(root->right, val);
        //插入新节点后如果失去平衡则调整
        if (getHeight(root->right) - getHeight(root->left) == 2)
        {
            TreeNode* t = root->right;
            if (getHeight(t->left) > getHeight(t->right))
                root = RL(root);
            else
                root = RR(root);
        }
    }else if (val < root->val)
    {
        //向左插入
        root->left = insertNode(root->left, val);
        //插入新节点后如果失去平衡则调整
        if (getHeight(root->left) - getHeight(root->right) == 2)
        {
            TreeNode* t = root->left;
            if (getHeight(t->left) > getHeight(t->right))
                root = LL(root);
            else
                root = LR(root);
        }
    }
    root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
    return root;
}

void AVLTree::insertNode(int val)
{
    _root  = insertNode(_root, val);
}

void AVLTree::deleteNode(int val)
{
    _root = deleteNode(_root, val);
}

TreeNode *AVLTree::deleteNode(TreeNode *root, int key)
{
    if (!root)//该节点并不存在
        return nullptr;

    if (key < root->val)
    {
        //key在root左侧
        root->left = deleteNode(root->left, key);
        if (getHeight(root->right) - getHeight(root->left) == 2)
        {
            TreeNode* t = root->right;
            if (getHeight(t->right) > getHeight(t->left))
                root = RR(root);
            else
                root = RL(root);
        }
    }else if (key > root->val)
    {
        //key在root右侧
        root->right = deleteNode(root->right, key);
        if (getHeight(root->left) - getHeight(root->right) == 2)
        {
            TreeNode* t = root->left;
            if (getHeight(t->left) > getHeight(t->right))
                root = LL(root);
            else
                root = LR(root);
        }
    }else
    {
        //找到要删除的节点key
        if (root->left && root->right)
        {
            if (getHeight(root->left) > getHeight(root->right))//从更高的子树开始删除,可以保证删除之后AVL仍然平衡
            {
                TreeNode* t = root->left;
                while(t->right)
                    t = t->right;
                root->val = t->val;
                root->left = deleteNode(root->left, t->val);
            }else
            {
                TreeNode* t = root->right;
                while(t->left)
                    t = t->left;
                root->val = t->val;
                root->right = deleteNode(root->right, t->val);
            }
        }else
        {
            TreeNode* t = root;
            root = root->left ? root->left : root->right;
            delete t;
            return root;
        }
    }

    root->height = std::max(getHeight(root->left), getHeight(root->right)) + 1;
    return root;
}




/**************************************测试函数****************************************/
//该测试函数和 参考文章中的测试函数相同,可对应着看
void test1()
{
    AVLTree tree;
    tree.insertNode(3);
    // tree.deleteNode(3);
}

void test2()
{
    AVLTree tree("3 2 1 4 5 6 7 16 15 14 13 12 11 10 8 9");
    tree.preTraverse(tree.getRoot());
    cout << endl;
    tree.inTraverse(tree.getRoot());
    cout << endl;
    cout << "Height:" << tree.getHeight(tree.getRoot()) << endl;

}

void test3()
{
    AVLTree tree("3 2 1 4 5 6 7 16 15 14 13 12 11 10 8 9");
    tree.deleteNode(8);
    tree.preTraverse(tree.getRoot());
    cout << endl;
    tree.inTraverse(tree.getRoot());
    cout << endl;
    cout << "Height:" << tree.getHeight(tree.getRoot()) << endl;

}

int main()
{
    test3();
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值