class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ans = new LinkedList<>();
if (root == null) return ans;
Stack<TreeNode> s = new Stack<>();
s.push(root);
while (!s.isEmpty()) {
TreeNode node = s.pop();
ans.add(node.val);
if (node.right != null) s.add(node.right);
if (node.left != null) s.add(node.left);
}
return ans;
}
}
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ans = new LinkedList<>();
if (root == null) return ans;
Stack<TreeNode> s = new Stack<>();
TreeNode cur = root;
while (!s.isEmpty() || cur != null) {
while (cur != null) {
s.push(cur);
cur = cur.left;
}
TreeNode node = s.pop();
ans.add(node.val);
if (node.right != null) cur = node.right;
}
return ans;
}
}
后序遍历:仿照前序遍历,但是按照中、右、左出栈,然后将结果反转
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ans = new LinkedList<>();
if (root == null) return ans;
Stack<TreeNode> s = new Stack<>();
s.push(root);
Stack<Integer> v = new Stack<>();
while (!s.isEmpty()) {
TreeNode node = s.pop();
v.add(node.val);
if (node.left != null) s.push(node.left);
if (node.right != null) s.push(node.right);
}
while (!v.isEmpty()) ans.add(v.pop());
return ans;
}
}
# 递归
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res=[]
def dfs(root:TreeNode)->List[int]:
nonlocal res
if not root:
return
res.append(root.val)
dfs(root.left)
dfs(root.right)
dfs(root)
return res
# 非递归
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:return []
res=[]
stack=collections.deque()
stack.append(root)
while stack:
node=stack.pop()
res.append(node.val)
# wrong answer 这里需要注意,因为栈本身是FILO的结构,所以使用自己的栈进行模拟(先序遍历)时,需要先入栈右子树,然后入栈左子树,这样出来的顺序才是对的
# if node.left:stack.append(node.left)
# if node.right:stack.append(node.right)
if node.right:stack.append(node.right)
if node.left:stack.append(node.left)
return res
中序遍历
# 递归
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res=[]
def dfs(root:TreeNode)->List[int]:
if not root: return
nonlocal res
dfs(root.left)
res.append(root.val)
dfs(root.right)
dfs(root)
return res
# 非递归
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:return []
res,stack=[],[]
# 先序遍历的非递归非常巧妙,背下来, 太妙了,打了一边还是觉得妙
cur=root
while stack or cur:
while cur:
stck.append(cur)
cur=cur.left
tmp=stack.pop()
res.append(tmp.val)
cur=tmp.right
return res
后序遍历
# 递归
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res=[]
def dfs(root:TreeNode)->List[int]:
if not root:return
nonlocal res
dfs(root.left)
dfs(root.right)
res.append(root.val)
dfs(root)
return res
# 非递归 逆转方式
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:return []
res,stack=[],[]
cur=root
# 非递归简单版本:因为是后序遍历 左右中 ,所以可以按照 中左右的逆序来做
while cur or stack:
while cur:
res.append(cur.val)
stack.append(cur)
cur=cur.right
tmp=stack.pop()
cur=tmp.left
return res[::-1]
# 非递归 存储状态flag方式
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root:return []
# 难点在于如何判别这个node是不是已经遍历过了 有一个元组来标识 (flag,node) 其中flag=0表示还没有遍历过,flag=1表示已经遍历过了
# 下面这种标识法的精髓我觉得在于保存了一种状态:这个节点是不是走过一次
# 我感觉这种方法相比其他的更好理解,更像递归压栈,且不知道可以改写成相对应的前序遍历与中序遍历
# 之前的前序非递归,是压栈res节点值,压栈stack右子树,压栈stack左子树,前序遍历这种解法是最简单的,因为不存在识别是不是遍历过的问题
# 之前的中序非递归,首先要找到最左边的节点,可以向一种不断斜向左下角的操作方式一样
stack,res=[(0,root)],[]
while stack:
flag,node=stack.pop()
if not node:continue
if flag==1: # 表示已经遍历过了
res.append(node.val)
else:
stack.append((1,node))
stack.append((0,node.right)) # 注意压栈的顺序
stack.append((0,node.left))
return res
/**
* 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<Integer> ans = new ArrayList<>();
if(null == root){
return ans;
}
Deque<TreeNode> tmp = new LinkedList<>();
tmp.push(root);
while(!tmp.isEmpty()){
TreeNode cur = tmp.pop();
ans.add(cur.val);
if(cur.right != null){
tmp.push(cur.right);
}
if(cur.left != null){
tmp.push(cur.left);
}
}
return ans;
}
}
中序
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
Deque<TreeNode> tmp = new LinkedList<>();
TreeNode cur = root;
while(!tmp.isEmpty() || cur != null){
if(cur != null){
tmp.push(cur);
cur = cur.left;
} else {
cur = tmp.pop();
ans.add(cur.val);
cur = cur.right;
}
}
return ans;
}
}
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
public class Solution {
//中序遍历非递归形式
public List<Integer> inorderTraversal(TreeNode root){
List<Integer> nodes = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur!=null||!stack.isEmpty()){
while(cur!=null){
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
nodes.add(cur.val);
cur = cur.right;
}
return nodes;
}
//前序遍历非递归形式
public List<Integer> preorderTraversal(TreeNode root){
List<Integer> result = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur!=null||!stack.isEmpty()){
while(cur!=null){
stack.push(cur);
result.add(cur.val);
cur = cur.left;
}
cur = stack.pop();
cur = cur.right;
}
return result;
}
//后序遍历非递归形式
public List<Integer> postorderTraversal(TreeNode root){
List<Integer> result = new LinkedList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
TreeNode pre = null;
while (cur!=null||!stack.isEmpty()){
while (cur!=null){
stack.push(cur);
cur = cur.left;
}
cur = stack.peek();
if (cur.right!=null && cur.right !=pre){
cur = cur.right;
}else {
stack.pop();
result.add(cur.val);
pre = cur;
cur = null;
}
}
return result;
}
}
#前序遍历
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root: return []
res,num,stark=[],root,[]
while num or stark:
while num :
res.append(num.val)
stark.append(num)
num = num.left
tem = stark.pop()
num = tem.right
return res
#中序遍历
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root : return []
res,stark,num = [],[],root
while num or stark:
while num:
stark.append(num)
num = num.left
tem = stark.pop()
res.append(tem.val)
num = tem.right
return res
#后序遍历
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
if not root : return []
res,stark,num = [],[],root
while num or stark:
while num :
stark.append(num)
res.append(num.val)
num = num.right
tem = stark.pop()
num = tem.left
return res[::-1]
共以下 30 个回答
添加的时候考虑节点是否为空
迭代写法(非递归)
前序遍历:中,右,左入栈即可
中序遍历:先找到以当前节点为根的树的最左侧节点,然后输出该节点,如果该节点有右节点,就把当前节点切换为右侧节点,重复上述过程
后序遍历:仿照前序遍历,但是按照中、右、左出栈,然后将结果反转
前序遍历(中左右,借助一个栈,先将根节点加入栈中,再将右节点加入栈中,最后将左节点加入栈中,这样出栈的顺序就是中左右)。
后序遍历(借助前序遍历,来实现,只需改变下前序遍历的方式使结果集为中右左的顺序,最后将结果集反转,结果集的顺序就是左右中)
中序遍历(有些特殊,因为中序遍历先访问左节点,所以还需借助一个指针)。
上面前、中、后三种遍历方式代码有些不统一,可以使用统一的代码模板,需要一个栈和作为标记的空节点。放上中序遍历的统一模板代码:
前序遍历:
https://leetcode.cn/problems/binary-tree-preorder-traversal/solutions/1955565/er-cha-shu-qian-xu-bian-li-fei-di-gui-by-l7ka/
中序遍历:
https://leetcode.cn/problems/binary-tree-inorder-traversal/solutions/1955621/zhong-xu-bian-li-die-dai-by-pia7a-k-njps/
后续遍历:
前序遍历变顺序,然后反转结果数组即可
因为python3玩的不是很熟练,所以基本上参考了这个答案 https://leetcode.cn/problems/binary-tree-preorder-traversal/solution/tu-jie-er-cha-shu-de-si-chong-bian-li-by-z1m/
前序遍历
中序遍历
后序遍历
前序遍历
中序遍历
后序遍历
前中后序遍历
一.二叉树的前序遍历
二.二叉树的中序遍历
三.二叉树的后序遍历
四.二叉树的层序遍历
总结:
前、中、后遍历:
思路:递归和迭代(使用辅助栈)
时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn)),最坏情况下树呈现链状,为 O(n)。
前序遍历和后序遍历的代码思路基本一样,而中序遍历稍微有的区别。
层序遍历:
思路:迭代(使用队列)
前序
中序
后序
时间复杂度:O(n)
空间复杂度:O(n)
时间O(n)
空间O(n)
前序遍历
中序遍历
后序遍历
模板这块 感觉前序和后序比较像,就是结果翻转,中序有点差别。总的来说都是while循环和if判断。
要求大家掌握一下非递归的遍历方式,请大家给出自己的代码,并且认准自己的模版,以后就要这个模版,切勿变来变去
递归具有固有的局限性,如果二叉树的深度太大,那么递归代码可能会导致调用的栈溢出问题,其次递归代码太简单,面试官增加难度会要求你写非递归形式。
统统都可以模版,后序遍历,如果只是和前序一样改变结点方向,得到的是根右左,然后再反转,对二叉树的中和后序的理解还不是很深刻,要理解遍历过程 时间复杂度O(n),空间复杂度O(n)
第八天第一题
144. 二叉树的前序遍历(10.30)
前序递归
前序迭代
94. 二叉树的中序遍历(10.30)
中序递归
中序迭代
莫里斯遍历空间复杂度O(1)
145. 二叉树的后序遍历(10.30)
后序递归
后序迭代
迭代模板