网易云课堂浙大数据结构课
第三周 树(上)
PAT: List Leaves解答
- 关键问题
- 如何根据输入创建树?
- 如何根据建好的二叉树找出叶子节点?且顺序为从上到下,从左到右?
- 如何根据输入创建树?
- 题目先输入N (N<=10),表示有个结点,节点数字从0到N-1编号;
- 然后从编号为0的结点到N-1,依次输入每个结点的左孩子编号和右孩子编号,没有某孩子则输入-, 将孩子信息记录到两个数组l[10]和r[10]中;当某个编号i出现时,就将findRoot[i]置为1(后面解释这一点);
- 这里的关键是找到根结点的编号!
找到根结点的编号后,就可以依据l[10]和r[10]创建树,采用先序、中序、后序和层序我觉得都可以,我采用了先序。 - 通过观察发现(好吧,这句话有点坑,但是的确是我走在回宿舍的路上突然发现的),第2步输入左右孩子信息的时候,不会出现根结点的编号!(画出原题给的示例的树,会发现3是根结点,而3不会出现在输入里)所以可以遍历数组findRoot找到没出现的那个数字,也就数组findRoot中唯一为0的那个数字(在0到N-1之间),这个数字就是根结点的编号
- 找到根结点就可以愉快的去创建树了,但是注意分配内存和释放内存,注意一些小细节
void LevelOrderCreateBiTree(BiTree &BT, char num)
{
BT = (BiTree)malloc(sizeof(TreeNode));
if (num != '-') {
BT->Data = num;
} else {
free(BT);
BT = NULL;
return;
}
LevelOrderCreateBiTree(BT->Left, l[num]);
LevelOrderCreateBiTree(BT->Right, r[num]);
}
- 如何根据建好的二叉树找出叶子节点?且顺序为从上到下,从左到右?
这个何老师在MOOC上讲过了,很简单。
- 要找出叶子结点,只要在某种遍历方式中,处理结点的时候(例如print),加个条件(左右孩子均空才处理)就行了,因为只有叶子结点的左右孩子都是空的;
- 要从上到下,从左到右打印叶子结点,思考一下就会发现层序遍历方式符合要求,所以这里采用层序遍历的方式打印叶子结点。
void LevelOrderPrintLeaves(BiTree BT)
{
BiTree T;
queue<BiTree> Q;
Q.push(BT);
while (!Q.empty()) {
T = Q.front();
Q.pop();
if (!T->Left && !T->Right) {
//print right space
--cnt;
if (cnt) {
cout << T->Data << " ";
} else {
cout << T->Data << endl;
}
}
if (T->Left) Q.push(T->Left);
if (T->Right) Q.push(T->Right);
}
}
- 细节问题:如何让你的输出后面没有多余的空格?
打印叶子结点的编号时,我估计大部分人会这样:
cout << BT->Data << " ";
但是这样会在最后一个叶子结点后打印多余的一个空格。
我用变量cnt在输入时统计叶子结点的个数,也就是当左右孩子均为-时++cnt;
if (l[i] == '-' && r[i] == '-') ++cnt;
然后用cnt来控制打印叶子结点的格式。
if (cnt) {
cout << T->Data << " ";
} else {
cout << T->Data << endl;
}
整体代码如下:
#include <iostream>
#include <queue>
#include <cstdlib>
using namespace std;
typedef int ElementType;
typedef struct TreeNode* BiTree;
struct TreeNode {
ElementType Data;
BiTree Left;
BiTree Right;
};
int findRoot[10] = { 0 }; // in order to find root's number
char l[10]; //record input data
char r[10]; //record input data
int cnt = 0; // in order to print right space;
void LevelOrderCreateBiTree(BiTree &BT, char num);
void LevelOrderPrintLeaves(BiTree BT);
void PreOrderPrinLeaves(BiTree BT);
int main()
{
//input data
int N;
cin >> N;
for (int i = 0; i != N; ++i) {
cin >> l[i] >> r[i];
if (l[i] != '-') {
l[i] = l[i] - '0';
findRoot[l[i]] = 1;
}
if (r[i] != '-') {
r[i] = r[i] - '0';
findRoot[r[i]] = 1;
}
//in order to print right space
if (l[i] == '-' && r[i] == '-') ++cnt;
}
//find root's number
//explanation: root's number will not occur in the input.
//e.g.: as the web shows, 3 is root, but not occurs in the input.
int root = 0;
for (int i = 0; i != N; ++i) {
if (0 == findRoot[i]) {
root = i;
break;
}
}
//create binary tree
BiTree BT;
LevelOrderCreateBiTree(BT, root);
//list leaves
LevelOrderPrintLeaves(BT);
//debug info:
//PreOrderPrinLeaves(BT);
//cout << "debug info" << endl;
return 0;
}
void LevelOrderCreateBiTree(BiTree &BT, char num)
{
BT = (BiTree)malloc(sizeof(TreeNode));
if (num != '-') {
BT->Data = num;
} else {
free(BT);
BT = NULL;
return;
}
LevelOrderCreateBiTree(BT->Left, l[num]);
LevelOrderCreateBiTree(BT->Right, r[num]);
}
void LevelOrderPrintLeaves(BiTree BT)
{
BiTree T;
queue<BiTree> Q;
Q.push(BT);
while (!Q.empty()) {
T = Q.front();
Q.pop();
if (!T->Left && !T->Right) {
//print right space
--cnt;
if (cnt) {
cout << T->Data << " ";
} else {
cout << T->Data << endl;
}
}
if (T->Left) Q.push(T->Left);
if (T->Right) Q.push(T->Right);
}
}
void PreOrderPrinLeaves(BiTree BT)
{
if (BT) {
cout << BT->Data << " ";
PreOrderPrinLeaves(BT->Left);
PreOrderPrinLeaves(BT->Right);
}
}