public class Tree {
public static void main(String[] args) {
int[] pre = {1, 2, 4, 7, 3, 5, 6, 8};
int[] mid = {4, 7, 2, 1, 5, 3, 8, 6};
int[] post = {7, 4, 2, 5, 8, 6, 3, 1};
TreeNode treeNode1 = preAndIn(pre, mid);
System.out.println(treeNode1);
TreeNode treeNode2 = inAndPost(mid, post);
System.out.println(treeNode2);
TreeNode treeNode3 = preAndPost(pre, post);
System.out.println(treeNode3);
showPre(treeNode1);
System.out.println("\r");
showIn(treeNode1);
System.out.println("\r");
showPost(treeNode1);
System.out.println("\r");
}
/**
* 前序遍历二叉树
* @param node
* @return void
* @date 2023/5/16 16:43
* @author: hwm
*/
public static void showPre(TreeNode node) {
if (node == null) {
return;
}
System.out.print(node.getData());
showPre(node.left);
showPre(node.right);
}
/**
* 中序遍历二叉树
* @param node
* @return void
* @date 2023/5/16 16:43
* @author: hwm
*/
public static void showIn(TreeNode node) {
if (node == null) {
return;
}
showIn(node.left);
System.out.print(node.getData());
showIn(node.right);
}
/**
* 后序遍历二叉树
* @param node
* @return void
* @date 2023/5/16 16:43
* @author: hwm
*/
public static void showPost(TreeNode node) {
if (node == null) {
return;
}
showPost(node.left);
showPost(node.right);
System.out.print(node.getData());
}
/**
* 根据二叉树的前序和中序遍历结果还原二叉树
* @param pre
* @param mid
* @return test.Tree.TreeNode
* @date 2023/5/16 16:37
* @author: hwm
*/
public static TreeNode preAndIn(int[] pre, int[] mid) {
if (pre.length == 0) {
return null;
}
// 先序第一位为当前子树的根
TreeNode node = new TreeNode(pre[0]);
if (pre.length == 1){
return node;
}
int rootIndex = -1;
// 查找根在中序中的位置,用于区分左子树和右子树
for (int i = 0; i < mid.length; i++) {
if (node.getData() == mid[i]) {
rootIndex = i;
break;
}
}
if (rootIndex == -1) {
// 异常情况直接退出
System.out.println("无法判定子树,自动退出");
System.out.println("pre:" + pre);
System.out.println("mid:" + mid);
return node;
}
// 先序第一位是根所以跳过,通过中序列中根的位置能确定左子树的元素长度,用来截取先序中左子树,Arrays.copyOfRange的第三个参数是闭区间(不包括)所以要加1,截取的元素是左子树的先序列
// 中序列中根的左侧就是左子树,所以从0-rootIndex就是左子树的中序列结果
node.left = preAndIn(Arrays.copyOfRange(pre,1,rootIndex + 1), Arrays.copyOfRange(mid, 0, rootIndex));
// 右子树的先序列就是rootIndex+1(+1是因为rootIndex位的元素是属于左子树的) -pre.length的结果,右子树的中序列类似
node.right = preAndIn(Arrays.copyOfRange(pre,rootIndex + 1, pre.length), Arrays.copyOfRange(mid, rootIndex + 1, mid.length));
return node;
}
/**
* 根据二叉树的中序和后序遍历结果还原二叉树
* @param mid
* @param post
* @return test.Tree.TreeNode
* @date 2023/5/16 17:01
* @author: hwm
*/
public static TreeNode inAndPost(int[] mid, int[] post) {
if (post.length == 0){
return null;
}
TreeNode node = new TreeNode(post[post.length - 1]);
if (post.length == 1){
return node;
}
int rootIndex = -1;
for (int i = 0; i < mid.length; i++) {
if (node.getData() == mid[i]) {
rootIndex = i;
break;
}
}
if (rootIndex == -1) {
// 异常情况直接退出
System.out.println("无法判定子树,自动退出");
System.out.println("mid:" + mid);
System.out.println("post:" + post);
return node;
}
node.left = inAndPost(Arrays.copyOfRange(mid, 0, rootIndex), Arrays.copyOfRange(post, 0, rootIndex));
node.right = inAndPost(Arrays.copyOfRange(mid, rootIndex + 1, mid.length), Arrays.copyOfRange(post, rootIndex, post.length - 1));
return node;
}
/**
* 根据二叉树的先序和后序遍历结果还原二叉树,非精确,由于缺少中序遍历,可能出现左右子树位置错误的情况(目前测试发现只发生在左或右子树为空的情况)
* @param pre
* @param post
* @return test.Tree.TreeNode
* @date 2023/5/16 17:01
* @author: hwm
*/
public static TreeNode preAndPost(int[] pre, int[] post) {
if (pre.length == 0){
return null;
}
TreeNode node = new TreeNode(pre[0]);
if (pre.length == 1){
return node;
}
int leftIndex = -1;
for (int i = 0; i < post.length; i++) {
if (pre[1] == post[i]) {
leftIndex = i;
break;
}
}
if (leftIndex == -1) {
// 异常情况直接退出
System.out.println("无法判定子树,自动退出");
System.out.println("pre:" + pre);
System.out.println("post:" + post);
return node;
}
// 先序和后序无法确定子树的根的位置,但是能通过先确定左子树,再圈定右子树,由遍历结果可以判定,先序第二位是左子树的根。
// 通过左子树的根 找到左子树根ai后序列中的位置,通过在后序列中的位置长度,圈定先序中左子树的范围,剩下的就是右子树,依此类推
node.left = preAndPost(Arrays.copyOfRange(pre, 1, leftIndex + 2), Arrays.copyOfRange(post, 0, leftIndex + 1));
node.right = preAndPost(Arrays.copyOfRange(pre, leftIndex + 2, pre.length), Arrays.copyOfRange(post, leftIndex + 1, post.length - 1));
return node;
}
@Data
static class TreeNode {
private int data;
private TreeNode left;
private TreeNode right;
public TreeNode(int data) {
this.data = data;
}
}
}
根据先序和后序还原二叉树,结果不精确。左子树或右子树为空的情况下,默认都会归为左子树
因为后序遍历是左右根,在左子树或右子树为空的情况下不能确定是左子树还是右子树,这里统一归为左子树
所以根据先序和后序还原二叉树只是二叉树的一种可能,并不能精确还原
参考文章:https://blog.csdn.net/baidu_39479284/article/details/120862098