平衡二叉树分析与实现(2011年12月22日12:35:26)

本文详细介绍了如何通过插入操作构建平衡二叉树,并针对效率进行了优化。通过实例演示了不同类型的调整策略,包括LL型、RR型、LR型和RL型,以确保树的平衡性。此外,还提供了数据输入输出的示例,展示了如何按广度优先遍历输出平衡二叉树的结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        花了一个上午的时间写的,先看了会书,在纸上划了划,感觉挺简单的,没想到实现起来还是有点难度的。路过的朋友评价评价代码质量怎么样。欢迎给出意见和批评,指出效率有待提高的地方。


        问题描述部分

      

/*
Description

根据给出的整数序列,生成平衡二叉树,按要求输出平衡二叉树。


数据输入:

第一行是一个整数N(1<=N<=20),表示测试例子数。
以后每个测试例子的第一行是一个整数,M,表示整数序列的大小;第二行是整数序列。


数据输出:

输出测试例子的平衡二叉树,每个例子的平衡二叉树按广度优先遍历,
依次输出各节点值及左右子节点值,每个节点一行,如果子节点为空,输出#,
节点值和子节点值之间用一个空格隔开。例子之间使用0分行。

Sample Input

2
5
13 24 37 90 53
6
11 24 35 80 50 17


Sample Output

24 13 53
13 # #
53 37 90
37 # #
90 # #
0
24 11 50
11 # 17
50 35 80
17 # #
35 # #
80 # #
*/

分析部分:

/**
(1)LL 型:
  新结点 X 插在 A 的左孩子的左子树里。调整方法见图
   图中以 B 为轴心,将 A 结点从 B 的右上方转到 B 的右下侧,使 A 成为 B 的右孩子。
      2      A          1     B
            /                / \
      1    B    ---->   0   X   A
          /
      0  X
(2)RR 型:
  新结点 X 插在 A 的右孩子的右子树里。调整方法见图
   图中以 B 为轴心,将 A 结点从 B 的左上方转到 B 的左下侧,使 A 成为 B 的左孩子。

   2   A
        \
   1     B       ---->       B     1
          \                 / \
   0       X               A   X   0
(3)LR 型:
  新结点 X 插在 A 的左孩子的右子树里。调整方法见图
   分为两步进行:第一步以 X 为轴心,将 B 从 X 的左上方转到 X 的左下侧,
   使 B 成为 X 的左孩子, X 成为 A 的左孩子。第二步跟 LL 型一样处理(应以 X 为轴心)。
    0     A                A
         /                /
    1   B       ----->   X     ---->         X     1
         \              /                   / \
    2     X            B                   B   A   0
(4)RL 型:
  新结点 X 插在 A 的右孩子的左子树里。调整方法见图
   分为两步进行:第一步以 X 为轴心,将 B 从 X 的右上方转到 X 的右下侧,
   使 B 成为 X 的右孩子, X 成为 A 的右孩子。第二步跟 RR 型一样处理 (应以 X 为轴心)。
    0     A            A
           \            \
    1       B ----->     X     ---->         X     1
           /              \                 / \
    2     X                B               A   B   0
*/

代码实现部分

//头文件,函数,结构声明部分

#include <stdio.h>
#include <stdlib.h>
#define MAX 1000
//#define Max(a,b) (((a) < (b)) ? (b) : (a))


typedef struct AVLNode *AVLTree;

struct AVLNode
{
    int data;
    AVLTree lChild;
    AVLTree rChild;
    int height;
};

AVLTree insert(int , AVLTree );
int height(AVLTree);
void motifyHeight(AVLTree,AVLTree);       //避免代码重复的修改高度函数
AVLTree singleRotateLeftLeft(AVLTree);   //LL
AVLTree singleRotateRightRight(AVLTree); //RR
AVLTree doubleRotateLeftRight(AVLTree);  //LR
AVLTree doubleRotateRightLeft(AVLTree);  //RL
void createQueue(AVLTree,AVLTree *,int);
void printSortedBinaryTree(AVLTree *,int);

 

//主函数

 

int main()
{
    AVLTree root = NULL;
    int cases,n,input[MAX],i; //cases个用例,每个用例结点的个数
    AVLTree queue[MAX];

    scanf("%d",&cases);
    while(cases--)
    {
        root = NULL;
        scanf("%d",&n);
        for(i=0; i<n; i++)
        {
            scanf("%d",&input[i]);
            root = insert(input[i],root);
        }
        createQueue(root,queue,n);
        printSortedBinaryTree(queue,n);
        destoryNodes(queue,n); //记得释放申请过的内存空间是一个好的编程习惯
        //最大限度的控制内存泄露问题
        if(cases != 0)
        {
            printf("0\n");
        }
    }
    system("pause");
    return 0;
}



//求结点高度

int height(AVLTree p)
{
    if (p == NULL)
        return -1;     //叶子结点的左右子树的高度为0
    else
        return p->height; //结点存在 直接返回该结点的height就行了
}


//插入结点操作

AVLTree insert(int x,AVLTree root)
{
    if(root == NULL)
    {
        root = (AVLTree)malloc(sizeof(struct AVLNode));
        root->data = x;
        root->lChild = NULL;
        root->rChild = NULL;
        root->height = 0;
    }
    else if(x < root->data)
    {
        //插入到左子树
        root->lChild = insert(x,root->lChild);
        if(height(root->lChild) - height(root->rChild) == 2)  //需要调整
        {
            //判断用哪种方式进行调整,能进入这里 x肯定是比root->data要小
            //所以要么是LL型,要么是LR型
            if(x < root->lChild->data)          //说明是LL型
            {
                root = singleRotateLeftLeft(root);
            }
            else                                //说明是LR型
            {
                root = doubleRotateLeftRight(root);
            }
        }
    }
    else if(x > root->data)
    {
        //插入到右子树
        root->rChild = insert(x,root->rChild);
        if(height(root->rChild) - height(root->lChild) == 2) //需要调整
        {
            //判断用哪种方式进行调整,能进入这里 x肯定是比root->data要大
            //所以要么是RR型,要么是RL型
            if(x > root->rChild->data)   //说明是RR型
            {
                root = singleRotateRightRight(root);
            }
            else
            {
                root = doubleRotateRightLeft(root);   //RL型
            }
        }
    }

    //当root为叶子结点或者没有左子树,或者没有右子树时 用root->lChild->data这种方式就不行
    //所以用一个函数求出高度,当没有左右子树为空时,左右子树的height为-1
    root->height = max(height(root->lChild),height(root->rChild)) + 1;

    return root;
}


//LL型

AVLTree singleRotateLeftLeft(AVLTree t)
{
    /**
          2      A          1     B
                /                / \
          1    B    ---->   0   X   A
              /
          0  X
    */
    AVLTree pTemp;
    pTemp = t->lChild;
    pTemp->rChild = t;
    t->lChild = NULL;

    //重新调整A,B的高度
    motifyHeight(t,pTemp);
    return pTemp;
}


//RR型

 

//RR型
AVLTree singleRotateRightRight(AVLTree t)
{
    /**
               2   A
                    \
               1     B       ---->       B     1
                      \                 / \
               0       X               A   X   0
    */

    AVLTree pTemp;
    pTemp = t-> rChild;
    pTemp->lChild = t;
    t->rChild = NULL;

    //重新调整高度
    motifyHeight(t,pTemp);
    return pTemp;
}


//LR型

//LR型
AVLTree doubleRotateLeftRight(AVLTree t)
{
    /**
     *        0     A                A
                   /                /
              1   B       ----->   X     ---->         X     1
                   \              /                   / \
              2     X            B                   B   A   0
     */
    AVLTree pTemp;
    t->lChild = singleRotateRightRight(t->lChild); //第一次转换
    pTemp = singleRotateLeftLeft(t);

    return pTemp;
}


//RL型

 

//RL型
AVLTree doubleRotateRightLeft(AVLTree t)
{

    /**
          0     A            A
                 \            \
          1       B ----->     X     ---->         X     1
                 /              \                 / \
          2     X                B               A   B   0
    */
    t->rChild = singleRotateLeftLeft(t->rChild);
    return singleRotateRightRight(t);
}


//用数组模拟队列,构建模拟队列

 

//用数组模拟队列
void createQueue(AVLTree root,AVLTree *queue,int n)
{
    AVLTree pTemp = root;

    int i,j;
    i = 0;
    j = 0;

    if(pTemp != NULL)
    {
        queue[i++] = pTemp;
    }

    //构造模拟queue,当满n时退出
    while(i != n)
    {
        if(pTemp->lChild != NULL)
        {
            queue[i++] = pTemp->lChild;
            if(i == n)
            {
                break;
            }
        }

        if(pTemp->rChild != NULL)
        {
            queue[i++] = pTemp->rChild;
            if(i == n)
            {
                break;
            }
        }

        pTemp = queue[++j];
    }
}


//按格式打印结果

 

//按格式打印输出
void printSortedBinaryTree(AVLTree *queue,int n)
{
    int i;
    AVLTree pTemp;

    for(i=0; i<n; i++)
    {
        pTemp = queue[i];
        printf("%d ",pTemp->data);

        if(pTemp->lChild != NULL)
        {
            printf("%d ",pTemp->lChild->data);
        }
        else
        {
            printf("# ");
        }

        if(pTemp->rChild != NULL)
        {
            printf("%d\n",pTemp->rChild->data);
        }
        else
        {
            printf("#\n");
        }
    }
}


//释放申请的内存空间

 

//释放申请的空间
void destoryNodes(AVLTree *queue,int n)
{
    int i;
    AVLTree pTemp;
    for(i=0; i<n; i++)
    {
        pTemp = queue[i];
        free(pTemp);
        queue[i] = NULL;
    }
}




 


完毕:提交结果AC.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值