学校poj平台上的题,比较全面地考察了树的存储结构、相关函数及性质。
原题:
总时间限制:
1000ms
内存限制:
65536kB
描述
一棵树的镜面映射指的是对于树中的每个结点,都将其子结点反序。例如,对左边的树,镜面映射后变成右边这棵树。
a a / | \ / | \ b c f ===> f c b / \ / \ d e e d
我们在输入输出一棵树的时候,常常会把树转换成对应的二叉树,而且对该二叉树中只有单个子结点的分支结点补充一个虚子结点“$”,形成“伪满二叉树”。
例如,对下图左边的树,得到下图右边的伪满二叉树
a a / | \ / \ b c f ===> b $ / \ / \ d e $ c / \ d f / \ $ e
然后对这棵二叉树进行前序遍历,如果是内部结点则标记为0,如果是叶结点则标记为1,而且虚结点也输出。
现在我们将一棵树以“伪满二叉树”的形式输入,要求输出这棵树的镜面映射的宽度优先遍历序列。
输入
输入包含一棵树所形成的“伪满二叉树”的前序遍历。
第一行包含一个整数,表示结点的数目。
第二行包含所有结点。每个结点用两个字符表示,第一个字符表示结点的编号,第二个字符表示该结点为内部结点还是外部结点,内部结点为0,外部结点为1。结点之间用一个空格隔开。
数据保证所有结点的编号都为一个小写字母。
输出
输出包含这棵树的镜面映射的宽度优先遍历序列,只需要输出每个结点的编号,编号之间用一个空格隔开。
样例输入
9 a0 b0 $1 c0 d0 $1 e1 f1 $1
样例输出
a f c b e d
大体思路:
1.根据输入的二叉树前序序列重建二叉树
2.把二叉树转化成树(我这里用的是动态孩子存储,你也可以用左孩子右兄弟)
3.前序遍历树,把每一个节点的孩子都逆序,实现镜面映射
4.层序遍历输出树
代码:(注释掉的print函数是用来测试的)
#include<iostream>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
typedef struct BinNode {
char data;
BinNode* lchild;
BinNode* rchild;
BinNode() {
data = '\0';
lchild = NULL;
rchild = NULL;
}
}BinNode;
typedef struct CSNode {
char data;
vector<CSNode*> children;//动态数组存储孩子节点
CSNode(int n) :data(n),children(vector<CSNode*>()){}
}CSNode;
CSNode* converse(BinNode* root) {//二叉树转成树(并返回对应树根节点)
if (root == NULL) return NULL;//一个二叉树节点的左孩子如果有右孩子(对应树中的兄弟),就把
vector<CSNode*> ve;//他左孩子所有的右孩子都作为他的孩子
CSNode* t = new CSNode(root->data);
BinNode* p = NULL;
if (root->lchild && root->lchild->data != '$') {//左孩子非空
p = root->lchild;
}
while (p && p->data!='$') {
ve.push_back(converse(p));
//if (p->rchild && p->rchild->data != '$')
p = p->rchild;
}
t->children = ve;
return t;
}
void printTree(CSNode* root) {//前序遍历打印树
if (root == NULL) return;
cout << root->data << " ";
for (int i = 0; i < root->children.size(); i++) {
printTree(root->children[i]);
}
}
void revert(CSNode* root) {//把给定节点的所有孩子节点逆序
if (root == NULL) return;
int len = root->children.size();
for (int i = 0; i < len / 2; i++) {
CSNode* tmp = root->children[i];
root->children[i] = root->children[len - i - 1];
root->children[len - i - 1] = tmp;
}
}
void mirror(CSNode* root) {//镜面映射树
if (root == NULL) return;
revert(root);
for (int i = 0; i < root->children.size(); i++) {
mirror(root->children[i]);
}
}
BinNode* rebuild(char x[],int num[],int n) {
stack<BinNode*> s;
BinNode* root = NULL;
for (int i = 0; i < n; i++) {
BinNode* r = new BinNode();
if (i == 0)
root = r;
BinNode* cur = NULL;
r->data = x[i];
if (!s.empty()) {
cur = s.top();
if (cur->lchild == NULL) {
cur->lchild = r;
r->data = x[i];
}
else if (cur->rchild == NULL) {
cur->rchild = r;
r->data = x[i];
}
if (cur->lchild && cur->rchild)
s.pop();
}
if (num[i] == 0 && x[i] != '$') {
s.push(r);
}
}
return root;
}
void bfsVisit(CSNode* root) {//层次遍历打印树
if (!root) return;
queue<CSNode*> q;
q.push(root);
while (!q.empty()) {
root = q.front();
q.pop();
cout << root->data << " ";
for (int i = 0; i < root->children.size(); i++)
q.push(root->children[i]);
}
}
void bfsVisit(BinNode* root) {//二叉树层次遍历
queue<BinNode*> q;
BinNode* tmp = root;
if (!tmp) return;
q.push(tmp);
//cout << tmp->data << " ";//先压一个进去,否则进不去循环
while (!q.empty()) {
//if (tmp == q.front()) q.pop();
tmp = q.front();
q.pop();
cout << tmp->data << " ";//出队列后再打印,否则最后一个元素没打印就出循环了
if (tmp->lchild)//放在最后弹队列,防止中间出现队列最后一个元素出来后
q.push(tmp->lchild);//其孩子没机会入队列就退出循环了
if (tmp->rchild)
q.push(tmp->rchild);
}
}
int main() {
int n;//节点数目
cin >> n;
char* x = new char[n]();
int* num = new int[n]();
for (int i = 0; i < n; i++) {
cin >> x[i];
cin >> num[i];
}
BinNode* root=rebuild(x,num,n);
//bfsVisit(root); cout << endl;
CSNode* t=converse(root);
//printTree(t);
mirror(t);
//printTree(t); cout << endl;
bfsVisit(t);
}