144.二叉树的前序遍历
题目
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
代码(递归)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
//list保存遍历后的节点数据
List<Integer> list = new ArrayList<Integer>();
//调用前序递归
preOrder(root, list);
return list;
}
//递归的参数是树的根节点指针+存储遍历节点的数据
public void preOrder(TreeNode root, List<Integer> list){
//递归终止条件是节点指针为空,如果是空没有其余操作直接返回
if(root == null){
return;
}
//想清楚一层遍历的流程是先访问并获取中元素,再访问左子,再访问右子
list.add(root.val); //获取中
preOrder(root.left,list); //访问左子
preOrder(root.right,list); //访问右子
}
}
代码(迭代)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
//list保存遍历后的节点数据
List<Integer> list = new ArrayList<Integer>();
Stack<TreeNode> stack = new Stack();
//这个必须要写,不然后边cur.val会报错NullPointerException
if(root == null){
return list;
}
//根节点入栈
stack.push(root);
while(!stack.isEmpty()){
TreeNode cur = stack.pop(); //栈顶,中间节点1出栈
list.add(cur.val); //中间节点1add
//右子节点3入栈
if(cur.right != null){
stack.push(cur.right);
}
//左子节点2入栈
if(cur.left != null){
stack.push(cur.left);
}
}
return list;
}
}
总结
1.递归的核心要确定三个点:
①递归函数的形参是什么,用到什么参数:根节点指针+遍历返回的数据列表
②递归的终止条件是什么:访问到空节点
③递归的一层是什么逻辑:先获取中间节点元素,再访问左子孩子,最后访问右子孩子。
2.迭代法的逻辑如下:
中间节点先入栈,然后中间节点出栈时,连续执行三个操作,add中,如果右子节点非空把右进栈,如果左子节点非空把左进栈。
以123为例,1作为根节点(中间节点)先入栈。
然后中间节点1出栈,cur指向中间节点1,第一步先访问元素,把cur.val加入到list结果集,第二步,判断右子节点3非空,右子节点3进栈,第三步,判断左子节点2非空,左子节点2入栈。
当栈非空时,不断的出栈,把出栈节点作为中间节点。然后节点2出栈,把cur.val的2加入到list结果集,访问左右节点都为空,空节点不入栈。
当栈非空时,不断的出栈,把出栈节点作为中间节点。然后节点3出栈,把cur.val的3加入到list结果集,访问左右节点都为空,空节点不入栈。
最后,栈空了,访问结束。list结果集里面是123。
94.二叉树的中序遍历
题目
给定一个二叉树的根节点 root
,返回 它的 中序 遍历 。
代码(递归)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
inOrder(root,list);
return list;
}
public void inOrder(TreeNode root, List<Integer> list){
if(root == null){
return;
}
inOrder(root.left, list);
list.add(root.val);
inOrder(root.right, list);
}
}
代码(迭代)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root == null){
return list;
}
//当前节点cur指向根节点
TreeNode cur = root;
//当栈非空or当前节点非空
while(cur != null || !stack.isEmpty()){
//如果当前节点(中),就入栈,然后往左边走
if(cur != null){
stack.push(cur);
cur = cur.left; //一开始会走到最左下的空节点
}
//如果当前节点cur是空(左),就出栈访问(中间),然后走右下
else{
cur = stack.pop();
list.add(cur.val);
cur = cur.right;
}
}
return list;
}
}
总结
中序迭代的核心逻辑是,先让cur指向根节点,然后如果cur不为空,就让cur进栈,相当于中间节点入栈,然后cur = cur.left,让cur不断走到树的最左下部分。当cur是空,说明走到了最左下的空节点,此时出栈,栈顶元素作为中间节点,需要add到list,此时左和中都处理完了,要继续访问右子树,让cur = cur.right.
以1234为例,根节点是1,cur=1,cur不为空,就让cur=1进栈,cur = cur.left = 2.
cur=2不为空,2进栈,cur = cur.left = 4。
cur=4不为空,4进栈,cur = cur.left,此时cur指向的左子树最下面节点4的左空节点。
当cur为空时,说明左子节点时空,此时栈顶元素4就是中间节点,则出栈并访问4,然后访问4的右节点。也是空,继续出栈,cur=2,访问节点2,2继续网右边走,走到空,继续出栈,cur=1,访问节点1,继续让1右边走,1走到3,cur=3,3不为空,就让3进栈,然后走3的左子空,3出栈并访问,cur指向3的右子空节点。
此时,cur为指向的最右下的空节点,栈也为空,结束循环。1234的树中序输出4213。
145.二叉树的后序遍历
题目
给你一棵二叉树的根节点 root
,返回其节点值的 后序遍历 。
代码(递归)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
postOrder(root,list);
return list;
}
public void postOrder(TreeNode root, List<Integer> list){
if(root == null){
return;
}
postOrder(root.left, list);
postOrder(root.right, list);
list.add(root.val);
}
}
代码(迭代)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
//如果树为null,直接返回空list
if(root == null){
return list;
}
//根节点1先进栈
stack.push(root);
while(!stack.isEmpty()){
//中间节点出栈
TreeNode cur = stack.pop();
//中间节点访问
list.add(cur.val);
//左子节点非空,则入栈
if(cur.left != null){
stack.push(cur.left);
}
//右子节点非空,则入栈
if(cur.right != null){
stack.push(cur.right);
}
}
//前序的结果是123,调整前序左右子树进栈顺序的结果是132
//把132,reverse一下,正好是231,是后序结果
Collections.reverse(list);
return(list);
}
}
总结
后序的迭代法其实和前序原理一样,前序是先拿中间节点访问,然后右左进栈,出栈是正好是中左右的顺序。后序把子节点的进栈顺序变为左右进栈。出栈就是中右左的顺序。最后,反转一下,就是左右中的顺序,后序完成。