二叉树的介绍
许多概念可以看之前的博客: 二叉树的遍历_塔塔开!!!的博客-CSDN博客_二叉树遍历
二叉树的遍历
- 前序遍历:根左右
- 中序遍历:左根右
- 后序遍历:左右根
- 层序遍历:BFS
实现方式:
- 递归
- 非递归(栈)
1. 递归实现
前序遍历
Code
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
dfs(root, res);
return res;
}
/**
前:根左右
*/
public static void dfs(TreeNode root, List<Integer> res){
if(root == null){
// 叶子节点
return ;
}
res.add(root.val);
dfs(root.left, res);
dfs(root.right, res);
}
}
中序遍历
Code
class Solution {
List<Integer> ans = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {
dfs(root);
return ans;
}
// 中序遍历
public void dfs(TreeNode root){
// 结束条件
if(root == null) return;
dfs(root.left);
ans.add(root.val);
dfs(root.right);
}
}
后序遍历
Code
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
dfs(root, res);
return res;
}
/**
后:左右根
*/
public static void dfs(TreeNode root, List<Integer> res){
if(root == null){
// 叶子节点
return ;
}
dfs(root.left, res);
dfs(root.right, res);
res.add(root.val);
}
}
2. 迭代实现
前序遍历
思路:用栈模拟前序遍历过程,由于是栈(先进后出)
- 根节点先栈
- 当栈不为空,右孩子先入栈,然后左孩子再入栈(后进先出)
栈模拟:根左右 —> 根右左
Code
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null){
return res;
}
// 前:根左右
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
while(!stk.empty()){
TreeNode node = stk.pop();
res.add(node.val);
// 右儿子先入栈
if(node.right != null){
stk.push(node.right);
}
// 做儿子入队
if(node.left != null){
stk.push(node.left);
}
}
return res;
}
}
后序遍历
上述迭代法获取前序遍历:根左右
—> 迭代过程按根右左
的顺序遍历插入,最终得到前序遍历的结果(根左右
)
扫描二维码关注公众号,回复:
14712342 查看本文章
而后序遍历是左右根
,它的翻转是根右左
,那么我们只要想办法拿到这棵树的根左右
次序,然后再将其翻转即可获得后续遍历的结果!,那么根右左
的遍历次序结果我们又是如何得到的呢?—— 模仿前序遍历迭代的获取过程:
根左右
—> 由入栈顺序根右左
得到- 那么
根右左
—> 由入栈顺序根左
得到
Code
/**
* 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<>();
if(root == null){
return list;
}
Stack<TreeNode> stk = new Stack<>();
stk.push(root);
// 先获取根右左的遍历次序结果
while(!stk.empty()){
TreeNode node = stk.pop();
list.add(node.val);
if(node.left != null){
stk.push(node.left);
}
if(node.right != null){
stk.push(node.right);
}
}
// 翻转得到后序遍历结果
Collections.reverse(list);
return list;
}
}
中序遍历
中:左根右
迭代法:
-
定义一个指针指向根节点,当节点不为空或者栈不为空时一直循环
- 当指针不为空时,当前节点入栈,一直循环遍历左儿子,如此往复直到
p指针
指向空-------(模拟一直左递归
的过程) - 当指针为空时,栈顶元素出栈,指针指向了出栈的节点,
p = stk.pop()
,节点值val
加入ans
(模拟遍历中根的过程,记录答案),然后指针p
移动到当前节点的右儿子(模拟遍历中右的过程),为下一次(左根右做好准备)
- 当指针不为空时,当前节点入栈,一直循环遍历左儿子,如此往复直到
-
如此往复,直到栈为空。
Code
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
TreeNode p = root;
Stack<TreeNode> stk = new Stack<>();
List<Integer> ans = new ArrayList<>();
while(p != null || !stk.empty()){
while(p != null){
// 模拟一直左递归的过程
stk.push(p);
p = p.left;
}
// p走到了空
// 根
p = stk.pop();
ans.add(p.val);
// 右
p = p.right;
}
return ans;
}
}