C语言实现 二叉树 对任意类型数据的遍历、叶子节点统计、树高计算

本文主要实现C语言对二叉树的构造,可存储所有类型数据,实现数据域的遍历,本文主要介绍递归的遍历方法,含详细图文;以及树高、叶子节点的计算等。

1 二叉树构造

typedef struct Tree //二叉树
{
    void *data;         //数据域,void* 可保存任意数据类型的地址
    struct Tree *left;  //左子节点指针
    struct Tree *right; //右子节点指针
} Tree;

2 根据数据data创建树节点

Tree *createTreeNode(void *data) //根据数据域data创建节点
{
    Tree *node = (Tree *)malloc(sizeof(Tree)); //在堆区申请内存
    node->data = data;
    node->left = NULL;
    node->right = NULL;
}

3 前序遍历代码(详细分析部分见8.2图解)

typedef struct Student //后续以二叉树保存Student数据信息为例
{
    int age;
    char name[20];
} Student;

void preOrderList(Tree *root) //前序遍历,先根节点,再左(子树),再右(子树)
{
    if (root == NULL)
        return;
    Student *stu = (Student *)root->data;
    printf("{id:%d,name:%s}\t", stu->age, stu->name);
    preOrderList(root->left);
    preOrderList(root->right);
}
//8.2有详细图解分析过程

4 中序遍历

void inOrderList(Tree *root)
{
    if (root == NULL)
        return;
    inOrderList(root->left);
    Student *stu = (Student *)root->data;
    printf("{id:%d,name:%s}\t", stu->age, stu->name);
    inOrderList(root->right);
}

5 后序遍历

void postOrderList(Tree *root)
{
    if (root == NULL)
        return;
    postOrderList(root->left);
    postOrderList(root->right);
    Student *stu = (Student *)root->data;
    printf("{id:%d,name:%s}\t", stu->age, stu->name);
}

6 叶子节点数量计算

void countOfLeafNode(Tree *root, int *count) //统计二叉树的叶子节点,即没有左右子结点
{
    if (root == NULL)
        return;
    if (root->left == NULL && root->right == NULL)//叶子节点即没有后驱节点
        (*count)++;
    countOfLeafNode(root->left, count);//结合前序遍历计算叶子节点数量
    countOfLeafNode(root->right, count);
}

7 树高计算

size_t heightOfTree(Tree *root)//函数的分析过程,可结果8.2图解对前序遍历的分析
{
    if (root == NULL)
        return 0;
    int heightOfLeftTree = heightOfTree(root->left);
    int heightOfRightTree = heightOfTree(root->right);
    int heightOfTree = heightOfLeftTree > heightOfRightTree ? heightOfLeftTree + 1 : heightOfRightTree + 1;//得到左子树和右子树的高度最大值,再加一,即树高
    return heightOfTree;
}

8 函数测试与结果分析

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    Student stu[7] = {
        {1, "jakes1"},
        {2, "jakes2"},
        {3, "jakes3"},
        {4, "jakes4"},
        {5, "jakes5"},
        {6, "jakes6"},
        {7, "jakes7"},
    };
    Tree *root = (Tree *)malloc(sizeof(Tree));
    root->data = &stu[0];
    root->left = createTreeNode(&stu[1]);
    root->right = createTreeNode(&stu[2]);
    root->left->left = createTreeNode(&stu[3]);
    root->left->left->right = createTreeNode(&stu[6]);
    root->right->left = createTreeNode(&stu[4]);
    root->right->right = createTreeNode(&stu[5]);
    printf("前序遍历:");
    preOrderList(root);
    printf("\n中序遍历:");
    inOrderList(root);
    printf("\n后序遍历:");
    postOrderList(root);
    puts("");
    int count = 0;
    countOfLeafNode(root, &count);//count入参传址
    printf("叶子节点数量为:%d\n", count);
    printf("树的高度为%d\n", heightOfTree(root));
    return 0;
}

        8.1 main函数中,对树的构建如下图

         8.2 以前序遍历为例,程序的执行顺序可参考下图。preOrderList()函数入参为Tree *类型,为简单绘图,简化为stu0、stu1.....,图中有4个printf(NULL),应该是pre(NULL),图画得略微仓促,但有助于对递归排序的理解。

         8.3 中序遍历和后续遍历均可按照此方法分析,main函数的运行结果如下:

9 补充一些关于树的基本概念
   9.1 根:没有前驱
   9.2 叶子:没有后继
   9.3 双亲:直接前驱
   9.4 孩子:直接后继
   9.5 节点的度:直接后继的数量
   9.6 树的度:节点的度中取最大值
   9.7 树的高度/深度:最大层数
   9.8 二叉树:
        9.8.1 在二叉树的第i层上最多2^(i-1)个节点
        9.8.2 深度为k的二叉树至多有2^k-1个节点,若有2^k-1个节点,则成为满二叉树
                 若仅在最后一层缺少右边的若干节点,其他层节点数已达到最大,成为完全二叉树,
                 满二叉树肯定是完全二叉树
        9.8.3 若度为2的节点数有n个,则叶子数必定为n+1;(叶子是指没有后继)
        9.8.4 具有n个节点的完全二叉树的深度必为int((log2)n)+1
        9.8.5对于完全二叉树,若从左至右,从上到下,对节点编号,节点i的左子节点必为2i

                右子节点必为2i+1,父节点必为(int)i/2

点击关注不迷路

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jakerc

原创不易,您的奖励将是我最大的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值