二叉树及平衡二叉树 纯C语言实现

二叉树及平衡二叉树 纯C语言实现

作者:cuicui
实现了二叉树节点的增加、查询、删除还有将二叉树变成平衡二叉树。

定义速览

  1. 深度(层数)、层、叶子、孩子、兄弟、堂兄弟。
  2. 二叉树:两个子节点,且区分左右节点。
  3. 满二叉树。
  4. 完全二叉树:最后两层可以出现子节点不为2的节点,如果只有一个子节点,必须为左节点。
  5. 平衡二叉树:对于所有节点,左树右树的节点数差一。
  6. 存储方式:顺序(数组)、链式。
  7. 遍历:按行、先序(根左右)、中序(左根右)、后序(左右根)。
  8. 特别的:已知先中或中后两种遍历方式可以重建整个树,先后不行。

代码中的函数定义

insert()//插入节点,默认的树生成方式是,大的数放右边,比根节点小的数放左边,依次比较。
paint()、show()//把树显示出来,为方便显示,这棵树是向左放倒的。
delete()//删除节点,删除一个节点后把它的右子树放上来,如果节点冲突,则把原节点的左子树放到新节点的最左边。
balance()//把普通二叉树变成平衡二叉树。
turnleft()//平衡时用到,把右节点放上来,原节点变为左节点。
turnright()//平衡时用到,把左节点放上来,原节点变成右节点。

源代码

用学生的ID排列做个例子 不想看代码的话就看看运行结果就行啦

#include "stdio.h"
#include "stdlib.h"

#define NAMESIZE 32

struct stu_st
{
    int id;
    char name[NAMESIZE];
    int score;
};

struct node_st
{
    struct stu_st stu;
    struct node_st *l;
    struct node_st *r;
};

struct node_st *tree = NULL;//全局变量

void printf_stu(struct stu_st *st)
{
    printf("id:%d,name:%s,score:%d", st->id, st->name, st->score);
}

//插入
int insert(struct node_st **root, struct stu_st *data)
{

    struct node_st *node;
    //这一判断比较关键,根节点和叶子节点都走这里,没有就申请内存
    if (*root == NULL)
    {
        node = malloc(sizeof(*node));
        if (node == NULL)
            return -1;
        node->stu = *data;
        node->l = NULL;
        node->r = NULL;
        *root = node;
        return 0;
    }

    if ((*root)->stu.id >= (*data).id)
        insert(&((*root)->l), data);
    else
    {
        insert(&((*root)->r), data);
    }
}

//查找学生
struct stu_st *find(struct node_st *node, int id)
{
    if (node == NULL)
    {
        return NULL;
    }

    if ((*node).stu.id == id)
    {
        return &(node->stu);
    }

    if ((*node).stu.id < id)
    {
        return find(node->r, id);
    }
    else
    {
        return find(node->l, id);
    }
}

//画右子树 画自己 画左子树
void paint(struct node_st *root, int level)
{
    if (root == NULL)
        return;

    paint(root->r, level + 1);

    int i = 0;
    for (i = 0; i < level; i++)
    {
        printf("    ");
    }
    printf("%d\n", root->stu.id);

    paint(root->l, level + 1);
}
//显示树
void show(struct node_st *root)
{
     printf("===================================\n");
    paint(root, 0);
}
//获得节点总数
int get_node_sum(struct node_st *node)
{
    if (node == NULL)
        return 0;
    else
        return (get_node_sum(node->l) + 1 + get_node_sum(node->r));
}

//获得最左节点
struct node_st *get_min(struct node_st *root)
{
    if (root->l == NULL)
        return root;
    return get_min(root->l);
}

//获得最右节点
struct node_st *get_max(struct node_st *root)
{
    if (root->r == NULL)
        return root;
    return get_max(root->r);
}

//平衡树时,树向左转
void turnleft(struct node_st **root)
{
    struct node_st *node = *root;
    *root = node->r;
    node->r = NULL;
    get_min(*root)->l = node;
    show(tree);
}

//平衡树时,树向右转
void turnright(struct node_st **root)
{
    struct node_st *node = *root;
    *root = node->l;
    node->l = NULL;
    get_max(*root)->r = node;
    show(tree);
}

//把普通二叉树变成平衡二叉树
void balance(struct node_st **node)
{
    int sub;
    
    if (*node == NULL)
        return;
    while (1)
    {
        sub = get_node_sum((*node)->r) - get_node_sum((*node)->l);
        if(sub>=-1 && sub<=1)
            break;
        if (sub > 1)
            turnleft(node);
        else if (sub < -1)
        {
            turnright(node);
        }
    }
    balance(&(*node)->l);
    balance(&(*node)->r);
}

//删除一个节点把它的右子树放上来
void delete(struct node_st **root, int id)
{
    struct node_st **node = root;
    struct node_st *cur = NULL;
    
    while (*node !=NULL && (*node)->stu.id != id)
    {
        if(id < (*node)->stu.id)
            node = &(*node)->l;
        else
        {
            node = &(*node)->r;
        }
        
    }
    
    if(*node == NULL)
        return ;
    
    cur = *node;
    
    if(cur->r == NULL)
        *node = cur->l;
    else
    {
        *node = cur->r;
        get_min(*node)->l  = cur->l;
    }
    free(cur);

}



int main()
{
    int i;
    struct stu_st temp, *stu_p;

    int arr[] = {1, 2, 3, 9, 8, 4, 5};
    for (i = 0; i < sizeof(arr) / sizeof(*arr); i++)
    {
        temp.id = arr[i];
        snprintf(temp.name, NAMESIZE, "stu%d", arr[i]);
        temp.score = rand() % 100;
        insert(&tree, &temp);
    }

    show(tree);//把生成的树显示一下
    balance(&tree);
    //show(tree);
    int deleteID = 4;
    delete(&tree,deleteID);
    show(tree);

    return 0;
}


运行结果

树是向左倒的哦

==================================生成好的树
            9
                8
                        5
                    4
        3
    2
1
===================================树向左转
        9
            8
                    5
                4
    3
2
    1
===================================树向左转
    9
        8
                5
            4
3
    2
        1
===================================树向左转
9
    8
            5
        4
            3
                2
                    1
===================================树向右转后
    9
8
        5
    4
        3
            2
                1
===================================树向右转
            9
        8
    5
4
    3
        2
            1
===================================子树向右转
            9
        8
    5
4
        3
    2
        1
===================================子树向左转,大功告成
        9
    8
        5
4
        3
    2
        1
===================================删掉一个节点,把右子树放上来
    9
8
    5
            3
        2
            1

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值