原理:前序遍历的第一个为根结点,在中序遍历中找到对应的结点位置后,在该位置左侧为根结点的左子树,在该位置右侧的为右子树,并可以找到在前序遍历中根结点左子树的的前序遍历和右子树的前序遍历,这两个数组的第一个就分别为根结点的左右孩子。
思路:一层一层的还原二叉树,还原一层的结点需要两种信息,上一层的所有结点,以及上一层每个结点左右孩子的信息。
还原算法以及前序、中序和后序遍历非递归算法
package ReconstructBinaryTree.core;
import java.util.ArrayList;
import java.util.LinkedList;
public class ReconstructBinaryTreeNode {
//由前序、中序遍历还原二叉树非递归算法
public static BinaryTreeNode constructTree(int[] preOrder, int[] inOrder) throws IsNotSameBinaryTree {
if (preOrder == null || inOrder == null) {
return null;
}
int totalLength = preOrder.length;
if (totalLength != inOrder.length) {
throw new IsNotSameBinaryTree("不是同一棵二叉树的遍历");
}
int[] queue1 = new int[6 * (totalLength + 1)];
//队列一和队列二作用相同,用来以6个数值为一组分别表示上一层结点的:
// 以左孩子为根前序遍历开始坐标,以左孩子为根中序遍历开始坐标,以及其对应的长度
// 以右孩子为根前序遍历开始坐标,以右孩子为根中序遍历开始坐标,以及其对应的长度
int rootValue = preOrder[0]; // 前序遍历的第一个结点为根结点
int j;
for (j = 0; j < totalLength; j++) {
if (inOrder[j] == rootValue) {
break;
}
}
if (inOrder[j] != rootValue) {
throw new IsNotSameBinaryTree("不是同一棵二叉树的遍历");
}
//在中序遍历中找根结点,若查找失败则说明这两个二叉树的遍历有问题
//给队列一填初值
queue1[0] = 1; //前序遍历第一个为根节点,所以在前序遍历结果中从下标为1开始,长度为queue[2]的数组是以根节点左孩子为根的前序遍历结果
queue1[1] = 0; //中序遍历第j个为根结点,所以在中序遍历结果中从下标为0开始, 长度为j-0的数组是以根结点左孩子为根的中序遍历结果
queue1[2] = j; //由前两个得长度为j-0,即j
queue1[3] = j + 1; //前序遍历第一个为根节点,所以在前序遍历结果中从下标为1+j开始,长度为queue[5]的数组是以根节点右孩子为根的前序遍历结果
queue1[4] = j + 1; //中序遍历第j个为根结点,所以在中序遍历结果中从下标为j+1开始, 长度为总长减去queue1[2]和一个根节点的数组是以根结点又孩子为根的中序遍历结果
queue1[5] = totalLength - j - 1; //所以这个长度为总长-queue1[2]-1
int[] queue2 = new int[6 * (totalLength + 1)];
ArrayList<BinaryTreeNode> layer1 = new ArrayList<>(); //用来装上一层的结点
ArrayList<BinaryTreeNode> layer2 = new ArrayList<>(); //存入下一层结点
BinaryTreeNode root = new BinaryTreeNode(rootValue);
layer1.add(root); //放入根结点
while (layer1.size() != 0) {
for (int i = 0; i < layer1.size(); i++) { //遍历上一层结点
for (int k = 2; k < 6; k += 3) { //每个结点都有它的左右孩子结点
if (queue1[i * 6 + k] > 0) { //若为null则跳过
int childValue = preOrder[queue1[i * 6 + k - 2]]; //前序遍历的第一个结点为根结点,也是上一层第i个结点的孩子结点,当k为2时是左孩子结点,当k为5时是右孩子结点
BinaryTreeNode child = new BinaryTreeNode(childValue);
if (k == 2) {
layer1.get(i).setLeftChild(child);
} else {
layer1.get(i).setRightChild(child);
}
layer2.add(child); //本层新产生的结点放入layer2里
for (j = queue1[i * 6 + k - 1]; j < queue1[i * 6 + k - 1] + queue1[i * 6 + k]; j++) { //在中序遍历中找到这个孩子结点
if (inOrder[j] == childValue) {
break;
}
}
if (inOrder[j] != childValue) {
throw new IsNotSameBinaryTree("不是同一棵二叉树的遍历");
}
//找到后分别在将这个孩子结点的左右孩子信息放入queue2里
int childCount = layer2.size() - 1;
queue2[childCount * 6] = queue1[i * 6 + k - 2] + 1; //孩子结点的左孩子的前序遍历开始下标
queue2[childCount * 6 + 1] = queue1[i * 6 + k - 1]; //孩子结点的左孩子的中序遍历开始下标
queue2[childCount * 6 + 2] = j - queue1[i * 6 + k - 1];//对应的长度
queue2[childCount * 6 + 3] = queue2[childCount * 6] + queue2[childCount * 6 + 2]; //孩子结点的右孩子的前序遍历开始下标
queue2[childCount * 6 + 4] = j + 1; //孩子结点的右孩子的中序遍历开始下标
queue2[childCount * 6 + 5] = queue1[i * 6 + k] - queue2[childCount * 6 + 2] - 1; //对应的长度
}
}
}
layer1.clear();
int[] queue = queue1;
queue1 = queue2;
queue2 = queue;
ArrayList<BinaryTreeNode> layer = layer1;
layer1 = layer2;
layer2 = layer;
}
return root;
}
private static int[] preOrder;
private static int[] inOrder;
//由前序、中序遍历还原二叉树递归算法
public static BinaryTreeNode reConstructTree(int[] preOrder, int[] inOrder) throws IsNotSameBinaryTree {
if (preOrder == null || inOrder == null) {
return null;
}
int totalLength = preOrder.length;
if (totalLength != inOrder.length) {
throw new IsNotSameBinaryTree("不是同一棵二叉数的遍历");
}
ReconstructBinaryTreeNode.preOrder = preOrder;
ReconstructBinaryTreeNode.inOrder = inOrder;
return reConstructTree(0, totalLength -1, 0 , totalLength-1);
}
private static BinaryTreeNode reConstructTree(int preStart, int preEnd, int inStart, int inEnd) throws IsNotSameBinaryTree {
int rootValue = ReconstructBinaryTreeNode.preOrder[preStart];
BinaryTreeNode root = new BinaryTreeNode(rootValue);
if (preStart == preEnd) {
if (inStart == inEnd && rootValue == ReconstructBinaryTreeNode.inOrder[inStart]) {
return root;
} else {
throw new IsNotSameBinaryTree("不是同一棵二叉树的遍历");
}
}
int i;
for (i = inStart; i <= inEnd; i++) {
if (ReconstructBinaryTreeNode.inOrder[i] == rootValue) {
break;
}
}
if (ReconstructBinaryTreeNode.inOrder[i] != rootValue) {
throw new IsNotSameBinaryTree("不是同一棵二叉树的遍历");
}
preStart += 1;
int length = i - inStart;
if (i > inStart) {
root.setLeftChild(reConstructTree(preStart,preStart + length - 1, inStart, i - 1));
}
if (i < inEnd){
root.setRightChild(reConstructTree(preStart + length, preEnd,i + 1,inEnd));
}
return root;
}
public static void prePrintBinaryTree(BinaryTreeNode root) {
if (root == null) {
return;
}
LinkedList<BinaryTreeNode> stack = new LinkedList<>();
BinaryTreeNode next = root;
while (stack.size() != 0 || next != null) {
if (next != null) {
stack.addFirst(next);
System.out.println(next.getValue());
next = next.getLeftChild();
} else {
next = stack.removeFirst();
next = next.getRightChild();
}
}
}
public static void inPrintBinaryTree(BinaryTreeNode root) {
if (root == null) {
return;
}
LinkedList<BinaryTreeNode> stack = new LinkedList<>();
BinaryTreeNode next = root;
while (stack.size() != 0 || next != null) {
if (next != null) {
stack.addFirst(next);
next = next.getLeftChild();
} else {
next = stack.removeFirst();
System.out.println(next.getValue());
next = next.getRightChild();
}
}
}
public static void lastPrintBinaryTree(BinaryTreeNode root) {
if (root == null) {
return;
}
LinkedList<BinaryTreeNode> stack = new LinkedList<>();
stack.addFirst(root);
BinaryTreeNode last = null;
while (stack.size() != 0) {
BinaryTreeNode first = stack.getFirst();
if ((first.getLeftChild() == null && first.getRightChild() == null)
|| (last != null && (last == first.getLeftChild() || last == first.getRightChild()))) {
stack.removeFirst();
System.out.println(first.getValue());
last = first;
} else {
if (first.getRightChild() != null) {
stack.addFirst(first.getRightChild());
}
if (first.getLeftChild() != null) {
stack.addFirst(first.getLeftChild());
}
}
}
}
}
测试程序
package ReconstructBinaryTree.Test;
import ReconstructBinaryTree.core.BinaryTreeNode;
import ReconstructBinaryTree.core.IsNotSameBinaryTree;
import ReconstructBinaryTree.core.ReconstructBinaryTreeNode;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入二叉树节点数");
Scanner scanner = new Scanner(System.in);
int count = scanner.nextInt();
while (true) {
if (count <= 0) {
System.out.println("请重新输入二叉节点数");
count = scanner.nextInt();
} else {
break;
}
}
System.out.println("请依次输入前序遍历和中序遍历");
int[] preOrder = new int[count];
int[] inOrder = new int[count];
for (int i = 0; i <count; i++) {
preOrder[i] = scanner.nextInt();
}
for (int i = 0; i < count; i++) {
inOrder[i] = scanner.nextInt();
}
try {
BinaryTreeNode root = ReconstructBinaryTreeNode.reConstructTree(preOrder, inOrder);
ReconstructBinaryTreeNode.lastPrintBinaryTree(root);
} catch (IsNotSameBinaryTree isNotSameBinaryTree) {
isNotSameBinaryTree.printStackTrace();
}
}
}