设计程序,利用二叉链表结构,建立一棵二叉树。并能递归实现二叉树的先序遍历、中序遍历和后序遍历三种遍历算法,能用队列实现二叉树的层次遍历算法,并按层次输出(标出层号),并能统计树叶数,结点数,层高等信息

(一)利用二叉链表结构,通过先序遍历先建立起一棵二叉树如图1-1。根据建立这个的二叉树,并且通过递归的方式实现了二叉树的先序遍历、中序遍历和后序遍历三种遍历算法,用队列实现二叉树的层次遍历算法,并按层次输出(标出层号),并能统计树叶数,结点数,层高等信息,如图1-2。

#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 30

// 定义一个字符类型别名,用于二叉树的元素类型
typedef char ElemType;
// 定义一个指向二叉树节点的指针类型别名
typedef struct TNode *BiTree;

// 定义二叉树节点的结构体
struct TNode
{
	char data; // 节点数据
	BiTree lchild; // 指向左子树的指针
	BiTree rchild; // 指向右子树的指针
};

// 判断二叉树是否为空
// 参数T是指向二叉树根的指针的指针
int IsEmpty_BiTree(BiTree *T)
{
    // 如果T指向的指针为NULL,说明二叉树为空
	if(*T == NULL)
	return 1; // 返回1,表示二叉树为空
	else
	return 0; // 返回0,表示二叉树不为空
}

// 创建二叉树
// 参数T是指向二叉树根的指针的指针
void Create_BiTree(BiTree *T)
{
    char ch;
    // 从标准输入读取一个字符
    ch = getchar();
    //当输入的是"#"时,认为该子树为空
    if(ch == '#')
        *T = NULL;// 将T指向的指针设为NULL,表示该子树为空
    //创建树结点
    else
    {
        // 动态分配内存空间给新的节点,并将地址赋值给T指向的指针
        *T = (BiTree)malloc(sizeof(struct TNode));
        // 设置新节点的数据
        (*T)->data = ch; //生成树结点
        // 递归地生成左子树
        Create_BiTree(&(*T)->lchild);
        // 递归地生成右子树
        Create_BiTree(&(*T)->rchild);
    }
}

// 先序遍历二叉树
void TraverseBiTree(BiTree T)
{
	// 如果节点为空,则直接返回
	if(T == NULL)
		return;
	else
	{
		// 访问节点
		printf("%c ",T->data);
		// 递归遍历左子树
		TraverseBiTree(T->lchild);
		// 递归遍历右子树
		TraverseBiTree(T->rchild);
	}
}

// 中序遍历二叉树
void InOrderBiTree(BiTree T)
{
	// 如果节点为空,则直接返回
	if(NULL == T)
		return;
	else
	{
		// 递归遍历左子树
		InOrderBiTree(T->lchild);
		// 访问节点
		printf("%c ",T->data);
		// 递归遍历右子树
		InOrderBiTree(T->rchild);
	}
}

// 后序遍历二叉树
void PostOrderBiTree(BiTree T)
{
	// 如果节点为空,则直接返回
	if(NULL == T)
		return;
	else
	{
		// 递归遍历左子树
		PostOrderBiTree(T->lchild);
		// 递归遍历右子树
		PostOrderBiTree(T->rchild);
		// 访问节点
		printf("%c ",T->data);
	}
}

// 计算二叉树的深度
int TreeDeep(BiTree T)
{
	int deep = 0; // 初始化深度为0
	if(T) // 如果树不为空
	{
		int leftdeep = TreeDeep(T->lchild); // 递归计算左子树的深度
		int rightdeep = TreeDeep(T->rchild); // 递归计算右子树的深度
		deep = leftdeep > rightdeep ? leftdeep + 1 : rightdeep + 1; // 取左右子树深度的最大值,并加1(因为根节点也算一层)
	}
	return deep; // 返回树的深度
}

// 统计二叉树的叶子节点数量,并打印叶子节点的值
void Leafcount(BiTree T, int *num)
{
	if(T) // 如果树不为空
	{
		if(T->lchild == NULL && T->rchild == NULL) // 如果当前节点是叶子节点(即左右子树都为空)
		{
			num++; // 叶子节点数量加1
			printf("%c ", T->data); // 打印叶子节点的值
		}
		Leafcount(T->lchild, num); // 递归遍历左子树
		Leafcount(T->rchild, num); // 递归遍历右子树
	}
}

// 二叉树的层序遍历(广度优先遍历)
void LevelOrder_BiTree(BiTree T)
{
    // 用一个队列保存结点信息,这里的队列采用的是顺序队列中的数组实现
    int front = 0; // 队列的前端指针
    int rear = 0;  // 队列的后端指针
    BiTree BiQueue[MAXSIZE]; // 假设MAXSIZE是队列的最大容量,这里是一个数组,用于模拟队列
    BiTree tempNode; // 临时节点,用于从队列中取出节点

    if(T != NULL) // 如果树不为空
    {
        BiQueue[rear++] = T; // 将根节点入队

        while(front != rear) // 当队列不为空时
        {
            // 取出队头元素,并使队头指针向后移动一位
            tempNode = BiQueue[front++];
            // 打印当前节点的值
            printf("%c ", tempNode->data);

            // 判断左子树是否为空,若不为空,则加入队列
            if(tempNode->lchild != NULL)
                BiQueue[rear++] = tempNode->lchild;

            // 判断右子树是否为空,若不为空,则加入队列
            if(tempNode->rchild != NULL)
                BiQueue[rear++] = tempNode->rchild;
        }
    }
}

int main(void)
{
	// 声明一个指向二叉树结构体的指针T,但这里T并没有直接分配内存
	BiTree T;

	int deepth, num = 0; // 声明树的深度和叶子节点数量的变量

	// 调用Create_BiTree函数,通过引用传递T的地址,创建二叉树,并将根节点地址赋值给T
	Create_BiTree(&T);

	// 输出先序遍历结果
	printf("先序遍历二叉树:\n");
	TraverseBiTree(T);
	printf("\n");

	// 输出中序遍历结果
	printf("中序遍历二叉树:\n");
	InOrderBiTree(T);
	printf("\n");

	// 输出后序遍历结果
	printf("后序遍历二叉树:\n");
	PostOrderBiTree(T);
	printf("\n");

	// 层次遍历二叉树,即广度优先遍历
	printf("层次遍历结果:");
	LevelOrder_BiTree(T);
	printf("\n");

	// 计算树的深度
	deepth = TreeDeep(T);
	printf("树的深度为:%d", deepth);
	printf("\n");

	// 计算并输出树的叶子节点
	printf("树的叶子结点为:");
	Leafcount(T,&num);

	printf("\n树的叶子结点个数为:%d", num);

	return 0;
}
图1-1 二叉树
图1-2 二叉树结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值