二叉树的两种创建方式
在写之前,首先明确一点:
如
果
说
只
有
前
后
序
遍
历
那
么
是
不
能
够
创
建
二
叉
树
的
,
必
须
有
中
\color{red}{如果说只有前后序遍历那么是不能够创建二叉树的,必须有中}
如果说只有前后序遍历那么是不能够创建二叉树的,必须有中
序
遍
历
才
能
创
建
二
叉
树
\color{red}{序遍历才能创建二叉树}
序遍历才能创建二叉树
第一种:根据前序和中序遍历构建二叉树
题目来源:
从前序与中序遍历序列构造二叉树
不论那种方法构造二叉树,我们的总体思路基本是相同的,但是就是在细节方法会有一点点不同。
我们都知道,前序遍历的的顺序是:
[根节点] [左子树的前序遍历结果] [右子树的前序遍历结果]
而中序遍历的结果是:
[左子树的中序遍历结果] [根节点] [右子树的中序遍历结果]
那么我们就需要在中序遍历中找出根节点,然后对左右子树的位置进行定位。这样一来,我们就知道了左子树和右子树的前序遍历和中序遍历结果,然后将其转接到左右子树的位置。接着对左右子树都是如此,不断递归。
那么具体的代码如下:
class Solution {
//定义preorder的下标用来遍历前序数组
int index;
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n =preorder.length;
return rebuildTree(preorder,inorder,0,n);
}
public TreeNode rebuildTree(int[] preorder,int[] inorder,int inleft,int inright){
//设置临界条件
if(index == preorder.length || inleft >= inright){
return null;
}
//寻找中序遍历的根节点
int pos = 0;
while(pos < inright){
if(inorder[pos] == preorder[index]){
break;
}
pos++;
}
//设置根节点
int rootvalue = preorder[index];
index++;
TreeNode root = new TreeNode(rootvalue);
//设置左子树
root.left = rebuildTree(preorder,inorder,inleft,pos);
//设置右子树
root.right = rebuildTree(preorder,inorder,pos+1,inright);
return root;
}
但是注意,这种方法缺点还是很明显的。
1.每一次的递归都要while寻找根节点一次,计算量增大
2.这种方法只能适用于没有重复值的数组
为了解决上述的第一个问题,那么我们可以用哈希映射来解决,但是第二个问题,目前笔者没有很好的思路。
第二种:根据中序和后序遍历构建二叉树
题目来源:
中序遍历的顺序:
[左子树的中序遍历] [根节点] [右子树的中序遍历]
后序遍历的顺序:
[左子树的后序遍历] [根节点] [右子树的中序遍历]
注意这种构建二叉树的思想其实和上面是一样的,但是细节处稍微有点不同,后序遍历的最后一位才是根节点,所有我们从后往前遍历,这就意味着我们需要先构建右子树然后再构建左子树。具体代码如下:
class Solution {
int index;
public TreeNode buildTree(int[] inorder, int[] postorder) {
index = postorder.length - 1;
return rebuildTree(inorder,postorder,0,inorder.length - 1);
}
public TreeNode rebuildTree(int[] inorder, int[] postorder,int inleft,int inright){
//设置临界条件
if(index < 0 || inleft > inright){
return null;
}
//寻找根节点
int pos = inleft;
while(pos <= inright){
if(inorder[pos] == postorder[index]){
break;
}
pos++;
}
//设置根节点
int rootVal = postorder[index];
TreeNode root = new TreeNode(rootVal);
index--;
//设置右子树
root.right = rebuildTree(inorder,postorder,pos + 1,inright);
//设置左子树
root.left = rebuildTree(inorder,postorder,inleft,pos-1);
return root;
}
}
同样,这种方式和上面的缺陷一样,如果改进的话需要用哈希映射来进行查找,而且如果数组有重复元素就会出错。