Hello 树先生!———二叉树递归

一.递归二叉树

1.二叉树遍历

在这里插入图片描述
用N代表空

1 前序遍历

先访问根节点,然后递归地访问左子树和右子树。
1->2->3->N->N->N->4->5->N->N->6->N->N

void PreOrder(bintree* root)
{
	if (root== NULL)
	{
		printf("N->");
		return;
	}
	printf("%d->", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

结果如下:

在这里插入图片描述

2中序遍历

先递归地访问左子树,然后访问根节点,最后递归地访问右子树。
N->3->N->2->N->1->N->5->N->4->N->6->N

void InOrder(bintree* root)
{
	if (root == NULL)
	{
		printf("N->");
		return;
	}
	InOrder(root->left);
	
	printf("%d->", root->data);
	InOrder(root->right);
}

结果如下:
在这里插入图片描述

3后序遍历

先递归地访问左子树和右子树,最后访问根节点。
N->N->3->N->2->N->N->5->N->N->6->4->1

void TailOrder(bintree* root)
{
	if (root == NULL)
	{
		printf("N->");
		return;
	}
	TailOrder(root->left);
	TailOrder(root->right);
	printf("%d->", root->data);
	
}

在这里插入图片描述

4层序遍历

具体的层序遍历步骤如下:
1。将根节点放入队列中。
2.当队列不为空时,循环执行以下步骤: a. 从队列中取出一个节点,并将其值输出。 b. 将该节点的左子节点和右子节点(如果存在)依次放入队列中。
3.当队列为空时,表示层序遍历结束
在这里插入代码片

层序遍历可以用于树的广度优先搜索,它能够按照层级顺序逐层遍历节点,适用于求解树的最短路径等问题。
在这里插入图片描述
如图这棵树,将根节点放入队列之中,当需要遍历之时,取出1号,随之将其左右孩子节点放入队列即2号和4号,当取出2号时,将3号放入,取出4号时将5号6号放入…
那么如何一层一层取出数据或打印数据呢?
我们借助队列个数统计,创建一个levesize记录每一层个数循环操作

void BinaryTreeLevelOrder(bintree* root)
{
	queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	int levesize = 1;//记录每层个数
	while (!QueueEmpty(&q))
	{
		//一层一层
		while (levesize--)
		{
			bintree* front = QueueFront(&q);
			QueuePop(&q);//出队列
			printf("%d ", front->data);
            //递归操作
			if (front->left)
				QueuePush(&q, front->left);
			if (front->right)
				QueuePush(&q, front->right);

		}
		printf("\n");
		levesize = QueueSize(&q);//每层出完后,重新统计

	}
	QueueDestroy(&q);
}

在这里插入图片描述
在c语言中没有队列库函数,所以借助曾经代码,对此不熟悉的可以参考往期文章:链接: 队列和栈

2.递归制造一棵二叉树

给定一个字符数组,将其表现为想要的树
ABD##E#H##CF##G##
采用前序遍历方式,制造结点

bintree* CreatBTree(char* a,int*pi)
{

	if (a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	bintree* root = (bintree*)malloc(sizeof(bintree));
	root->data = a[(*pi)++];
	root->left= CreatBTree(a, pi);
	root->right= CreatBTree(a, pi);

	return root;


}
结束条件为'#',开始返回,根节点的左孩子接受左子树返回的节点,右孩子接受右子树返回的节点

在这里插入图片描述
我们展示一下将要实现的功能:

int main()
{ 
	//bintree*treeroot=Creattree();
	int i = 0;
	char a[100] = "ABD##E#H##CF##G##";
	bintree* treeroot = CreatBTree(a, &i);
	PreOrder(treeroot);
	printf("\n");
	InOrder(treeroot);
	printf("\n");
	TailOrder(treeroot);
	printf("\n");
	printf("%d", TreeSize(treeroot));
	printf("\n");
	printf("%d", TreeLeafSize(treeroot));
	printf("\n");
	printf("%d", TreeHeight(treeroot));
	printf("\n");
	printf("%d", TreeKleve(treeroot,3));
	return 0;
}

在这里插入图片描述
这些功能在第二部分实现

二.部分功能实现

1.统计二叉树节点数

有两种常见思路:

                        1.创建一个全局变量size,然后遍历二叉树,size++。
                        2.递归思路,左右子树节点之和加1。

第一种比较简单,我们实现第二种思路。
结束条件为,root为空
如果二叉树为空,则节点数为0。
否则,节点数为根节点数加上左子树节点数和右子树节点数。
递归地计算左子树节点数和右子树节点数。

int TreeSize(bintree* root)
{
	return root == NULL ?
		0 : TreeSize( root->left) +//左
		TreeSize(root->right) +//右
		1;//根

}

2.统计子叶个数

类似于第二点,只不过由于判断子叶条件变了所以递归条件变了。
分治子问题:

          1.是空,返回条件,返回0
          2.不是空,是叶子,返回1
int TreeLeafSize(bintree* root)
{
	if (root == NULL) 
		//是空,返回条件,返回0
		return 0;
	if (root->left == NULL && root->right == NULL) 
		//不是空,是叶子,返回1
		return 1;
	return TreeLeafSize(root->left) + TreeLeafSize(root->right);
	//左子树叶子与右子树叶子之和
}

在这里插入图片描述
如图所示,先递归红色左子树,在递归棕色右子树,此为分治子问题,一共两种情况不同返回递归结果
在这里插入图片描述

答案正确。

3.统计树高

同样的问题:左右递归,选择左右子树高的记录。

int TreeHeight(bintree* root)
{
	if (root == NULL)
		return 0;
	int leftheight = TreeHeight(root->left);
	int rightheight = TreeHeight(root->right);

	return leftheight > rightheight ? leftheight + 1 : rightheight + 1;

}

在这里插入图片描述
我们可以人为给树增加两层

node5->left = node7;
node7->left = node8;

在这里插入图片描述

4.统计任意一层的节点数

这题仍然是一个分治子问题,由于在同一层的节点存在NULL和非空,所以递归条件:

          1.root==NULL时,不计数量返回0
          2.k=1时,root!=NULL时,计数量为1
int TreeKleve(bintree* root,int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return TreeKleve(root->left, k - 1) + TreeKleve(root->right, k - 1);

}

在这里插入图片描述
以该图解释,计数第三层,则为左子树和右子树第二层相加,则为左子树的左右子树第一层相加和右子树的左右子树第一层相加

根k=3
<=>左子树k=2+右子树k=2
<=>左子树的     左右子树k=1              +            右子树的       左右子树k=1
结果为3

在这里插入图片描述

三.判断完全二叉树

判断一棵树是否是完全二叉树通常需要使用层序遍历的方法。以下是判断一棵树是否为完全二叉树的步骤:

对树进行层序遍历,从根节点开始。
1.如果在层序遍历中遇到了空节点(即null节点),则该空节点后面的所有节点必须都是空节点,否则树不是完全二叉树。
2.如果在层序遍历中遇到了一个节点,但是它的左子节点是空节点,而右子节点不是空节点,则树不是完全二叉树。
3.如果在层序遍历中遇到了一个节点,但是它没有左子节点,但是有右子节点,则树不是完全二叉树。
4.如果在层序遍历中没有出现上述情况,且遍历到最后一个节点后,树仍然是完全二叉树。
bool BinaryTreeComplete(bintree* root)
{
	queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
			bintree* front = QueueFront(&q);
			QueuePop(&q);
			if (front == NULL)
				break;

		
				QueuePush(&q, front->left);
				QueuePush(&q, front->right);

	}
	while (!QueueEmpty(&q))
	{
		bintree* front = QueueFront(&q);
		QueuePop(&q);
		if (front)	
		{
			QueueDestroy(&q);
			return false;
		}
			
	}
	QueueDestroy(&q);
	return true;
}

在第一遇到NULL时看队列内是否还有数据,如果没有则为完全二叉树
显然该树不是完全二叉树
在这里插入图片描述

在这里插入图片描述

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
1. 什么是二叉树? 二叉树是一种形结构,其中每个节点最多有两个子节点。一个节点的左子节点比该节点小,右子节点比该节点大。二叉树通常用于搜索和排序。 2. 二叉树的遍历方法有哪些? 二叉树的遍历方法包括前序遍历、中序遍历和后序遍历。前序遍历是从根节点开始遍历,先访问根节点,再访问左子,最后访问右子。中序遍历是从根节点开始遍历,先访问左子,再访问根节点,最后访问右子。后序遍历是从根节点开始遍历,先访问左子,再访问右子,最后访问根节点。 3. 二叉树的查找方法有哪些? 二叉树的查找方法包括归查找和非归查找。归查找是从根节点开始查找,如果当前节点的值等于要查找的值,则返回当前节点。如果要查找的值比当前节点小,则继续在左子中查找;如果要查找的值比当前节点大,则继续在右子中查找。非归查找可以使用栈或队列实现,从根节点开始,每次将当前节点的左右子节点入栈/队列,直到找到要查找的值或者栈/队列为空。 4. 二叉树的插入与删除操作如何实现? 二叉树的插入操作是将要插入的节点与当前节点的值进行比较,如果小于当前节点的值,则继续在左子中插入;如果大于当前节点的值,则继续在右子中插入。当找到一个空节点时,就将要插入的节点作为该空节点的子节点。删除操作需要分为三种情况:删除叶子节点、删除只有一个子节点的节点和删除有两个子节点的节点。删除叶子节点很简单,只需要将其父节点的对应子节点置为空即可。删除只有一个子节点的节点,需要将其子节点替换为该节点的位置。删除有两个子节点的节点,则可以找到该节点的后继节点(即右子中最小的节点),将其替换为该节点,然后删除后继节点。 5. 什么是平衡二叉树? 平衡二叉树是一种特殊的二叉树,它保证左右子的高度差不超过1。这种平衡可以确保二叉树的查找、插入和删除操作的时间复杂度都是O(logn)。常见的平衡二叉树包括红黑和AVL

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

强sir的世界

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值