题解 UVA122 【树的层次遍历 Trees on the level】
By《算法竞赛入门经典》
前几天终于自学到树了,这道题作为例题自然是比较需要重点掌握了。
感觉这道题我在怎么讲解肯定也没有lrj讲得好,所以我这篇题解主要是lrj的思想。
最重要的是树的存储
可以用两种方法
-
结构体+指针
struct Node{ bool have_value;//是否被赋值过,这个是针对本题要求设定的 int v;//结点的值 Node* left, *right; Node():have_value(false),left(NULL),right(NULL){}//构造函数(大概就是初始化的意思吧) }*root;//二叉树的根结点
由于二叉树是递归定义的,其左右子结点类型都是“指向结点类型的指针”。换句话说, 如果结点的类型为Node,则左右子结点的类型都是Node *。
每次需要一个新的Node时,都要用new运算符申请内存,并执行构造函数。下面把申请 新结点的操作封装到newnode函数中:
Node* newnode() { return new Node(); }
还有这里lrj还提到了一个问题,当每次执行root=newnode()之后,之后这些内存就变成无法访问的内存垃圾了,因此最好写一个递归函数专门来清理这些内存。
下面是释清理内存的代码,请在“root = newnode()”之前加一 行“remove_tree(root)”:
void remove_tree(Node* u) { if(u == NULL) return;//提前判断比较稳妥 remove_tree(u->left);//递归释放左子树的空间 remove_tree(u->right);//递归释放右子树的空间 delete u;//调用u的析构函数并释放u结点本身的内存 }
-
数组+下标
首先还是给每个结点编号, 但不是按照从上到下从左到右的顺序,而是按照结点的生成顺序。用计数器cnt表示已存在的 结点编号的最大值,因此newnode函数需要改成这样:
const int root = 1; void newtree() { left[root] = right[root] = 0; have_value[root] = false; cnt = root; } int newnode() { int u = ++cnt; left[u] = right[u] = 0; have_value[root] = false; return u; }
上面的newtree()是用来代替前面的“remove_tree(root)”和“root = newnode()”两条语句的: 由于没有了动态内存的申请和释放,只需要重置结点计数器和根结点的左右子树了。 接下来,把所有的Node类型改成int类型,然后把结点结构中的成员变量改成全局数组 (例如,u->left和u->right分别改成left[u]和right[u]),除了char外,整个程序就没有任何指 针了。
存储完树之后,这道题就没什么难点了,直接BFS就可以了。
$my-code$
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#define maxn 1001000
using namespace std;
struct Node {
bool have_value;
int v;
Node *left,*right;
Node():have_value(false),left(NULL),right(NULL){}
};
int v;
bool failed;
char s[maxn];
Node* root;
Node* newnode(){return new Node();}
inline void remove_tree(Node *p) {
if(p == NULL) {
return ;
}
remove_tree(p->left);
remove_tree(p->right);
delete p;
}
inline bool BFS(vector<int> &ans) {
ans.clear();
queue<Node* > Q;
Q.push(root);
while(!Q.empty()) {
Node* u=Q.front();Q.pop();
if(!u->have_value) {
return false;
}
ans.push_back(u->v);
if(u->left != NULL) {
Q.push(u->left);
}
if(u->right != NULL) {
Q.push(u->right);
}
}
return true;
}
inline void add_Node(int v,char *s) {
int n=strlen(s);
Node *u=root;
for(int i=0; i<n; i++) {
if(s[i] == 'L') {
if(u->left == NULL) {
u->left=newnode();
}
u=u->left;
}
if(s[i] == 'R') {
if(u->right == NULL) {
u->right=newnode();
}
u=u->right;
}
}
if(u->have_value) {
failed=true;
}
u->v=v;
u->have_value=true;
}
inline bool read_input() {
failed=false;
remove_tree(root);
root=newnode();
for( ;; ) {
if(scanf("%s", s) != 1) {
return false;
}
if(strcmp(s,"()") == 0) {
break;
}
sscanf(&s[1],"%d",&v);
add_Node(v,strchr(s,',')+1);
}
return true;
}
int main()
{
vector<int> ans;
while(read_input()) {
if(failed || !BFS(ans)) {
printf("not complete");
}else {
for(vector<int>::iterator t=ans.begin(); t!=ans.end(); t++) {
if(t != ans.end()-1) {
printf("%d ",*t);
}else {
printf("%d",*t);
}
}
}
printf("\n");
}
return 0;
}