PTA实验三 6-2 统计二叉树度为2的结点个数

本题要求实现一个函数,可统计二叉树中度为2的结点个数。

函数接口定义:

int NodeCount ( BiTree T);

 

T是二叉树树根指针,函数NodeCount返回二叉树中度为2的结点个数,若树为空,返回0。

裁判测试程序样例: 


#include <stdio.h>
#include <stdlib.h>

typedef char ElemType;
typedef struct BiTNode
{
	ElemType data;
	struct BiTNode* lchild, * rchild;
}BiTNode, * BiTree;

BiTree Create();/* 细节在此不表 */

int NodeCount(BiTree T);

int main()
{
	BiTree T = Create();
	printf("%d\n", NodeCount(T));
	return 0;
}
/* 你的代码将被嵌在这里 */

 

输入样例:

输入为由字母和'#'组成的字符串,代表二叉树的扩展先序序列。例如对于如下二叉树,输入数据:

AB#DF##G##C##

输出样例(对于图中给出的树):

二叉树.png

2

代码长度限制         16 KB

时间限制                400 ms

内存限制                64 MB

<方法一>:借助递归利用分治来求解答案

思路:我们想要求一整棵树中的度数为2的节点,听上去有点困难,那不妨把这棵树变小一点看看会不会简单一点,那问题来了,该怎么变小呢?没错!就是去看看这棵树的左或者右子树中有没有度数为2的节点(假设它有子树。如果没有怎么办?这简单啊,没有对应的子树是不是就相当于它对应的“子树”上度数为2的节点的数目为0?),按照这个思路不断把一棵树变小最终我们一定能把这棵树变成一个只有一个节点的“树”。很显然只有一个节点那它肯定不具有度数为2的节点呀!然后我们只需要返回0即可,这样对于这个特殊的树的父节点来说,有一边已经确定了度数为2的节点有0个,然后去找另一边看看有没有符合题意的节点即可。

思路讲完了,现在我们来看看代码:
 

int NodeCount(BiTree T) {
	if (T) {//看看当前这棵树是不是空树,主要是针对刚传递进来的树就是空树这一特殊情况
		if (T->lchild && T->rchild) {//如果当前节点的左右子树均存在,那么它自己肯定是符合题意的,然后我们只需要顺着它的左子树去找一找,再顺着右子树去找一找,最后把结果加起来返回就可以了!
			return 1 + NodeCount(T->lchild) + NodeCount(T->rchild);
		}
		else if (T->lchild && !T->rchild) {//这种情况是左子树存在但右子树不存在,那它自己肯定不符合题意了,只能去左边找找看喽
			return NodeCount(T->lchild);
		}
		else if (!T->lchild && T->rchild) {//和上面情况类似,只不过变成了去右边找
			return NodeCount(T->rchild);
		}
		else {//这里就是递归出口了,现在我们已经把一棵二叉树分解的只剩一个节点了,返回0,让上一层递归函数去另一边找目标(如果存在的话)
			return 0;
		}
	}
    else {//如果第一次传递的数就是个空树那直接返回0就行了
        return 0;
    }
}

有没有觉得很简单?这就是分治的魅力!我们把一个大问题分解成了很多个小问题,然后对每个小问题继续分解,最终出现了非常特殊的且很简单的情况,然后去解决简单的小问题,所有简单的小问题成功解决后我们发现整个大问题也迎刃而解了。

提交结果:

<方法二>:借助栈来非递归的遍历二叉树,然后对于每个节点都去判断它的左右子树是否都存在,存在的话就让记录的变量加1,否则去判断另一个节点。本质是模拟查找的过程。
代码如下:

int NodeCount(BiTree T) {
	if (!T) {//如果树为空直接返回0
		return 0;
	}
	BiTNode *Stack[100];//定义一个最大容量为100的栈,足够用
	int top = 0, ans = 0;//记录栈顶指针和当前的答案,我习惯让指针指向栈顶的上面一层,这样当top=0时表示栈空
	Stack[top++] = T;//先把根节点入栈
	while (top != 0) {//当栈不为空的时候循环
		BiTree cur = Stack[--top];//每次循环时先弹出来一个节点进行判断
		if (cur->lchild && cur->rchild) {
			++ans;
		}
        //然后分别判断左右子树是否存在,存在就入栈
		if (cur->rchild) {
			Stack[top++] = cur->rchild;
		}
		if (cur->lchild) {
			Stack[top++] = cur->lchild;
		}
	}
	return ans;
}
//发现了吗?这是先序遍历,每次都先访问根节点,然后先入右节点再入左节点,由于栈的特性,下次循环先弹出的节点必然是左子树的节点,一旦弹的是右子树说明父节点的左子树为空或者已经访问过了。当然,拿其他序方式遍历也是可以的

 此方法需要你对二叉树的非递归遍历有所了解,最好是把先序中序后序的非递归遍历方法都学习一下,很有用的。

提交结果如下:

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值