树结构如下所示。
class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(){};
public TreeNode(int val){
this.val = val;
}
}
二叉树的建树逻辑一般可以采用后序遍历的逻辑,先创建父结点,然后通过递归的方式得到左右孩子结点,最后将父节点返回。
给定集合建立二叉树
给定一个list集合[1,2,None,None,3,4,None,None,5,None,None],根据该集合建立如下图所示二叉树。
public TreeNode build(LinkedList<String> list) {
if(list.get(0).equals("None")){
list.remove(0);
return null;
}else{
TreeNode node = new TreeNode(Integer.valueOf(list.get(0)));
list.remove(0);
node.left = bulid(list);
node.right = bulid(list);
return node;
}
}
首先,获取list的第一个元素1,判断1不等于None,进入else,利用TreeNode的有参构造,创建根节点,将list中首元素即1移除。之后递归方式得到左右孩子结点。先看left,递归进入bulid方法,获取list首元素2,创建结点,移除元素2,先看left,递归进入build方法,获取list首元素None,删除None,并返回null,2元素的left为null,在看2结点的right,获取list元素None,删除None,返回null,2元素的right为null,2结点bulid方法递归结束,返回2结点赋值给根节点1的left,left递归结束,递归根节点1的right。right和left同理,最终就可以建立一棵二叉树。
给定有序数组建立二叉搜索树
给出一个示例为[-10,-3,0,5,9],建立如下图所示二叉搜索树。基本思路为:
- 选取有序数组的中间元素作为父结点
- 根据父结点在数组中的位置,得到左子树和右子树对应的有序数组序列
- 同样思路递归得到左右子节点
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return helper(nums, 0, nums.length - 1);
}
private TreeNode helper(int[] nums, int left, int right){
if(left > right) return null;
int mid = (left + right) / 2;
int val = nums[mid];
TreeNode node = new TreeNode(val);
node.left = helper(nums, left, mid - 1);
node.right = helper(nums, mid + 1, right);
return node;
}
}
首先sortedArrayToBST方法调用helper方法,进入helper方法,left为0,right为4,mid的值为2,将下标2对应的值0建立树结点,递归建立左右子结点,先看左节点,递归调用helper,left为0,right为1,mid为0,选取下标0对应的值-10建立树结点,之后递归结点-10左右子结点,左节点helper传入left为0,right为-1,left>right,返回null,-10左结点left赋值为null,右结点helper传入left为1,right为1,left>right不成立,mid为1,将下标为1的元素-3建立树结点,之后递归下标元素为-3的左右子节点,左节点helper传入left为1,right为0,递归结束,-3左结点赋值为null,右结点helper传入left为2,right为1,递归结束,-3右节点赋值为null,-3的helper方法运行结束,将-3的结点返回给-10结点的右结点,-10结点右结点递归结束,-10结点helper方法运行结束,赋值给根节点1的左节点,根节点左子树建立完成,同样的步骤能够得到根节点的右子树。
给定前序和中序序列遍历建立二叉树
先给出示例,先序遍历序列为[3,9,20,15,7], 中序遍历序列为[9,3,15,20,7]。基本思路为:
- 从左到右遍历先序序列,获取先序序列的元素,建立树结点
- 找出先序序列元素在中序序列中的位置,从而划分左右子树
- 按第一、二步规则递归遍历左右子树
class Solution {
Map<Integer, Integer> map = new HashMap<>();
int[] preorder;
int[] inorder;
int idx;
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder = preorder;
this.inorder = inorder;
this.idx = 0;
for(int i = 0;i < inorder.length;i++){
map.put(inorder[i], i);
}
return helper(0, inorder.length - 1);
}
private TreeNode helper(int l, int r){
if(l > r) return null;
int val = preorder[idx];
idx++;
TreeNode node = new TreeNode(val);
int i = map.get(val);
node.left = helper(l, i - 1);
node.right = helper(i + 1, r);
return node;
}
}
上述代码主要有两个方法,一个方法是buildTree,在该方法中主要工作就是有哈希表保存中序序列中每个结点对应的下标位置,方便切分为左右子序列。并调用helper方法返回二叉树。helper方法中,传递left为0,right为5,首先从先序遍历中获取首个元素,为3,并建立树结点,根据哈希表找出结点3在中序序列中的下标,划分左侧序列为[9],右侧序列为[15,20,7]。看右侧,左侧类似,且相对右侧比较简单。直接进入根结点right的递归helper,传递left为2,right为5,此时,先序序列中idx指向了元素20,建立结点值为20的树结点,之后根据哈希表找到中序序列中20所在位置,得到左侧序列[15]和右侧序列[7],递归进入结点20的left,传递left为2,right为2,从前序序列中继续获取结点值为15,建立树结点,递归进入结点值为15的left,传递left为2,right为1,满足left>right,返回null,结点值为15的left赋值为null,递归进入15的right,传递left为3,right为2,满足left>right,结点值为15的right赋值为null,15结点helper方法结束,返回结点15赋值给结点20的left,同理递归20的right,将结点7赋值给结点20的right。结点20的helper方法结束,返回结点20赋值给根节点的right。
给定中序和后序序列遍历建立二叉树
这个代码与给定前序和中序序列建立二叉树实现逻辑相同,不同之处如下:
- 需要从右到左遍历后序数组
- 先递归遍历右子树,后遍历左子树
class Solution {
int[] postorder;
int[] inorder;
int post_idx;
Map<Integer, Integer> map;
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.post_idx = postorder.length - 1;
this.postorder = postorder;
this.inorder = inorder;
this.map = new HashMap<>();
for(int i = 0;i < inorder.length;i++){
map.put(inorder[i], i);
}
return helper(0, inorder.length - 1);
}
private TreeNode helper(int in_l, int in_r){
if(post_idx < 0 || in_l > in_r) return null;
int val = postorder[post_idx];
post_idx = post_idx - 1;
TreeNode node = new TreeNode(val);
int idx = map.get(val);
node.right = helper(idx + 1, in_r);
node.left = helper(in_l, idx - 1);
return node;
}
}
实战
- 二叉树的序列化与反序列化
- 将有序数组转化为二叉搜索树
- 从前序和中序遍历序列构造二叉树
- 从中序和后序遍历序列构造二叉树