AVL树的C++实现 Implement of AVL tree

AVL是一种自平衡的二叉查找树。

不同于普通的二叉查找树之处在于:每个节点的左右子树高度差最多为1,故每个节点多了一个高度(height)属性。

其实现难点在于插入和删除时要检测节点高度差是否满足上述条件,当超过1时,分四种情况进行调节。

case1:左儿子的左子树插入值 left-left

case2:左儿子的右子树插入值 left-right

case3:右儿子的左子树插入值 right-left

case4:右儿子的右子树插入值 right-right

以上四种情况中,虽然删除操作不是“插入值”,但是删除后导致的结果可以转换成插入来看待处理。

为了简便说明原理,此处仅对删除操作的一种类型作图说明。

以下,删除的值在左侧时,即remove函数中treeNode->val > data的情况。

 

 

#include <queue>
#include <iostream>
using namespace std;
struct AVLTreeNode
{
    int val;
    int height;
    AVLTreeNode *left;
    AVLTreeNode *right;
};

int GetHeight(AVLTreeNode *treeNode)
{
    //must update this height when insert or move a node
    return treeNode == NULL ? -1 : treeNode->height;

    //if use the code below,there is no need to use member "height"
    //and there is no need to update height anymore
    //but it may cost much time as it uses recursion to get the height every time
    /*if(treeNode == NULL)
    return -1;
    return 1 + max(GetHeight(treeNode->left), GetHeight(treeNode->right));*/
}

//case 1,add "1" to 3,2(left-left)
/*
    3         2
    2    ->   1   3
1
*/
void RotateWithLeftChild(AVLTreeNode *&treeNode)
{
    AVLTreeNode *p = treeNode->left;
    treeNode->left = p->right;
    p->right = treeNode;
    treeNode->height = max(GetHeight(treeNode->left), GetHeight(treeNode->right)) + 1;
    p->height =  max(GetHeight(p->left), treeNode->height) + 1;
    treeNode = p;
}

//case 4,add "3" to 1,2(right-right)
/*
1       2
    2    ->   1   3
    3
*/
void RotateWithRightChild(AVLTreeNode *&treeNode)
{
    AVLTreeNode *p = treeNode->right;
    treeNode->right = p->left;
    p->left = treeNode;
    treeNode->height = max(GetHeight(treeNode->left), GetHeight(treeNode->right)) + 1;
    p->height = max(GetHeight(p->right), treeNode->height) + 1;
    treeNode = p;
}

//case 2,add "2" to 3,1(left-right)
/*
    3       3      2
    1    ->   2   ->  1 3
    2     1
*/
void DoubleWithLeftChild(AVLTreeNode *&treeNode)
{
    RotateWithRightChild(treeNode->left);
    RotateWithLeftChild(treeNode);
}

//case 3,add "2" to 1,3(right-left)
/*
1       1          2
    3    ->   2   ->  1 3
2       3
*/
void DoubleWithRightChild(AVLTreeNode *&treeNode)
{
    RotateWithLeftChild(treeNode->right);
    RotateWithRightChild(treeNode);
}

AVLTreeNode *FindMin(AVLTreeNode *treeNode)
{
    if(treeNode == NULL)
    return NULL;
    else if(treeNode->left == NULL)
    return treeNode;
    else
    return FindMin(treeNode->left);
}

AVLTreeNode *FindMax(AVLTreeNode *treeNode)
{
    if (treeNode == NULL)
    return NULL;
    else if (treeNode->right == NULL)
    return treeNode;
    else
    return FindMax(treeNode->right);
}

void Insert(AVLTreeNode *&treeNode, int data)
{
    if(treeNode == NULL){
        treeNode = new AVLTreeNode;
        treeNode->left = NULL;
        treeNode->right = NULL;
        treeNode->val = data;
    }

    else if (treeNode->val > data) {//go to left subtree
        Insert(treeNode->left,data);
        if (GetHeight(treeNode->left) - GetHeight(treeNode->right) == 2){
            if(data < treeNode->left->val) //left-left
                RotateWithLeftChild(treeNode);
            else              //left-right
                DoubleWithLeftChild(treeNode);
        }
    } else if (treeNode->val < data){ //go to right subtree
        Insert(treeNode->right,data);
        if(GetHeight(treeNode->right) - GetHeight(treeNode->left) == 2){
            if (data > treeNode->right->val)
                RotateWithRightChild(treeNode);
            else
                DoubleWithRightChild(treeNode);
            }
    } else ;//duplicate, do nothing

    //it's impossible that treeNode is NULL here
    //so update it's height is safe
    treeNode->height = max(GetHeight(treeNode->left),GetHeight(treeNode->right)) + 1;
}

void Remove(AVLTreeNode *&treeNode, int data)
{
    if(treeNode == NULL)//not found
    return;
    if (treeNode->val > data) //go to left subtree
    {
        Remove(treeNode->left,data);
        if (GetHeight(treeNode->right) - GetHeight(treeNode->left) == 2)
        {
            if(treeNode->right->right != NULL)
                RotateWithRightChild(treeNode);
            else
                DoubleWithRightChild(treeNode);
        }
    }
    else if (treeNode->val < data) //go to right subtree
    {
        Remove(treeNode->right,data);
        if (GetHeight(treeNode->left) - GetHeight(treeNode->right) == 2)
        {
            if (treeNode->left->left != NULL)
                RotateWithLeftChild(treeNode);
            else 
                DoubleWithLeftChild(treeNode);
        }
    }
    else if(treeNode->left != NULL && treeNode->right != NULL)//found,has two children
    {
        treeNode->val = FindMin(treeNode->right)->val;
        Remove(treeNode->right,treeNode->val);//not "data"!!
        if (GetHeight(treeNode->left) - GetHeight(treeNode->right) == 2)
        {
            if(treeNode->left->left != NULL)
                RotateWithLeftChild(treeNode);
            else
                DoubleWithLeftChild(treeNode);
            }
    }
    else // found,has one or no child
    {
        AVLTreeNode *tmp = treeNode;
        treeNode = (treeNode->left != NULL) ? treeNode->left : treeNode->right;
        delete tmp;
        tmp = NULL;
    }
    
    //if treeNode is NULL,treeNode->height will cause error
    //so if treeNode is a leaf, there is no need to update its height
    if(treeNode != NULL)
    treeNode->height = max(GetHeight(treeNode->left), GetHeight(treeNode->right)) + 1;
}

void LevelOrderTraverse(AVLTreeNode *root)
{
    if(root == NULL) return;
    queue<AVLTreeNode*> Q;
    Q.push(root);
    while(!Q.empty())
    {
        AVLTreeNode *p = Q.front();
        if (p->left != NULL)
        Q.push(p->left);
        if (p->right != NULL)
        Q.push(p->right);
        cout << p->val <<"("<<p->height<<") ";
        Q.pop();
    }
    cout << "\n";
}

void PreOrderTraverse(AVLTreeNode *treeNode)
{
    if (treeNode != NULL)
    {
        cout << treeNode->val <<"("<<treeNode->height<<") ";
        PreOrderTraverse(treeNode->left);
        PreOrderTraverse(treeNode->right);
    }
}

void InOrderTraverse(AVLTreeNode *treeNode)
{
    if (treeNode != NULL)
    {
        InOrderTraverse(treeNode->left);
        cout << treeNode->val <<"("<<treeNode->height<<") ";
        InOrderTraverse(treeNode->right);
    }
}

void PostOrderTraverse(AVLTreeNode *treeNode)
{
    if (treeNode != NULL)
    {
        PostOrderTraverse(treeNode->left);
        PostOrderTraverse(treeNode->right);
        cout << treeNode->val <<"("<<treeNode->height<<") ";
    }
}

void MakeEmpty(AVLTreeNode *&treeNode)
{
    if (treeNode != NULL)
    {
        MakeEmpty(treeNode->left);
        MakeEmpty(treeNode->right);
        delete treeNode;
    }
    treeNode = NULL;
}

void BuildAVLTree(AVLTreeNode *&root,int a[], int n)
{
    for (int i = 0; i < n; i++)
    {
        Insert(root,a[i]);
    }
}

int main(void)
{
    int a[] = {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};//test insert
    int b[] = {2,1,3,4};//test remove

    AVLTreeNode *root = NULL;
    //BuildAVLTree(root,a,sizeof(a)/sizeof(a[0]));
    BuildAVLTree(root,b,sizeof(b)/sizeof(b[0]));
    LevelOrderTraverse(root);
    
    Remove(root,4);
    PreOrderTraverse(root);
    cout << "\n";
    InOrderTraverse(root);
    cout << "\n";
    MakeEmpty(root);
    return 0;
}

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值