平衡二叉树理解

http://blog.csdn.net/guoqingshuang/article/details/50190119  原文地址
 /*这个程序用记录每一个节点的高度代替了求每一个节点的平衡因子 

也就是说在严蔚敏的教材中每次插入节点后都要对节点的平衡银子进行更新
而这里只对节点的高度进行更新*/


/*你大概这样思考,
当在某个结点p的左子树q的左子树处插入时要右旋转,因为左边出现了失衡,


其实旋转就是一个换失衡根结点的问题,


那么再思考,要保持排序树的特性,如何更换根结点


有几种方案
一种是选择左子树的最右结点直接替换为根,然后把替换了的根安排到右子树的最左位置,这样可以保持排序的特性,但不一定能保证平衡
一种是把左子树根结点P做为根结点,但这时涉及到左子树根结点的右子树Pr安排问题,因为要保证左边的全部比P小,而实际上原来的Pr都比它大,这样我们就思考把他做为原根结点的左子树,把原根结点做为P的右子树,这样不仅保证了排序的特性还保证了平衡


大概的代码如下
P=R->LChild;//P为失衡结点的左子树根结点
R->LChild=P->RChild;//把P的右子树做为R的左子树
P->RChild=R;//把P替换为根结点


其它的旋转都是一样的原理,你要多动手划一划,我这时间不多,不好再给你一一画图说明,不好意思,你多多思考吧。


其实右旋就是把失衡结点的左子树根结点提升为二叉树的根结点,然后你再想想如何保持有序就行了
其实左旋就是把失衡结点的右子树根结点提升为二叉树的根结点,然后你再想想如何保持有序就行了
RL就是二者的结合,但要从最下层失衡结点开始


不能仅靠记忆,你可以先加强理解排序二叉树的插入和删除的理解,当然,这里只是换位置,其实很多东西是一样的。*/
#include<stdio.h>
#include<stdlib.h>
struct node
{
   int data;
   int d;
   struct node *lchild,*rchild;
};
int max(int x,int y)
{
    return x>y?x:y;
}
int Deep(struct node *head)
{
    if(!head)
        return -1;
    return head->d;
}
void LL(struct node *&head)
{
    struct node *q;
    q=head->lchild;
    head->lchild=q->rchild;
    q->rchild=head;
    //旋转之后更新节点的高度
    q->d=max(Deep(q->lchild),Deep(q->rchild))+1;
    head->d=max(Deep(head->lchild),Deep(head->rchild))+1;
    head=q;
}
void RR(struct node *&head)
{
    struct node *q=head->rchild;
    head->rchild=q->lchild;
    q->lchild=head;
    q->d=max(Deep(q->lchild),Deep(q->rchild))+1;
    head->d=max(Deep(head->lchild),Deep(head->rchild))+1;
    head=q;
}
void RL(struct node *&head)
{   //不平衡节点的右儿子进行旋转
    RR(head->rchild);                  //同时把这里的head->rchild换成head->lchild  和下面的(head->lchild)换成head->rchild也对
    LL(head);
}
void LR(struct node *&head)
{
    LL(head->lchild);
    RR(head);
}
void Creat(struct node *&head,int x)
{
    if(!head)
    {
        head=(struct node *)malloc(sizeof(struct node));
        head->lchild=NULL;
        head->rchild=NULL;
        head->data=x;
        head->d=0;
    }
    else if(x<head->data)
    {
        Creat(head->lchild,x);
        //因为是递归操作,所以先出现判断的应该是离插入节点最近的父亲节点,然后是父亲的父亲,直到找到平衡因子的绝对值>1的点 然后马上进行旋转,平衡因子不平衡的节点之上的节点平衡因子数不会变 因为旋转后与旋转前的深度相同
        if(Deep(head->lchild)-Deep(head->rchild)>1)   //如果大于1了,表明这个节点的插入引起了树高度的变化,这里是插入后判断左右子树的高度差
        {
            if(x<head->lchild->data)       //head应该是离插入节点最近的一个不平衡的节点
                LL(head);
            else
                LR(head);
        }
    }
    else if(x>head->data)
    {
        Creat(head->rchild,x);
        if(Deep(head->rchild)-Deep(head->lchild)>1)
        {
            if(x>head->rchild->data)
            RR(head);
            else
            RL(head);
        }
    }
    head->d=max(Deep(head->lchild),Deep(head->rchild))+1;   //插入节点后且平衡旋转后根的高度的计算,每次插入节点后都更新一遍,注意这里head并不指向一个固定节点,是一直在变化的
}
void zx(struct node *head)
{
    if(head!=NULL)
    {
    zx(head->lchild);
    printf("%d  ",head->data);
    zx(head->rchild);
    }
}
int main()
{
    int n,m;
    scanf("%d",&n);
    struct node *head=NULL;
    for(int i=0;i<n;i++)
    {
        scanf("%d",&m);
        Creat(head,m);
    }
    printf("%d\n",head->data);
    //zx(head);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值