问题描述
二叉树可以用于排序。其原理很简单:对于一个排序二叉树添加新节点时,先与根节点比较,若小则交给左子树继续处理,否则交给右子树。
当遇到空子树时,则把该节点放入那个位置。
比如,10 8 5 7 12 4 的输入顺序,应该建成二叉树如下图所示,其中.表示空白。
…|-12
10-|
…|-8-|
…|…|-7
…|-5-|
…|-4
本题目要求:根据已知的数字,建立排序二叉树,并在标准输出中横向打印该二叉树。
输入格式
输入数据为一行空格分开的N个整数。 N<100,每个数字不超过10000。
输入数据中没有重复的数字。
输出格式
输出该排序二叉树的横向表示。为了便于评卷程序比对空格的数目,请把空格用句点代替:
样例输入1
10 5 20
样例输出1
…|-20
10-|
…|-5
样例输入2
5 10 20 8 4 7
样例输出2
…|-20
…|-10-|
…|…|-8-|
…|…|-7
5-|
…|-4
解题思路见代码:(PS我是参考的某大牛的解法,为了加深印象自己亲自写了一遍,加了非常多的注释。。。题不难就是很麻烦。。。)
//所用数据结构:
//该解法在表示二叉树的数据结构上采用了结构体数组
//的表示方法,每个节点按照输入顺序存入结构体数组。
//每个节点的左右子树根节点为在结构体数组中的编号。
//算法过程见注释
#include<iostream>
#include<sstream>
const int maxn = 200;
struct node{
int left,right; //左右子节点在结构体数组中的下标号
int left_s,right_s; //左右子树节点数
int v,id,ak;//v表示值,id表示横向打印时该节点在第几行,ak表示v的长度
char a[10];//用于存放v的字符串形式
}Nodes[maxn];
char map[maxn][maxn]; //用于存放要打印的横向二叉树
using namespace std;
void BinaryTree_set(int rt,int k){ //构建排序二叉树,rt表示根节点,k表示要插入的节点
if(Nodes[k].v > Nodes[rt].v){ //插入节点数值大于根节点数值时
Nodes[rt].right_s++; //根节点的右子树节点数会增加1
if(Nodes[rt].right != -1){ //判断根节点的右子树是否存在
BinaryTree_set(Nodes[rt].right,k); //递归以右子树的根节点为根节点插入k节点
}else{ //右子树不存在
Nodes[rt].right = k;//直接将当前根节点的右子树为k
}
}else{//同理
Nodes[rt].left_s++;
if(Nodes[rt].left != -1){
BinaryTree_set(Nodes[rt].left,k);
}else{
Nodes[rt].left = k;
}
}
}
void Set_id(int rid,int k){ //计算各节点打印在第几行 rid表示当前处于第几行,k为要进行计算的节点
Nodes[k].id = rid + Nodes[k].right_s + 1; //保证打印的行不从第0行开始
if(Nodes[k].right != -1){
Set_id(rid,Nodes[k].right);//当右子树存在时,那么就计算右子树根节点处于第几行,
//此时rid应该为参数传进来的rid,因为右子树会优先打印,
//右子树是以他父节点的参照物为参照物,他父节点的参照物正好为rid
}
if(Nodes[k].left != -1){
Set_id(Nodes[k].id,Nodes[k].left); //由于是左子树,相对于父节点打印的晚,
//他的参照物为父节点打印时所在的行
}
}
void Map_set(int k,int index){ //构建要打印的横向二叉树,存在map中 k表示处理的节点号,
//index为k节点从map第几列开始存放
for(int i = 0;i < Nodes[k].ak;i++){ //把k节点的值存放在map中
map[Nodes[k].id][index + i] = Nodes[k].a[Nodes[k].ak - i - 1];
}
index += Nodes[k].ak; //更新index,指向字符串后一位
if(Nodes[k].right != -1 || Nodes[k].left != -1){ //当k节点有左右孩子时
map[Nodes[k].id][index++] = '-';
int max = Nodes[k].id;//用于保存k节点左子树所在行数
int min = Nodes[k].id; //用于保存k节点右子树所在行数
if(Nodes[k].right != -1){//右子树存在
min = Nodes[Nodes[k].right].id; //保存右子树根节点的行数
map[Nodes[Nodes[k].right].id][index + 1] = '-';//在右子树所在行的位置放入'-'
Map_set(Nodes[k].right,index + 2); //递归进行又开始处理右子树根节点,其存入位置为index+2
}
if(Nodes[k].left != -1){//同理
max = Nodes[Nodes[k].left].id;
map[Nodes[Nodes[k].left].id][index + 1] = '-';
Map_set(Nodes[k].left,index + 2);
}
for(int i = min; i <= max;i++){ //通过min和max知道左右子树根节点的行数,min行到max行放入'|'
map[i][index] = '|';
}
map[Nodes[k].id][index + 1] = '\0'; //该节点所在行处理完后,加入行尾结束符
}else{
map[Nodes[k].id][index] = '\0';//该节点所在行处理完后,加入行尾结束符
return;
}
}
int main(){
string s;
getline(cin,s);
istringstream ss(s);
int e;
int n = 0;
int A[maxn];
while(ss >> e){ //读取输入值
A[n++] = e;
}
for(int i = 0;i < n;i++){
int e = A[i];
Nodes[i].right = Nodes[i].left = -1;
Nodes[i].right_s = Nodes[i].left_s = 0;
Nodes[i].v = e;
Nodes[i].ak = 0;
while(e){ //把v转换成字符串存到a中,同时计算出ak
Nodes[i].a[Nodes[i].ak++] = e % 10 + '0';
e = e / 10;
}
}
for(int i = 1;i < n;i++){
BinaryTree_set(0,i);
}
Set_id(0,0);
for(int i = 1;i < maxn;i++){
for(int j = 0;j < maxn;j++){
map[i][j] = '.';
}
}
Map_set(0,0);
for(int i = 1;i <=n;i++){
cout<<map[i]<<endl;
}
return 0;
}