UVa122二叉树的层次遍历
二叉树的存储结构,可以采取顺序存储和链式存储。顺序存储对于完全二叉树来说不浪费空间而且各种运算简单,求双亲求孩子都是常量算法;对于二叉树来说,浪费空间的情况下求双亲和求孩子仍然是常量,但是对于单支树来说浪费大。
采用链式存储,可以用二叉链表和三叉链表。二叉链表的结点类就是指向左孩子的指针lchild,数据值data和指向右孩子的指针rchild。二叉链表的情况下,求孩子是常量算法,求双亲是一阶算法(所有点走一遍)。三叉链表的结点类是在二叉链表的基础上多了一个parent指针,这样使得找双亲也成为常量算法。
链式存储都可以考虑静态结构和动态结构。静态结构就是数组,看房间号。静态链表结构是利用数组定义,数组名就是指针常量,运算过程中存储空间大小不变,指针为数组下标。线性表和二叉树这种非线性结构的存储方式都会考虑顺序存储和链式存储这两种方式。其实就是前驱共不共享和最后一个元素有几个的区别。所以数据结构就是画出一个图,就对一种写法。
二叉树的遍历,有n个结点就有n!种遍历方式,研究其中有规律的方式。层次遍历就是从上到下从左到右。树就是图,图的深度优先遍历和广度优先遍历都不唯一,因为起点的选择不同,路径的选择也不同,二叉树以根结点为起点是定下来。图的广度优先遍历其实就是图对应广度优先生成树的层次遍历,因此可以用队列实现。
对于这道题目来说,静态结构的顺序存储肯定是存不下了,单支树的256个结点,编号会大到\(2^{255}\)这么多去。因此,不使用顺序存储,采用链式存储。
对于所有的链式结构,都是两个类,一个链表类一个结点类。
输入数据就是告诉建树方式,层次遍历就是读树输出的方式。
读入方式也很值得学习,以空格为分界来读,再使用sscanf从字符串中读出整数值。这样做就避免了自己写状态机来处理。
注意在层次遍历的时候,要判断有没有孩子,也就是没有访问过的孩子是没找到还是没找完。
使用静态结构的代码如下。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int MAXN = 260;
char s[10010];
int root = 1;
int cnt = 1; // 目前所有结点的最大编号
int lchild[MAXN], rchild[MAXN];
int data[MAXN]; // 如果数据值可以是负数和0,所以要记录是否赋值过
bool have_value[MAXN];
bool failed = false;
int cnt_ans = 0;
int ans[MAXN];
bool vis[MAXN];
void Init() {
memset(lchild, 0, sizeof(lchild));
memset(rchild, 0, sizeof(rchild));
memset(data, 0, sizeof(data));
memset(have_value, 0, sizeof(have_value));
memset(vis, 0, sizeof(vis));
root = 1;
cnt = 1;
lchild[root] = 0;
rchild[root] = 0;
failed = false;
return;
}
void addnode(int v, char* s) {
int n = strlen(s);
int p = root;
for (int i = 0; i < n; i++) {
if (s[i] == 'L') {
if (lchild[p] == 0) {
lchild[p] = ++cnt;
}
p = lchild[p];
} else if (s[i] == 'R') {
if (rchild[p] == 0) {
rchild[p] = ++cnt;
}
p = rchild[p];
} // 忽略')'的这些情况
}
if (have_value[p]) {
failed = true;
}
data[p] = v;
have_value[p] = true;
return;
}
void traverse(int root) {
queue<int> Q;
Q.push(root);
cnt_ans = 0;
vis[root] = 1;
while (Q.empty() == false) {
int cur = Q.front();
Q.pop();
if (have_value[cur] == false) {
failed = true;
}
ans[cnt_ans++] = cur;
if (lchild[cur] != 0 && vis[lchild[cur]] == 0) {
Q.push(lchild[cur]);
vis[lchild[cur]] = 1;
}
if (rchild[cur] != 0 && vis[rchild[cur]] == 0) {
Q.push(rchild[cur]);
vis[lchild[cur]] = 1;
}
}
return;
}
int main() {
for (;;) {
bool end = false;
Init();
for (;;) {
if (scanf("%s", s) != 1) {
end = true;
break;
}
if (strcmp(s, "()") == 0) {
traverse(root);
if (failed == true) {
printf("not complete\n");
} else {
for (int i = 0; i < cnt_ans; i++) {
if (i == 0) {
printf("%d", data[ans[i]]);
} else {
printf(" %d", data[ans[i]]);
}
}
printf("\n");
}
break;
}
int v;
sscanf(&s[1], "%d", &v);
addnode(v, strchr(s, ',') + 1);
}
if (end == true) {
break;
}
}
return 0;
}