死磕二叉树(一)
定义
二叉树是每个结点最多有两个子树的树结构。
3
/ \
4 5
/ \
1 2
因为二叉树的左右子树都具有类似的结构,二叉树的题目往往和递归是关联的。
从二叉树的遍历谈起
遍历二叉树的每一个点,通常有三种方式,中序,前序,后序的方式,对应上图的树来说,结果是:
3 4 1 2 5 // 前序
1 4 2 3 5 // 中序
1 2 4 5 3 // 后序
前、后、中都是相对于根节点的位置来定义的。
首先来看:
94. 二叉树的中序遍历
深度优先
通过递归的方式很容易构造,关键在于如何选出递归结束的条件,比如当前节点是空值时,需要return
方法一:
class Solution {
List<Integer> list = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
helper(root);
return list;
}
void helper(TreeNode root){
if(root == null) return;
else {
if(root.left != null) helper(root.left);
list.add(root.val);
if(root.right != null) helper(root.right);
}
}
}
方法二:
除了递归的方式,还有迭代法,迭代中序遍历时,需要借助一个栈,栈的功能是存储上一个节点,好让处理完左子树的时候,可以回头访问根节点,根据这个思路,我们可以在访问开始前沿着左子树一路访问到null
,然后再访问上一个节点(此时可以看成根节点),最后再访问右节点:
class Solution {
public List<Integer> inorderTraversal2(TreeNode root){
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while (root != null || !stack.isEmpty()){
if(root != null){
stack.add(root);
root = root.left;
} else {
root = stack.pop();
list.add(root.val);
root = root.right;
}
}
return list;
}
}
144. 二叉树的前序遍历
有了中序遍历的基础,前序遍历的递归形式可以很容易的写出来:
方法一:
class Solution {
List<Integer> list = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
helper(root);
return list;
}
void helper(TreeNode root){
if(root == null) return;
else {
list.add(root.val);
if(root.left != null) helper(root.left);
if(root.right != null) helper(root.right);
}
}
}
方法二:
使用迭代法依然时要借助一个栈来实现,这里栈的功能和中序遍历类似,都是要存储上一个节点,便于访问完左子树后再访问右子树。不同的是,访问下一个左节点之前,就需要把节点的值保存到结果中去:
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null){
if(root != null){
stack.add(root);
res.add(root.val);
root = root.left;
}else{
root = stack.pop();
root = root.right;
}
}
return res;
}
}
145. 二叉树的后序遍历
前序遍历和后序遍历之间的的关系:
前序遍历顺序为:根 -> 左 -> 右
后序遍历顺序为:左 -> 右 -> 根
前序遍历的时候,每个节点的值都会插入到结果链表的尾部,res.add(root.val)
如果每次都选择插入到结果链表的头部,那么遍历顺序会变为:右 -> 左 -> 根
此时转换一下左右子树的先后顺序,就得到我们想要的结果:左 -> 右 -> 根
迭代法:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> res = new LinkedList<Integer>();
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null){
if(root != null){
stack.add(root);
res.addFirst(root.val);
root = root.right;
}else{
root = stack.pop();
root = root.left;
}
}
return res;
}
}