二叉平衡搜索树

文章介绍了二叉平衡搜索树中的AVL树,用于解决二叉搜索树退化为链表导致效率下降的问题。通过定义平衡因子和调整操作(如LL型、RR型、LR型、RL型旋转),确保树的高度差不超过2,从而保持高效搜索。文中提供了插入和删除节点时进行平衡调整的C语言代码实现。
摘要由CSDN通过智能技术生成

二叉平衡搜索树

相关概念

引入原因

在使用二叉搜索树的时候,有时该树会退化为链表,这样就会使遍历二叉树的时间复杂度退化到O(n),使的搜索树的效率降低。因此为了保障树的效率,我们要设法使其一直保持在平衡的最优状态。

平衡的概念

一个根节点的左右子树高度相差不超过2,在此基础上需要一个用来判断的平衡因子。因此我们需要记录在每个节点处树的高度。通过比较他左右子树的高度来判断在该节点处是否需要进行调整

调整操作

LL型

根节点的下一个节点无右子树

在这里插入图片描述

根节点的下一个节点有右子树

在这里插入图片描述

AVLTree* llRotation(AVLTree *T)//得到根节点
{
    AVLTree *temp=T->left;//得到中间节点
    T->left=temp->right;//假如中间节点有右孩子,就让中间节点的右孩子成为根节点的左孩子,若中间节点没右孩子就令其指向空
    temp->right=T;//让根节点作为中间节点的右节点
    temp->hight=MAX(GET_HEIGHT(temp->left),GET_HEIGHT(temp->right))+1;//分别得到调整之后中间节与根的树高
    T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
    return temp;//调整后中间节点变为根节点
}
RR型

与LL型恰好相反

AVLTree* rrRotation(AVLTree *T)//得到根节点以及指向根节点的指针
{
    AVLTree *temp=T->right;//得到中间节点
    T->right=temp->left;//假如中间节点有左孩子,就让中间节点的左孩子成为根节点的右孩子,若中间节点没孩子就令其指向空
    temp->left=T;//让根节点作为中间节点的左节点
    temp->hight=MAX(GET_HEIGHT(temp->left),GET_HEIGHT(temp->right))+1;//分别得到调整之后中间节与根的树高
    T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
    return temp;//调整后中间节点变为根节点
}
LR型

在这里插入图片描述

LR型相当于先对中间节点的子树进行RR型调整再对调整完后根节点的子树进行LL型调整

RL型

与LR型相反,先对中间节点的子树进行LL型调整再对调整完后根节点的子树进行RR型调整

整体调整代码
AVLTree* fixed(AVLTree *T,int data)
{
    if(GET_HEIGHT(T->left)-GET_HEIGHT(T->right)==2){
        if(T->left->data > data){
            T=llRotation(T);
        }else{
            T->left=rrRotation(T->left);
            T=llRotation(T);
            }
    }else if(GET_HEIGHT(T->right)-GET_HEIGHT(T->left)==2){
            if(T->right->data < data){
              T=rrRotation(T);
            }else{
                T->right=llRotation(T->right);
                T=rrRotation(T);
            }
    }
    return T;
}

完整代码实现

整体的思路

在插入与删除中,均为先对带处理的节点进行插入或删除,再通过回溯的方式找到导致树不平衡的根节点,从小到大将树修正

#include <stdio.h>
#include <stdlib.h>
#define MAX(a, b)   (a > b ? a : b)//比较得出左右两颗子树中更高的一颗子树
#define GET_HEIGHT(T)   (T ? T->hight:0)//得到树的高度
typedef struct TreeNode
{
    int data,hight;
    struct TreeNode * left;
    struct TreeNode * right;
}AVLTree;
AVLTree * getnewnode(int data)//初始化树的节点
{
    AVLTree *T = NULL;
    T = (AVLTree *)malloc(sizeof(AVLTree *));
    T->data = data;
    T->hight=0;
    T->right = NULL;
    T->left = NULL;
    return T;
}
AVLTree* rrRotation(AVLTree *T)//得到根节点以及指向根节点的指针
{
    AVLTree *temp=T->right;//得到中间节点
    T->right=temp->left;//假如中间节点有左孩子,就让中间节点的左孩子成为根节点的右孩子
    temp->left=T;//让根节点作为中间节点的左节点
    temp->hight=MAX(GET_HEIGHT(temp->left),GET_HEIGHT(temp->right))+1;//分别得到调整之后中间节与根的树高
    T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
    return temp;//调整后中间节点变为根节点
}
AVLTree* llRotation(AVLTree *T)
{
    AVLTree *temp=T->left;
    T->left=temp->right;
    temp->right=T;
    temp->hight=MAX(GET_HEIGHT(temp->left),GET_HEIGHT(temp->right))+1;
    T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
    return temp;
}
AVLTree* fixed(AVLTree *T,int data)
{
    if(GET_HEIGHT(T->left)-GET_HEIGHT(T->right)==2){//若左树比右树高大于2
        if(T->left->data > data){//如果中间节点的值大于导致不平衡节点的值,则为ll调整
            T=llRotation(T);
        }else{//否则为lr调整
            T->left=rrRotation(T->left);
            T=llRotation(T);
            }
    }else if(GET_HEIGHT(T->right)-GET_HEIGHT(T->left)==2){//若右树比左树的高大于2
            if(T->right->data < data){//如果中间节点的值小于导致不平衡节点的值,则为rr调整
              T=rrRotation(T);
            }else{//否则为rl调整
                T->right=llRotation(T->right);
                T=rrRotation(T);
            }
    }
    return T;
}
AVLTree* insertTree(AVLTree *T, int data)
{
    if (T == NULL){
        T=getnewnode(data);
        printf("%d插入树中\n",data);
        T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;//更新当前节点的树高
        return T;
    }
    if (T->data > data){
        T->left = insertTree(T->left, data);
        T=fixed(T,data);
    }else{
        if(T->data < data){
            T->right = insertTree(T->right, data);
            T=fixed(T,data);
        }else{
            printf("%d已在树中,不能再次插入!!!\n",data);
        }
    }
    T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;//更新当前节点的树高
    return T;
}
//删除节点
AVLTree* findMax2(AVLTree* T)
{
    AVLTree* p=T;
    while(p->right!=NULL){
        p=p->right;
    }
    return p;
}
AVLTree*  Delete(AVLTree * T,int data)
{
    if(T==NULL) return T;
    else if(data<T->data) T->left = Delete(T->left,data);
	else if(data>T->data) T->right = Delete(T->right,data);
    else{
        if(T->left==NULL&&T->right==NULL){
            free(T);
            T=NULL;
        }
        else if(T->right==NULL){
                AVLTree *temp=T;
                T=T->left;
                free(temp);
        }
        else if(T->left==NULL){
                AVLTree *temp=T;
                T=T->right;
                free(temp);
        }
        else{
            AVLTree *temp=findMax2(T->left);
            T->data=temp->data;
            T->left=Delete(T->left,temp->data);
        }
    }
    if(T){
        T=fixed(T,data);
        T->hight=MAX(GET_HEIGHT(T->left),GET_HEIGHT(T->right))+1;
    }
    return T;
}
void Preorder(AVLTree * T)//前序遍历打印验证结果
{
    if(T==NULL){
        return;
    }
    printf("%d ",T->data);
    Preorder(T->left);
    Preorder(T->right);
}
int main()
{
    int i;
    int a[9]={1,2,3,4,5,6,7,8,9};
    AVLTree *T=NULL;
    for(i=0;i<9;i++){
        T=insertTree(T,a[i]);
    }
    Preorder(T);
    Delete(T,5);
    printf("\n");
    Preorder(T);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值