最近笔试题一直遇到这个题,今天就总结一下。本文主要回答以下几个问题(Java实现):
- 前序 + 中序 => 后序 + 层序
- 后序 + 中序 => 前序 + 层序
- 以上2个问题的2种解决办法(a. 手写出二叉树 b. 编程实现)
先看以下3种遍历的特点:
特点:
- 前序的第一个是root,后序的最后一个是root。
- 每种排序左子树右子树分布都是有规律的,见上图。
- 对于每一个子树(左/右)可以看成一个全新的树,仍然遵循上面的规律。
根据上面的特点,可以解决问题(核心都是中序的结构特点:可以明确区分出左子树右子树的位置):
前+中=>后+层:
- 前序的第一个就是root,对应找到中序中根的位置,那么中序根前面的就是左子树,后面的就是右子树。
- 数一下左子树右子树的元素个数,对应在前序中找到左子树右子树的位置,如上图标示。
- 那么,下面对于左子树右子树又是一个全新的树,仍然按照以上规律,即在前序左子树L中,第一个元素B是root(同时也是父节点A的左节点),在前序右子树R中,第一个元素C是root(同时也是父节点A的右节点)……
- 重建出二叉树之后,后序/层序就是遍历就OK了。
后+中=>前+层:(类似上面的方法,就是后序的根节点在尾部,相应的左子树/右子树的根节点B/C在尾部,见上图所示。)
具体解决办法:
- 若是选择题,直接手写出二叉树,有了二叉树之后,什么序都秒秒钟的事。
- 若是编程题,那就要动手实现了,具体有2个思路:a. 直接递归打印各种序的排列(不用重建二叉树)。 b. 先重建出二叉树,再各种序的遍历打印。
实现:
手写:
代码实现:
直接递归打印,不用重建二叉树
前序+中序=>后序
public class PreOrderAndInOrder {
/**
*
* @param pre_bg_index 前序数组中,开始的索引(具体到左(右)子树中,数组开始索引+长度len精确指定了某一个左(右)子树)
* @param in_bg_index 中序数组中,开始的索引
* @param len 树(左(右)子树对应到数组中的长度)
* @param pre_Order_Array 前序数组
* @param in_Order_Array 中序数组 (这里一直把前序中序数组当做参数,是由于在递归过程中,没有动过数组,只是动态的去其中的某些项。)
*/
public static void postOrderSolution(int pre_bg_index, int in_bg_index, int len, char[] pre_Order_Array, char[] in_Order_Array) {
if (len == 0)
return;
char root = pre_Order_Array[pre_bg_index];
if (len==1){//递归出口。
System.out.print(root+" ");
return;
}
int i = 0;
while (root != in_Order_Array[in_bg_index + i]) {//找到中序根节点的位置。
i++;
}
//左右中,标准的后序遍历的形式。
postOrderSolution(pre_bg_index+1, in_bg_index, i, pre_Order_Array, in_Order_Array);
postOrderSolution(pre_bg_index+i+1, in_bg_index+i+1, len-i-1, pre_Order_Array, in_Order_Array);
System.out.print(root+" ");
}
public static void main(String[] args){
char[] pre_Order_Array = {'A','B','D','E','H','C','F','G','I'};
char[] in_Order_Array = {'D','B','H','E','A','F','C','G','I'};
postOrderSolution(0, 0, pre_Order_Array.length, pre_Order_Array, in_Order_Array);
}
}
后序+中序=>前序(与上面大体类似,就是后序的下标用于定位根节点的位置与前序不同)
public class InOrderAndPostOrder {
/**
*
* @param post_end_index 后序数组中,结束的索引(具体到左(右)子树中,数组结束索引+长度len精确指定了某一个左(右)子树)
* @param in_bg_index 中序数组中,开始的索引
* @param len 树(左(右)子树对应到数组中的长度)
* @param post_Order_Array 后序数组
* @param in_Order_Array 中序数组 (这里一直把前序中序数组当做参数,是由于在递归过程中,没有动过数组,只是动态的去其中的某些项。)
*/
public static void preOrderSolution(int post_end_index, int in_bg_index, int len, char[] post_Order_Array, char[] in_Order_Array) {
if (len == 0)
return;
char root = post_Order_Array[post_end_index];
if (len==1){//递归出口。
System.out.print(root+" ");
return;
}
int i = 0;
while (root != in_Order_Array[in_bg_index + i]) {//找到中序根节点的位置。
i++;
}
//中左右,标准的前序遍历的形式。注意左子树中后序结束的索引是从后往前减的,中间减掉的(len-i-1)是右子树对应的数组长度。
System.out.print(root+" ");
preOrderSolution(post_end_index-(len-i-1)-1, in_bg_index, i, post_Order_Array, in_Order_Array);
preOrderSolution(post_end_index-1, in_bg_index+i+1, len-i-1, post_Order_Array, in_Order_Array);
}
public static void main(String[] args){
char[] post_Order_Array = {'D','H','E','B','F','I','G','C','A'};
char[] in_Order_Array = {'D','B','H','E','A','F','C','G','I'};
preOrderSolution(post_Order_Array.length-1, 0, post_Order_Array.length, post_Order_Array, in_Order_Array);
}
}
重建二叉树,然后各种序遍历输出,这里以 前序+中序=>后序+层序 为例:
public class TreeNode {
char val;
TreeNode left;
TreeNode right;
public TreeNode(char val) {
this.val = val;
}
}
public class ReConstructPreAndIn {
/**
* @param pre_bg_index 前序数组中,开始的索引(具体到左(右)子树中,数组开始索引+长度len精确指定了某一个左(右)子树)
* @param in_bg_index 中序数组中,开始的索引
* @param len 树(左(右)子树对应到数组中的长度)
* @param pre_Order_Array 前序数组
* @param in_Order_Array 中序数组 (这里一直把前序中序数组当做参数,是由于在递归过程中,没有动过数组,只是动态的去其中的某些项。)
*/
public static TreeNode reConstruct(int pre_bg_index, int in_bg_index, int len, char[] pre_Order_Array, char[] in_Order_Array) {
if (len == 0)
return null;
char root = pre_Order_Array[pre_bg_index];
if (len == 1) {//递归出口。
TreeNode newNode = new TreeNode(root);
return newNode;
}
int i = 0;
while (root != in_Order_Array[in_bg_index + i]) {//找到中序根节点的位置。
i++;
}
TreeNode node = new TreeNode(root);
node.left = reConstruct(pre_bg_index + 1, in_bg_index, i, pre_Order_Array, in_Order_Array);
node.right = reConstruct(pre_bg_index + i + 1, in_bg_index + i + 1, len - i - 1, pre_Order_Array, in_Order_Array);
return node;
}
//后序遍历
public static void postOrderTransverse(TreeNode root) {
if (root == null)
return;
if (root.left == null && root.right == null) {
System.out.print(root.val + " ");
return;
}
postOrderTransverse(root.left);
postOrderTransverse(root.right);
System.out.print(root.val + " ");
}
//层序遍历
public static void levelOrderTransverse(TreeNode root){
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
TreeNode node;
while (!queue.isEmpty()){
node = queue.peek();
System.out.print(node.val+" ");
queue.poll();
if(node.left!=null)
queue.add(node.left);
if(node.right!=null)
queue.add(node.right);
}
}
public static void main(String[] args) {
char[] pre_Order_Array = {'A', 'B', 'D', 'E', 'H', 'C', 'F', 'G', 'I'};
char[] in_Order_Array = {'D', 'B', 'H', 'E', 'A', 'F', 'C', 'G', 'I'};
TreeNode root = reConstruct(0, 0, pre_Order_Array.length, pre_Order_Array, in_Order_Array);
postOrderTransverse(root);
System.out.println();
levelOrderTransverse(root);
}
}
End