求叶子节点个数
题目描述
假设一棵非空树采用孩子链存储结构,每个结点值均为单个字符。请设计一个算法求树中的叶子结点个数。
输入格式
输入包含多行。
第一行包含一个整数 n n n 和一个字符 r o o t root root,表示树的节点个数和根节点。
接下来的 n − 1 n-1 n−1 行,每行包含两个字符 a a a 和 b b b,表示 a a a 是 b b b 的父节点。
输出格式
输出一个整数,表示叶子结点的个数。
样例 #1
样例输入 #1
4 A
A B
B C
A D
B E
样例输出 #1
3
思路
如果节点 x
的度 degree
小于或等于0,说明该节点没有子节点,即它是一个叶子节点,此时函数返回1。
如果节点 x
的度 degree
大于0,说明它不是叶子节点,而是一个内部节点。此时函数需要计算它所有子节点的叶子节点数量。函数初始化一个计数器 cnt
为0,然后遍历节点 x
的所有子节点。对于每一个子节点 i
,函数递归调用 countLeaf(node[x].child[i])
,计算以子节点 i
为根的子树中叶子节点的数量,然后将结果加到 cnt
上。
遍历完所有的子节点后,cnt
就是以 x
为根的子树中叶子节点的数量,函数返回 cnt
。
算法分析
时间复杂度是
O
(
n
)
O(n)
O(n),其中
n
n
n 是树中节点的数量。这是因为在整个计算过程中,每个节点只会被访问和处理一次。对于每个节点,函数会检查其度(也就是子节点的数量),如果度为0,函数会立即返回;如果度不为0,函数会遍历所有的子节点,并递归调用 countLeaf
函数。
空间复杂度也是 O ( n ) O(n) O(n)。虽然函数本身没有使用额外的数据结构来存储数据,但是由于函数是递归的,所以它会使用调用栈来存储递归调用的信息。在最坏的情况下,如果树是一棵斜树(也就是每个节点最多只有一个子节点),那么函数的递归深度就等于树的深度,也就是节点的数量,因此空间复杂度为 O ( n ) O(n) O(n)。
AC代码
#include <algorithm>
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
using Status = int;
using ElemType = char;
const int N = 1e6 + 7;
const int M = 1e3 + 7;
const int TRUE = 1;
const int FALSE = 0;
const int OK = 1;
const int ERROR = 0;
const int IMFEASIBLE = -1;
// const int OVERFLOW = -2;
int n;
struct TreeNode {
int degree;
int child[M];
} node[M];
int countLeaf(int x) {
// cout << (char)x << endl;
if (node[x].degree <= 0) {
return 1;
}
int cnt = 0;
for (int i = 0; i < node[x].degree; i++) {
cnt += countLeaf(node[x].child[i]);
}
return cnt;
}
Status addChild(int u, int v) {
if (node[u].degree >= M) {
return ERROR;
}
node[u].child[node[u].degree++] = v;
return OK;
}
int main() {
char root;
cin >> n;
cin >> root;
for (int i = 0; i < n; i++) {
char u, v;
cin >> u >> v;
addChild((int)u, (int)v);
}
cout << countLeaf((int)root);
return 0;
}