0%

逆推二叉树

逆推二叉树

根据中序、后序得到二叉树。根据中序、前序得到二叉树。

二叉树的层序遍历

​ 假设现在有一颗二叉树如下

img

其中序遍历为: CBAEDF (左 - 根- 右)

其后序遍历为:CBEFDA (左 - 右 - 根)

其前序遍历为:ABCDEF (根 - 左 - 右)

如果我们现在只知道中序和后序,或者中序和前序。如何构建出二叉树。

假设已知中序和后序,构建过程如下。

1
2
3
4
5
1. 根据后序(CBEFDA), 可以知道根节点为最后一个节点。即节点A。
2. 拿到根节点A以后,根据中序(CBAEDF), A左边的是A的左子树,A右边的是A的右子树。
3. 根据根节点的位置来判断左子树和右子树的左右边界条件,以便于后续二叉树构建。
4. 分别递归构建左子树和右子树。
5. 返回根节点。

参数定义:

inorderStartIndex: 构建子树时,中序遍历数组中的起始位置;

inorderEndIndex: 构建子树时,中序遍历数组中的结束位置;

postorderStartIndex: 后序遍历数组中的起始位置;

postorderEndIndex: 后序遍历数组中的结束位置。

rootIndex: 当前构建树的根节点在中序数组中的index

每次递归构建子树时的起始下标和结束下标的计算:

根据中序遍历,根节点位置确定以后,根节点左边为左子树,右边为右子树。那么就需要确定左子树的起始边界和右子树的起始边界。

img

已知A左边的就是左子树,所以对应的后序遍历数组中,下一次遍历左右起始位置如下

1
2
3
4
5
6
1. 左子树:
中序数组: 起始位置: inorderStartIndex 结束位置: rootIndex-1
后序数组: 起始位置: postorderStartIndex 结束位置: postorderStartIndex + (rootIndex - inorderStartIndex) - 1
2. 右子树:
中序数组: 起始位置: rootIndex+1 结束位置: inorderEndIndex
后序数组: 起始位置: postorderStartIndex + (rootIndex - inorderStartIndex) 结束位置: postorderEndIndex

假设已知中序和前序

与上述一样,只是在确定起始位置的时候有所不同。

img

根据前序可以知道根节点。即为前序数组的第一个元素。则计算的起始位置为:

1
2
3
4
5
6
1. 左子树:
中序数组: 起始位置: inorderStartIndex 结束位置: rootIndex-1
后序数组: 起始位置: postorderStartIndex 结束位置: postorderStartIndex + (rootIndex - inorderStartIndex) - 1
2. 右子树:
中序数组: 起始位置: rootIndex+1 结束位置: inorderEndIndex
后序数组: 起始位置: postorderStartIndex + (rootIndex - inorderStartIndex) 结束位置: postorderEndIndex

代码

定义树节点

1
2
3
4
5
6
7
8
9
class TreeNode<T> {
T val;
TreeNode left;
TreeNode right;

public TreeNode(T val) {
this.val = val;
}
}

中序+后序

为了方便在中序数组中获取到根节点的索引,可以把中序遍历的所有数据放在一个map里面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
private Map<Character, Integer> indexMap = new HashMap<>();

/**
* 根据后序和中序构建二叉树
*
* @param postorder
* @param inorder
* @return
*/
private TreeNode<Character> getTreeByInorderAndPostorder(String postorder, String inorder) {
for (int i = 0; i < inorder.length(); i++) {
indexMap.put(inorder.charAt(i), i);
}
return buildTreeByInorderAndPostorder(0, inorder.length() - 1, 0, posts.length - 1, postorder.toCharArray());
}

private TreeNode<Character> buildTreeByInorderAndPostorder(int inorderStartIndex, int inorderEndIndex, int postorderStartIndex, int postorderEndIndex, char[] posts) {
// 边界条件
if (inorderStartIndex > inorderEndIndex || postorderStartIndex > postorderEndIndex) {
return null;
}
// 从后序中获取到根节点的值
char rootVal = posts[postorderEndIndex];
// 从中序中获取到根节点在中序的索引
int rootIndex = indexMap.get(rootVal);
TreeNode<Character> root = new TreeNode<>(rootVal);
root.left = buildTreeByInorderAndPostorder(inorderStartIndex, rootIndex - 1, postorderStartIndex, postorderStartIndex + rootIndex - inorderStartIndex - 1, posts);
root.right = buildTreeByInorderAndPostorder(rootIndex + 1, inorderEndIndex, postorderStartIndex + rootIndex - inorderStartIndex, postorderEndIndex - 1, posts);
return root;
}
}

中序+前序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private TreeNode<Character> getTreeByInorderAndPreorder(String inorder, String preorder) {
for (int i = 0; i < inorder.length(); i++) {
indexMap.put(inorder.charAt(i), i);
}
return buildTreeByInorderAndPreorder(0, inorder.length() - 1, 0, preorder.length() - 1, preorder.toCharArray());
}

private TreeNode<Character> buildTreeByInorderAndPreorder(int inorderStartIndex, int inorderEndIndex,
int preorderStartIndex, int preorderEndIndex,
char[] preorder) {
if (inorderStartIndex > inorderEndIndex || preorderStartIndex > preorderEndIndex) return null;
char rootVal = preorder[preorderStartIndex];
int rootIndex = indexMap.get(rootVal);
TreeNode<Character> root = new TreeNode<>(rootVal);
root.left = buildTreeByInorderAndPreorder(inorderStartIndex, rootIndex - 1, preorderStartIndex + 1, preorderStartIndex + rootIndex - inorderStartIndex, preorder);
root.right = buildTreeByInorderAndPreorder(rootIndex + 1, inorderEndIndex, preorderStartIndex + rootIndex - inorderStartIndex + 1, preorderEndIndex, preorder);
return root;
}

二叉树的层次遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 /**
* 层次遍历
*
* @param root 根节点
* @return
*/
private String levelTraverse(TreeNode<Character> root) {
StringBuilder sb = new StringBuilder();
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode<Character> node = queue.poll();
sb.append(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
}
return new String(sb);
}
-------------本文结束感谢您的阅读-------------