【递归在二叉树中的应用:前中后序遍历,求树结点个数,叶子结点个数,第K层结点的个数】

本文详细介绍了如何在C语言中构建二叉树,包括节点结构定义、节点创建函数BuyNode,以及主函数中对二叉树的构造和各种遍历方法(前序、中序、后序)。还涉及了计算结点总数、叶子结点数、第K层结点数,以及二叉树的销毁和查找功能。
摘要由CSDN通过智能技术生成

一、构建二叉树

//构造一个二叉树的结点
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	int val;
}BTNode;


BTNode* BuyNode(int val)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		printf("malloc fail");
		exit(-1);
	}
	newnode->left = NULL;
	newnode->right = NULL;
	newnode->val = val;
	return newnode;
}

这里使用结构体来表示二叉树的一个结点,结点的参数包括左右指针和值。然后构造了一个BuyNode函数,用来为申请的二叉树结点开辟空间。

二、主函数的实现

int main()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);
	BTNode* node7 = BuyNode(7);


	node1->left = node2;
	node1->right = node3;
	node2->left = node4;
	node2->right = node5;
	node4->left = node6;
	node3->left = node7;


	//前序遍历
	PrevOrder(node1);
	printf("\n");


	//中序遍历
	InOrder(node1);
	printf("\n");


	//后序遍历
	PostOrder(node1);
	printf("\n");


	//求树结点的个数
	printf("该树结点的个数为:%d\n", TreeSize(node1));


	//求叶子结点个数
	printf("该树的叶子结点个数为:%d\n", TreeLeafSize(node1));


	//树的第k层结点的个数
	printf("该树第K层的结点个数为:%d\n", TreeKLevel(node1, 3));


	// 二叉树查找值为x的节点:前序遍历
	BTNode* ret = BinaryTreeFind(node1, 2);
	if (ret != NULL)
	{
		printf("查找到的位置的数值为%d\n", ret->val);
	}

	BinaryTreeDestory(&node1);
	return 0;
}

主函数部分,申请了7个二叉树的结点,并手动将它们连接起来。然后调用前中后序函数进行遍历打印,其中还有,求树的结点,求叶子结点,求第K层结点,树的销毁等函数。

三、树的遍历:前中后序遍历

1.前序遍历在这里插入图片描述

我们知道,前序遍历的顺序是根左右,它会先走根,再走左树,再走右树。对于左树来说,也有它的根左树右树。依次向下,知道遇到null返回。因为对于每一个结点来说,都是根左右的遍历方式,所以我们只需要写一次遍历,然后递归即可。递归的终止值是什么呢?刚才说到,递归只有遇到null才会返回,所以终止条件就是root==null.

//前序遍历
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->val);
	PrevOrder(root->left);
	PrevOrder(root->right);
}

2.前序遍历的递归展开图(只画了左子树的,右子树同理)

在这里插入图片描述

前中后序遍历都是一样的逻辑,递归展开图就不再画了。

2.中序遍历

//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	PrevOrder(root->left);
	printf("%d ", root->val);
	PrevOrder(root->right);
}

3.后序遍历

//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	PrevOrder(root->left);
	PrevOrder(root->right);
	printf("%d ", root->val);
}

四、求结点个数

1.求树的结点的个数(这里使用的是前序遍历)

int TreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + TreeSize(root->left) + TreeSize(root->right);
}

往一个函数中传入一个结点,若结点为空,则直接返回,为不为空则记为一个结点再加上,以该结点为根的左右子树的结点。

2.求叶子结点的个数

//求叶子结点个数
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

将一个根结点传入函数中,如结点为空值,则返回0,若该结点不为空值,且该结点的左右结点为空值,则说明该结点就是叶子结点,则返回1.如果该结点既不是空值,且该结点的左右结点也不为空值,则说明该结点并非叶子结点。该结点还有以它为根的子树,所以应该将它的左右子树传入函数,递归。知道找到子结点,并统计个数。

3.求第K层结点的个数

//树的第k层结点的个数
int TreeKLevel(BTNode* root, int K)
{
	if (root == NULL)
	{
		return 0;
	}
	if (K == 1)
	{
		return 1;
	}
	return TreeKLevel(root->left, K - 1) + TreeKLevel(root->right, K - 1);
}

第K层的结点等于第K-1层的左结点加上右节点。

五、二叉树的销毁(后序遍历)

// 二叉树销毁:后序遍历
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestory((*root)->left);
	BinaryTreeDestory((*root)->right);
	free(*root);
	*root = NULL;
}

二叉树的销毁采用左右根的方式,最后销毁根结点。遍历方式就是后序遍历。

六、二叉树的查找(前序遍历)

// 二叉树查找值为x的节点:前序遍历
BTNode* BinaryTreeFind(BTNode* root, int x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->val == x)
	{
		return root;
	}
	return BinaryTreeFind(root->left, x) == NULL ? BinaryTreeFind(root->right, x) : BinaryTreeFind(root->left, x);
}

使用二叉树查找某一个值是否存在,存在则返回它的地址,不存在则返回空。使用根左右的前序遍历方式,关键在于最后一句代码:最后一句代码使用了条件判断,如果根查不到,就查左子树,左子树是需要递归遍历的,如果递归遍历的结果是NULL,则返回遍历右子树的值(不管它是否为空),如果左子树遍历找到了,则直接返回左子树的值,不再遍历右子树。

总结:

在这篇内容中,我们用C语言改造一个7个结点的二叉树,然后讲解了二叉树的前中后序的递归遍历方式。还有利用二叉树的递归特性,求二叉树结点的个数,二叉树叶子结点的个数,第K层树的结点的个数。以及二叉树的销毁,还有二叉树的查找等。

喜欢的朋友点个关注,一起学习呀~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值