AVL树:图解左右旋单双旋(内附代码)

前言

上一篇博客讲完了二叉搜索树,二叉搜索树在分配单元上有一些挺好的做法,非极端情况下查找的时间复杂度为 O ( l o g n ) O(logn) O(logn),但是请看下面这种情况,如果我们要查找数字6,时间复杂度会退化为 O ( n ) O(n) O(n),跟普通链表没什么差别了。所以我们需要一种方式来平衡一下这棵树,使得我们可以一直保持着比较快的搜索时间。

在这里插入图片描述
在这里插入图片描述

重要概念

那么我们应该在什么时候平衡呢?在每一次插入新节点时进行平衡,平衡的操作包括左单旋,右单旋,左双旋,右双旋。听起来十分复杂,但其实并没有,我们可以通过画图使得这个步骤变简单。

思考逻辑

我初学的时候直接理解的代码,非常难受,后来老师上课的时候手绘了一次旋转的全过程,于是我印象深刻。我理解了以下两个图的变换从而写的代码

单旋转

k 1 k_1 k1降级为 k 2 k_2 k2的孩子,然后把 k 2 k_2 k2的Y树分配给 k 1 k_1 k1实现平衡,这里要注意XYZ代表子树,这些子树可以是空的,只要满足了 k 1 k_1 k1的左右子树的高度相差为2,不影响这个转换的过程。
在这里插入图片描述

BSTree* RtSgRotation(BSTree* root)	//右单旋(right single rotation)
{
    BSTree* temp;
    temp = root->lchild;
    root->lchild = temp->rchild;
    temp->rchild = root;
    root->height = getMax(getHeight(root->lchild), getHeight(root->rchild))+1;
    temp->height = getMax(getHeight(temp->lchild), root->height)+1;
    return temp;
}

BSTree* LtSgRotation(BSTree* root)	//左单旋(left single rotation)
{
    BSTree* temp;
    temp = root->rchild;
    root->rchild = temp->lchild;
    temp->lchild = root;
    root->height = getMax(getHeight(root->lchild), getHeight(root->rchild))+1;
    temp->height = getMax(getHeight(temp->rchild), root->height)+1;
    return temp;
}

双旋转

双旋转可以理解为两次单旋转的结合, x x x拆开看是精髓所在,其他同上的单旋转!图如下:
在这里插入图片描述

BSTree* RtDbRotation(BSTree* root)	//右双旋(right double rotation)= 左单旋+右单旋
{
    root->lchild = LtSgRotation(root->lchild);
    return RtSgRotation(root);
}

BSTree* LtDbRotation(BSTree* root)	//左双旋(left double rotation)= 右单旋+左单旋
{
    root->rchild = RtSgRotation(root->rchild);
    return LtSgRotation(root);
}

全部代码

#include <stdio.h>
#include <stdlib.h>

typedef struct BST
{
    int data;
    int height;
    struct BST* lchild;
    struct BST* rchild;
}BSTree;

BSTree* CreateBSTNode(int x)
{
    BSTree* newNode = (BSTree*)malloc(sizeof(BSTree));
    newNode->data = x;
    newNode->height = 0;
    newNode->lchild = NULL;
    newNode->rchild = NULL;
    return newNode;
}

int getHeight(BSTree* root)	//求一个节点的高
{
    if(!root)
    {
        return -1;
    }
    else
    {
        return root->height;
    }
}

int getMax(int a, int b)
{
    if(a > b)
        return a;
    return b;
}

BSTree* RtSgRotation(BSTree* root)	//右单旋(right single rotation)
{
    BSTree* temp;
    temp = root->lchild;
    root->lchild = temp->rchild;
    temp->rchild = root;
    root->height = getMax(getHeight(root->lchild), getHeight(root->rchild))+1;
    temp->height = getMax(getHeight(temp->lchild), root->height)+1;
    return temp;
}

BSTree* LtSgRotation(BSTree* root)	//左单旋(left single rotation)
{
    BSTree* temp;
    temp = root->rchild;
    root->rchild = temp->lchild;
    temp->lchild = root;
    root->height = getMax(getHeight(root->lchild), getHeight(root->rchild))+1;
    temp->height = getMax(getHeight(temp->rchild), root->height)+1;
    return temp;
}

BSTree* RtDbRotation(BSTree* root)	//右双旋(right double rotation)= 左单旋+右单旋
{
    root->lchild = LtSgRotation(root->lchild);
    return RtSgRotation(root);
}

BSTree* LtDbRotation(BSTree* root)	//左双旋(left double rotation)= 右单旋+左单旋
{
    root->rchild = RtSgRotation(root->rchild);
    return LtSgRotation(root);
}

BSTree* CreateBSTree(BSTree* root, int x)
{
    if(!root)
    {
        root = CreateBSTNode(x);
        return root;
    }
    else if(x < root->data)	// 插入的时候,x会被插入在左子树
    {
        root->lchild = CreateBSTree(root->lchild, x);
        if(getHeight(root->lchild) - getHeight(root->rchild) == 2)	//如果左右孩子的高相差2,就需要右旋转来解决了
        {
            if(x < root->lchild->data)	
                root = RtSgRotation(root);	// 如果x比左孩子的数据小,说明被插入到了左孩子的左孩子,那么就是右单旋
            else
                root = RtDbRotation(root);	// 如果x比左孩子的数据大,说明被插入到了左孩子的右孩子,那么就是右双旋
        }
    }
    else if(x > root->data)	// 插入的时候,x会被插入在右子树
    {
        root->rchild = CreateBSTree(root->rchild, x);
        if(getHeight(root->rchild) - getHeight(root->lchild) == 2)	//如果右左孩子的高相差2,就需要左旋转来解决了
        {
            if(x > root->rchild->data)
                root = LtSgRotation(root);	// 如果x比右孩子的数据大,说明被插入到了右孩子的右孩子,那么就是左单旋
            else
                root = LtDbRotation(root);	// 如果x比右孩子的数据小,说明被插入到了右孩子的左孩子,那么就是左双旋
        }
    }
    root->height = getMax(getHeight(root->lchild), getHeight(root->rchild))+1;
    return root;
}

void preOrder(BSTree* root)
{
    if(root)
    {
        printf("%d ", root->data);
        preOrder(root->lchild);
        preOrder(root->rchild);
    }
}

void midOrder(BSTree* root)
{
    if(root)
    {
        midOrder(root->lchild);
        printf("%d ", root->data);
        midOrder(root->rchild);
    }
}

void postOrder(BSTree* root)
{
    if(root)
    {
        postOrder(root->lchild);
        postOrder(root->rchild);
        printf("%d ", root->data);
    }
}
BSTree* find(BSTree* root, int x)
{
    if(!root)
        return NULL;
    if(x < root->data)
        return find(root->lchild, x);
    else if(x > root->data)
        return find(root->rchild, x);
    else
        return root;
}
/*
BSTree* find(BSTree* root, int x)
{
    BSTree* curNode = root;
    //BSTree* curParNode;
    int flag = 0;
    while(curNode->data != x && !curNode)
    {
        //curParNode = curNode;
        if(x < curNode->data)
            curNode = curNode->lchild;
        else if(x > curNode->data)
            curNode = curNode->rchild;
        else
            flag = 1;
    }
    if(flag == 1)
        return curNode;
    else
        return NULL;
}
*/
BSTree* findleftmax(BSTree* root)
{
    if(root->rchild)
        return findleftmax(root->rchild);
    return root;
}

BSTree* DeleteBSTNode(BSTree* root, int x)
{
    /*三种情况:
    **1. 没有子结点
    **2.一个子结点
    **3.两个子结点
    **特殊考虑删的是根结点
    */
    BSTree* temp;
    if(!root)
        return NULL;
    else if(x < root->data)
        root->lchild = DeleteBSTNode(root->lchild, x);
    else if(x > root->data)
        root->rchild = DeleteBSTNode(root->rchild, x);
    else
    {
        if(root->lchild && root->rchild)
        {
            temp = findleftmax(root->lchild);
            root->data = temp->data;
            root->lchild = DeleteBSTNode(root->lchild, root->data);
        }
        else
        {
            temp = root;
            if(root->lchild)
            {
                root = root->lchild;
            }
            else if(root->rchild)
            {
                root = root->rchild;
            }
            else
            {
                root = NULL;
            }
            free(temp);
            temp = NULL;
        }
    }
    return root;
}

int main()
{
    BSTree* root = NULL;    //NULL should always be initialized to the root!!!
    int x;
    int flag = 1;
    while(flag)
    {
        printf("Enter the data of BST node: ");
        scanf("%d", &x);
        getchar();
        root = CreateBSTree(root, x);
        printf("Enter 0 to stop: ");
        scanf("%d", &flag);
        getchar();
    }
    preOrder(root);
    printf("\n");
    printf("Please enter the value to delete: ");
    scanf("%d", &x);
    DeleteBSTNode(root, x);
    preOrder(root);
    return 0;
}

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值