二叉树的最小深度
【描述】给定一棵二叉树, 求该二叉树的最小深度。二叉树的最小深度就是从根结点到最近的叶结点的路径上的结点数量。
【输入描述】第一行是一个正整数 n, 表示二叉树的结点个数。 二叉树结点编号从 1到 n, 根结点为 1, n <= 10 。接下来有 n 行, 依次对应二叉树的结点1~n。
每行有两个整数, 分别表示该结点的左儿子和右儿子的结点编号。 如果第一个(第二个) 数为-1 则表示没有左(右)儿子。
【输出描述】输出一个整型数, 表示树的最小深度。
【输入样例】
7
2 7
3 6
4 5
-1 -1
-1 -1
-1 -1
-1 -1
【输出样例】
2
cpp
#include<iostream>
#include<queue>
using namespace std;
struct tree_node{
int ls,rs; //ls:左孩子结点编号,rs:右孩子结点编号
};
tree_node tree[11];
int n;
queue<int> q;
int getMinDepth(){
int depth=0;
// 根结点编号1,入队
q.push(1);
while(!q.empty()){
depth++;
int levelCount = q.size();// 每层的节点数
while(levelCount>0){// 逐个处理这一层的结点
levelCount--;
int id = q.front();
q.pop();
if(tree[id].ls==-1 && tree[id].rs==-1)//第一个叶子结点
return depth;
// 先左后右,子结点(编号)入队
if(tree[id].ls != -1)
q.push(tree[id].ls);
if(tree[id].rs != -1)
q.push(tree[id].rs);
}
}
}
int main(){
// 读入和保存树
cin >> n;
for(int i=1;i<=n;i++){
cin >> tree[i].ls >> tree[i].rs;
}
// 以层序遍历方式获得最小深度
cout << getMinDepth();
return 0;
}
/*
本题测试点
【样例输入1】
1
-1 -1
【样例输出1】
1
【样例输入2】
7
2 3
4 5
6 7
-1 -1
-1 -1
-1 -1
-1 -1
【样例输出2】
3
【样例输入3】
4
2 -1
3 -1
4 -1
-1 -1
【样例输出3】
4
【样例输入4】
3
2 -1
-1 -1
-1 -1
【样例输出4】
2
【样例输入5】
2 3
-1 4
-1 -1
-1 -1
-1 -1
【样例输出5】
2
*/
二叉树的角结点
【描述】给定一棵二叉树, 输出该二叉树的所有角结点。二叉树的角结点指每层的最左边的结点和最右边的结点。例如右图的二叉树,按层次从左到右输出所有角结点: 1 2 6 3 7 5。
【输入描述】第一行是一个正整数 n, 表示二叉树的结点个数。 二叉树结点编号从 1到 n, 根结点为 1, n <= 10 。接下来有 n 行, 依次对应二叉树的结点1~n。
每行有两个整数, 分别表示该结点的左儿子和右儿子的结点编号。 如果第一个(第二个) 数为-1 则表示没有左(右)儿子。
【输出描述】按从上到下、从左到右输出所有角结点。
【输入样例】
7
2 6
3 4
-1 -1
5 -1
-1 -1
-1 7
-1 -1
【输出样例】
1 2 6 3 7 5
cpp
#include<iostream>
#include<queue>
using namespace std;
struct tree_node{
int ls,rs; //ls:左孩子结点编号,rs:右孩子结点编号
};
tree_node tree[11];
int n;
queue<int> q;
void printCornerNodes(){
// 根结点编号1,入队
q.push(1);
while(!q.empty()){
int levelCount = q.size();// 当前层的节点数
for(int i=levelCount;i>0;i--){// 处理这一层的结点
int id = q.front();
q.pop();
//每层第一个元素即最左结点
//每层最后一个元素即最右结点
if(i==levelCount || i==1)
cout << id << " ";
// 先左后右,子结点(编号)入队
if(tree[id].ls != -1)
q.push(tree[id].ls);
if(tree[id].rs != -1)
q.push(tree[id].rs);
}
}
}
int main(){
// 读入和保存树
cin >> n;
for(int i=1;i<=n;i++){
cin >> tree[i].ls >> tree[i].rs;
}
// 以层序遍历方式打印角结点
printCornerNodes();
return 0;
}
/*
本题测试点
【样例输入1】
3
3 -1
-1 -1
2 -1
【样例输出1】
1 3 2
【样例输入2】
7
2 7
3 6
4 5
-1 -1
-1 -1
-1 -1
-1 -1
【样例输出2】
1 2 7 3 6 4 5
【样例输入3】
7
2 3
4 5
6 7
-1 -1
-1 -1
-1 -1
-1 -1
【样例输出3】
1 2 3 4 7
【样例输入4】
10
2 10
3 -1
4 9
5 8
6 7
-1 -1
-1 -1
-1 -1
-1 -1
-1 -1
【样例输出4】
1 2 10 3 4 9 5 8 6 7
【样例输入5】
10
2 3
4 5
6 7
8 -1
-1 9
-1 -1
-1 10
-1 -1
-1 -1
-1 -1
【样例输出5】
1 2 3 4 7 8 10
*/
判断平衡二叉树
【描述】给定一棵二叉树, 判断该二叉树的是否平衡二叉树。
平衡二叉树指树的每个结点的两个子树的高度差都不能超过1。 反之任意一个结点的左右子树的高度差>1,则这个树不是平衡二叉树。 只有一个结点的树也是平衡二叉树。
【输入描述】第一行是一个正整数 n, 表示二叉树的结点个数。 二叉树结点编号从 1到 n, 根结点为 1, n <= 10 。接下来有 n 行, 依次对应二叉树的结点1~n。
每行有两个整数, 分别表示该结点的左儿子和右儿子的结点编号。 如果第一个(第二个) 数为-1 则表示没有左(右)儿子。
【输出描述】这个树是平衡二叉树,输出"yes",否则输出"no"。
【输入样例】
7
2 6
3 4
-1 -1
5 -1
-1 -1
-1 7
-1 -1
【输出样例】
yes
cpp
#include<iostream>
using namespace std;
struct tree_node{
int ls,rs; //ls:左孩子结点编号,rs:右孩子结点编号
};
tree_node tree[11];
int n;
int depth(int root){
if(root == -1 ) return 0;
// 树的深度=左右子树深度较大者+1
return max(depth(tree[root].ls),depth(tree[root].rs))+1;
}
bool isBalanced(int root){
if(root == -1 ) return true;
// 树平衡:左右子树必须平衡,且左右子树深度差<=1
if(!isBalanced(tree[root].ls) || !isBalanced(tree[root].rs))
return false;
int lDepth = depth(tree[root].ls);
int rDepth = depth(tree[root].rs);
if(abs(lDepth-rDepth)>1) return false;
return true;
}
int main(){
// 读入和保存树
cin >> n;
for(int i=1;i<=n;i++){
cin >> tree[i].ls >> tree[i].rs;
}
// 是否平衡二叉树
if(isBalanced(1))
cout << "yes";
else
cout << "no";
return 0;
}
/*
本题测试点
【样例输入1】
1
-1 -1
【样例输出1】
yes
【样例输入2】
3
3 -1
-1 -1
2 -1
【样例输出2】
no
【样例输入3】
3
2 3
-1 -1
-1 -1
【样例输出3】
yes
【样例输入4】
7
2 6
3 4
-1 -1
5 -1
-1 -1
-1 7
-1 -1
【样例输出4】
yes
【样例输入5】
7
2 7
3 6
4 5
-1 -1
-1 -1
-1 -1
-1 -1
【样例输出5】
no
*/
右叶结点的和
【描述】给定一棵二叉树, 求所有右叶结点值的和。
【输入描述】
第一行是一个正整数 n, 表示二叉树的结点个数。 二叉树结点编号从 1到 n, 根结点为 1, n <= 10 。接下来有 n 行, 依次对应二叉树的结点1~n。
每行有3个整数, 分别表示该结点的值、左儿子和右儿子的结点编号。 如果第2个(第3个) 数为-1 则表示没有左(右)儿子。
【输出描述】
输出一个整型数, 表示所有右叶结点值的和。
【输入样例】
7
12 2 6
3 3 4
5 -1 -1
0 5 -1
0 -1 -1
6 -1 7
7 -1 -1
【输出样例】
7
【提示】
方法1:层序遍历时保持两个队列,一个层序过程中的结点(编号)队列,一个结点是否右子结点的标记队列。
保持两个队列同步(一一对应)
方法2:在结点结构体中增加一个标记,标记当前结点是否是某个父结点的右子结点。
cpp
#include<iostream>
#include<queue>
using namespace std;
struct tree_node{
int value;
int ls,rs; //ls:左孩子结点编号,rs:右孩子结点编号
};
tree_node tree[11];
int n;
queue<int> q; // 层序遍历:结点编号队列
queue<bool> qFlag; // 层序遍历:结点是否右结点的标记队列
int rightLeavesSum(){
int sum = 0;
// 根结点编号1,入队
q.push(1);
qFlag.push(false);
while(!q.empty()){
int levelCount = q.size();// 当前层的节点数
for(int i=levelCount;i>0;i--){// 处理这一层的结点
int id = q.front();
int isRightSon = qFlag.front();
q.pop();
qFlag.pop();
//是右结点且是叶结点,计算和
if(isRightSon && tree[id].ls == -1 && tree[id].rs == -1)
sum += tree[id].value;
// 先左后右,子结点(编号)入队
if(tree[id].ls != -1){
q.push(tree[id].ls);
qFlag.push(false);
}
if(tree[id].rs != -1){
q.push(tree[id].rs);
qFlag.push(true);
}
}
}
return sum;
}
int main(){
// 读入和保存树
cin >> n;
for(int i=1;i<=n;i++){
cin >> tree[i].value ;
cin >> tree[i].ls >> tree[i].rs;
}
// 计算所有右叶结点之和
cout << rightLeavesSum();
return 0;
}
/*
本题测试点
【样例输入1】
3
1 3 -1
3 -1 -1
7 2 -1
【样例输出1】
0
【样例输入2】
3
1 2 3
3 -1 -1
7 -1 -1
【样例输出2】
7
【样例输入3】
7
12 2 6
3 3 4
5 -1 -1
0 5 -1
0 -1 -1
6 -1 7
7 -1 -1
【样例输出3】
7
【样例输入4】
7
12 2 7
0 3 6
5 4 5
0 -1 -1
7 -1 -1
4 -1 -1
8 -1 -1
【样例输出4】
19
【样例输入5】
7
12 2 6
3 3 4
5 -1 -1
4 5 -1
0 -1 -1
6 -1 7
0 -1 -1
【样例输出5】
0
*/