目录
- 1.概述
- 2.代码实现
- 2.1.二叉树定义
- 2.2.前序遍历
- 2.3.中序遍历
- 2.4.后序遍历
- 2.5.层序遍历
 
- 3.应用
本文参考:
LABULADONG 的算法网站
1.概述
(1)所谓遍历 (Traversal) 是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
(2)从二叉树的递归定义可知,一棵非空的二叉树由根结点、左子树和右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
 ① 访问结点本身 N;
 ② 遍历该结点的左子树 L;
 ③ 遍历该结点的右子树 R;
(3)以上三种操作有六种执行次序:NLR、LNR、LRN、NRL、RNL、RLN。由于前三种次序与后三种次序对称,所以本文只讨论先左后右的前三种次序。然后再根据访问结点操作发生位置命名:
 ① NLR:前序遍历 (Preorder Traversal,也称为先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
 ② LNR:中序遍历 (Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
 ③ LRN:后序遍历 (Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
注意:由于被访问的结点必是某子树的根,所以 N (Node)、L (Left subtree)和 R (Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR 和 LRN 分别又称为先根遍历、中根遍历和后根遍历。
(4)除了 NLR、LNR 和 LRN 外,这里再介绍一种遍历方式——层序遍历,即从根节点开始,从上往下、从左往右,一层一层地进行遍历。
(5)以下面的二叉树为例,来说明上面提到的四种遍历方式。
 
前序遍历、中序遍历和后序遍历在二叉树上的情况如下所示:

① 前序遍历的结果为:
0 1 2 3 4 5 6 7
② 中序遍历的结果为:
2 1 4 3 0 5 7 6
③ 后序遍历的结果为:
2 4 3 1 7 6 5 0
④ 层序遍历:

结果为:
0 1 5 2 3 6 4 7
2.代码实现
2.1.二叉树定义
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;
    }
}
2.2.前序遍历
class Solution {
    
    // res 用于保存前序遍历的结果
    LinkedList<Integer> res = new LinkedList<>();
    
    public List<Integer> preorderTraversal(TreeNode root) {
        traverse(root);
        return res;
    }
    
    public void traverse(TreeNode root) {
        if (root == null) {
            return;
        }
        //将当前根节点的值加入到 res 中
        res.add(root.val);
        //遍历左子树
        traverse(root.left);
        //遍历右子树
        traverse(root.right);
    }
}
2.3.中序遍历
class Solution {
    //res用于保存最终结果
    LinkedList<Integer> res = new LinkedList<>();
    
    public List<Integer> inorderTraversal(TreeNode root) {
        traverse(root);
        return res;
    }
    
    public void traverse(TreeNode root) {
        if (root == null) {
            return;
        }
        //遍历左子树
        traverse(root.left);
        //将当前根节点的值加入到 res 中
        res.add(root.val);
        //遍历右子树
        traverse(root.right);
    }
}
2.4.后序遍历
class Solution {
    //res用于保存最终结果
    LinkedList<Integer> res = new LinkedList<>();
    
    public List<Integer> inorderTraversal(TreeNode root) {
        traverse(root);
        return res;
    }
    
    public void traverse(TreeNode root) {
        if (root == null) {
            return;
        }
        //遍历左子树
        traverse(root.left);
        //遍历右子树
        traverse(root.right);
        //将当前根节点的值加入到 res 中
        res.add(root.val);
    }
}
2.5.层序遍历
class Solution {
    //二叉树的层序遍历
    public List<List<Integer>> levelOrder(TreeNode root) {
        // res 用于保存最终结果
        List<List<Integer>> res = new LinkedList<>();
        if (root == null) {
            return res;
        }
        // queue 保存层序遍历过程中每一层的所有节点
        Queue<TreeNode> queue = new LinkedList<>();
        //最开始的第一层只有根节点,故先将根节点加入到队列中
        queue.offer(root);
        // while 循环控制从上向下方向的遍历
        while (!queue.isEmpty()) {
            // levelSize 记录当前层的节点数量
            int levelSize = queue.size();
            // levelVals 保存当前层的所有节点值
            List<Integer> levelVals = new LinkedList<>();
            // for 循环控制每一层从左向右的遍历
            for (int i = 0; i < levelSize; i++) {
                //poll():返回并删除队列中的第一个元素
                TreeNode curNode = queue.poll();
                levelVals.add(curNode.val);
                //同时将下一层中的所有节点保存到 queue 中
                if (curNode.left != null) {
                    queue.offer(curNode.left);
                }
                if (curNode.right != null) {
                    queue.offer(curNode.right);
                }
            }
            //将当前层的所有节点值加入到 res 中
            res.add(levelVals);
        }
        return res;
    }
}
3.应用
(1) 二叉树遍历是二叉树上进行其它运算之基础,例如 LeetCode 中的144.二叉树的前序遍历、94.二叉树的中序遍历、145.二叉树的后序遍历以及102.二叉树的层序遍历均是对其的直接应用。
(2)大家可以去 LeetCode 上找相关的二叉树遍历题目来练习,或者也可以直接查看 LeetCode算法刷题目录 (Java)这篇文章中的二叉树章节。此外,如果大家发现文章中的错误之处,可在评论区中指出。



















