重构方法参考文章【重构二叉树(Java实现):https://blog.youkuaiyun.com/wangbingcsu/article/details/51372695】
文章目录
- 二叉树类
- 三种遍历方式
- 前序遍历
- 中序遍历
- 后序遍历
- 两种重构方式
- 通过前序遍历中序遍历重构二叉树
- 通过后序遍历中序遍历重构二叉树
- 总代码
- 测试代码
二叉树类
这里我们创建一个二叉树的类,并为他添加一个插入的方法(左节点总是比父节点小,右节点总是比父节点大)
public class BinaryTree {
int data;
BinaryTree left;
BinaryTree right;
public BinaryTree(int data) {
this.data = data;
left = null;
right = null;
}
public void insert(BinaryTree root, int data) {//左节点总是比父节点小,右节点总是比父节点大
if (data > root.data) {
if (root.right == null) {
root.right = new BinaryTree(data);
} else {
this.insert(root.right, data);
}
} else {
if (root.left == null) {
root.left = new BinaryTree(data);
} else {
this.insert(root.left, data);
}
}
}
}
三种遍历方式
这三种遍历方式,相对的是根节点的遍历顺序。
前序遍历
1.访问根节点
2.前序遍历左子树
3.前序遍历右子树
public static void preOrder(BinaryTree root) {//前序遍历
if (root != null) {
System.out.print(root.data + ",");// 数据在同一行输出
preOrder(root.left);
preOrder(root.right);
}
}
中序遍历
1.中序遍历左子树
2.访问根节点
3.中序遍历右子树
public static void inOrder(BinaryTree root) {//中序遍历
if (root != null) {
inOrder(root.left);
System.out.print(root.data + ",");// 数据在同一行输出
inOrder(root.right);
}
}
后序遍历
1.后序遍历左子树
2.后序遍历右子树
3.访问根节点
public static void postOrder(BinaryTree root) {//后序遍历
if (root != null) {
postOrder(root.left);
postOrder(root.right);
System.out.print(root.data + ",");// 数据在同一行输出
}
}
两种重构方式
我们可以通过前序遍历和中序遍历重构出唯一的二叉树,也可以通过中序遍历和后序遍历重构出唯一的二叉树,
但是通过前序遍历和后序遍,无法重构出唯一的二叉树。
通过前序遍历中序遍历重构二叉树
- 值确定根节点:根据前序遍历的第一个值确定根节点
- 递归确定左子树
- 递归确定右子树
// 根据前序中序重构二叉树
public static BinaryTree reConstructBinaryTree1(int[] pre, int[] in) {
if (0 == pre.length || 0 == in.length)
return null;
// 先序遍历数组的第一个元素作为根节点
BinaryTree root = new BinaryTree(pre[0]);
for (int i = 0; i < in.length; ++i) {
if (root.data == in[i]) {
root.left = reConstructBinaryTree1(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));
root.right = reConstructBinaryTree1(Arrays.copyOfRange(pre, i + 1, pre.length),
Arrays.copyOfRange(in, i + 1, in.length));
}
}
return root;
}
通过后序遍历中序遍历重构二叉树
- 值确定根节点:根据后序遍历的最后一个值确定根节点
- 递归确定左子树
- 递归确定右子树
// 根据后序中序重构二叉树
public static BinaryTree reConstructBinaryTree2(int[] post, int[] in) {
if (0 == post.length || 0 == in.length)
return null;
BinaryTree root = new BinaryTree(post[post.length - 1]);
for (int i = 0; i < in.length; ++i) {
if (root.data == in[i]) {
root.left = reConstructBinaryTree2(Arrays.copyOfRange(post, 0, i), Arrays.copyOfRange(in, 0, i));
root.right = reConstructBinaryTree2(Arrays.copyOfRange(post, i, post.length - 1),
Arrays.copyOfRange(in, i + 1, in.length));
}
}
return root;
}
总代码
这里,为了省事,把二叉树三种遍历方式和两种重构方式都写在了这个类里。
public class BinaryTree {
int data;
BinaryTree left;
BinaryTree right;
public BinaryTree(int data) {
this.data = data;
left = null;
right = null;
}
public void insert(BinaryTree root, int data) {// 左节点总是比父节点小,右节点总是比父节点大
if (data > root.data) {
if (root.right == null) {
root.right = new BinaryTree(data);
} else {
this.insert(root.right, data);
}
} else {
if (root.left == null) {
root.left = new BinaryTree(data);
} else {
this.insert(root.left, data);
}
}
}
public static BinaryTree reConstructBinaryTree(int[] pre, int[] in) {// 根据前序中序重构二叉树
if (pre.length == 0 || in.length == 0) {
return null;
}
BinaryTree node = new BinaryTree(pre[0]);
for (int i = 0; i < in.length; i++) {
if (pre[0] == in[i]) {
node.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));
node.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length),
Arrays.copyOfRange(in, i + 1, in.length));
}
}
return node;
}
// 根据前序中序重构二叉树
public static BinaryTree reConstructBinaryTree1(int[] pre, int[] in) {
if (0 == pre.length || 0 == in.length)
return null;
// 先序遍历数组的第一个元素作为根节点
BinaryTree root = new BinaryTree(pre[0]);
for (int i = 0; i < in.length; ++i) {
if (root.data == in[i]) {
root.left = reConstructBinaryTree1(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));
root.right = reConstructBinaryTree1(Arrays.copyOfRange(pre, i + 1, pre.length),
Arrays.copyOfRange(in, i + 1, in.length));
}
}
return root;
}
public static BinaryTree reConstructBinaryTree2(int[] post, int[] in) {// 根据后序中序重构二叉树
if (0 == post.length || 0 == in.length)
return null;
BinaryTree root = new BinaryTree(post[post.length - 1]);
for (int i = 0; i < in.length; ++i) {
if (root.data == in[i]) {
root.left = reConstructBinaryTree2(Arrays.copyOfRange(post, 0, i), Arrays.copyOfRange(in, 0, i));
root.right = reConstructBinaryTree2(Arrays.copyOfRange(post, i, post.length - 1),
Arrays.copyOfRange(in, i + 1, in.length));
}
}
return root;
}
// 三种遍历方式
public static void preOrder(BinaryTree root) {// 前序遍历
if (root != null) {
System.out.print(root.data + ",");// 数据在同一行输出
preOrder(root.left);
preOrder(root.right);
}
}
public static void inOrder(BinaryTree root) {// 中序遍历
if (root != null) {
inOrder(root.left);
System.out.print(root.data + ",");// 数据在同一行输出
inOrder(root.right);
}
}
public static void postOrder(BinaryTree root) {// 后序遍历
if (root != null) {
postOrder(root.left);
postOrder(root.right);
System.out.print(root.data + ",");// 数据在同一行输出
}
}
}
测试
这里为了省事,测试类直接继承二叉树类,进行测试。
public class BinaryTreeTest extends BinaryTree {
public BinaryTreeTest(int data) {
super(data);
}
public static void main(String[] args) {
testReConstruct();
}
public static void testReConstruct() {// 测试重构二叉树
int[] pre = { 12, 9, 76, 35, 22, 16, 48, 46, 40, 90 };
int[] in = { 9, 12, 16, 22, 35, 40, 46, 48, 76, 90 };
int[] post = { 9, 16, 22, 40, 46, 48, 35, 90, 76, 12, };
BinaryTree root = reConstructBinaryTree2(post, in);
postOrder(root);
}
public static void testOrder() {// 测试三种遍历
int[] list = { 12, 76, 35, 22, 16, 48, 90, 46, 9, 40 };
BinaryTree root = new BinaryTree(list[0]);
for (int i = 1; i < list.length; i++) {
root.insert(root, list[i]);
}
preOrder(root);
System.out.println();// 换行
inOrder(root);
System.out.println();// 换行
postOrder(root);
}
}