题目链接
思路:完全二叉树可以用数组存储,根节点的下标从1开始,根节点下标为i,左孩子和右孩子结点的下标分别为2i和(2i+1)。将输入的序列从小到大排列得到序列数组num,从根节点(下标为1)开始建树,对应的序列区间左端下标L=0,右端下标R=n-1:计算每个结点的左子树序列的长度i,就可以得到根节点在排序数组的下标[L+0],将num[L+0]存放在结果数组的对应位上,再递归处理左子树区间和右子树区间,递归参数就是对应区间的左右下标。得到的结果数组本身就是层次遍历序列,按序输出即可。
AC Code:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n,num[1000],result[1000];
void buildtree(int index,int L,int R){
//对排序数组中[L,R]区间进行建树,找到根节点放在结果数组的index位
if(L>R) return;//区间长度小于0,直接返回
int cnt=R-L+1,pos;//计算区间长度,左右子树区间分界点
int height=floor(log(cnt)/log(2))+1;//计算树的高度
if(cnt==pow(2,height)-1){//最后一层满的满二叉树
pos=(cnt-1)/2+L;//找到对应根节点的下标(前面有pos个数比它大)
result[index]=num[pos];//将得到的数据存放在结果数组中
}
else{//最后一层不满
int numbottom=min(cnt-pow(2,height-1)+1,pow(2,height-2));
//计算最后一层比当前根节点小的个数
pos=numbottom+(pow(2,height-1)-2)/2+L;
//当前树中比当前根节点小的个数,即排序数组的下标
result[index]=num[pos];
//找到根节点的数据域,将其存放在结果数组中
}
buildtree(2*index,L,pos-1);//递归处理左子树
buildtree(2*index+1,pos+1,R);//递归处理右子树
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",num+i);
}
sort(num,num+n);//对题给序列从小到大排序
buildtree(1,0,n-1);//从下标1(根节点)开始建树
for(int i=1;i<=n;i++){//输出层次序列
printf("%d",result[i]);
if(i<n) printf(" ");
}
return 0;
}