题目
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是完美二叉树。对于深度为 D 的,有 N 个结点的二叉树,若其结点对应于相同深度完美二叉树的层序遍历的前 N 个结点,这样的树就是完全二叉树。
给定一棵完全二叉树的后序遍历,请你给出这棵树的层序遍历结果。
输入格式:
输入在第一行中给出正整数 N(≤30),即树中结点个数。第二行给出后序遍历序列,为 N 个不超过 100 的正整数。同一行中所有数字都以空格分隔。
输出格式:
在一行中输出该树的层序遍历序列。所有数字都以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
8
91 71 2 34 10 15 55 18
输出样例:
18 34 55 71 2 10 15 91
朴素思路
输入给出的是完全二叉数的后序遍历,因为是完全二叉树,所以我们可以很简单的通过dfs(深度优先遍历)来模拟建树,把树建出来后,再通过bfs(广度优先遍历)来得到层序遍历。
完全二叉树的性质之一:
有n个节点的完全二叉树,对各个节点从上到下,从左到右依次编号,则节点之间编号的关系为:【设i为某个节点的编号,则有:该节点左子树的编号为2i,右子树的编号为2i+1】,这个编号顺序恰好就是层序遍历的顺序。
代码
import java.util.*;
public class Main {
static int n,index=0;
static int []a;
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
n=in.nextInt();
a=new int[n];
for(int i=0;i<n;++i){
a[i]=in.nextInt();
}
//建树,并拿到根节点
Node root=dfs(1);
Queue<Node> q=new LinkedList<>();//用于bfs的队列
StringBuilder res = new StringBuilder();//用于存储答案的可变字符串对象
//bfs部分
q.add(root);
while(!q.isEmpty()){
Node node=q.poll();
if(node!=null){
q.add(node.l);
q.add(node.r);
res.append(node.value+" ");
}
}
res.deleteCharAt(res.length()-1);//因为行尾不能有空格,所以删掉最后的空格
System.out.println(res);
}
static Node dfs(int i){
if(i>n)return null;
Node node=new Node();
//后续遍历:左、右、中
node.l=dfs(i<<1);//用位运算代替乘法和加法运算,速度更快
node.r=dfs(i<<1|1);
node.value=a[index++];
return node;
}
//节点类
static class Node{
Node l,r;
int value;
}
}
优化思路
因为完全二叉树的性质(上文提到过),可以比较方便的用数组来保存一个完全二叉树,所以可以直接在dfs中将节点值保存到结果数组的对应位置上。
优化代码
import java.util.*;
public class Main {
static int n,index=0;
static int []a,b;
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
n=in.nextInt();
a=new int[n];
b=new int[n+1];
for(int i=0;i<n;++i){
a[i]=in.nextInt();
}
dfs(1);
for(int i=1;i<n;++i){
System.out.print(b[i]+" ");
}
System.out.println(b[n]);
}
static void dfs(int i){
if(i>n)return;
dfs(i<<1);
dfs(i<<1|1);
b[i]=a[index++];
}
}