一. 基本遍历
(1)深度优先(DFS)
1.1 递归
自动栈
(Depth First Search, 简称 DFS)
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
- 前序遍历
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
if(root !=null){
list.add(root.val);
inorderTraversal(root.left);
inorderTraversal(root.right);
}
return list;
}
- 后序遍历
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
if(root !=null){
list.add(root.val);
inorderTraversal(root.right);
inorderTraversal(root.left);
}
return list;
}
- 中序遍历
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new LinkedList<>();
if(root !=null){
inorderTraversal(root.left);
list.add(root.val);
inorderTraversal(root.right);
}
return list;
}
递归的表达性很好,也很容易理解,
不过如果层级过深,很容易导致栈溢出。
1.2 非递归(迭代)
144. 二叉树的前序遍历
145. 二叉树的后序遍历
94. 二叉树的中序遍历
- 前序遍历
/*中 左 右
先将根节点放入
取出栈中节点 : 给栈中 放入取出节点 的 右节点 , 左节点
循环往复
*/
public List<Integer> preorderTraversal(TreeNode root) {
LinkedList<Integer> list = new LinkedList<>();
if (root == null){
return list;
}
// 双端队列 做 栈
// Deque<TreeNode> stack = new ArrayDeque<>();
Deque<TreeNode> stack = new LinkedList<>();
stack.addLast(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pollLast();
list.add(node.val);
if (node.right != null){
stack.addLast(node.right);
}
if (node.left != null){
stack.addLast(node.left);
}
}
return list;
}
- 后序遍历
后续遍历思想: 左-右-根 ; 可以视为, 根-右-左, 然后结果转置即可.
即将前序遍历的代码 改为 中 右 左 ,在添加到list集合时候,用 addFirst方法
/**
* 前序遍历 : 中 左 右
* 后序遍历 : 左 右 中
*
* 后续遍历思想: 左-右-根 ; 可以视为, 根-右-左, 然后结果转置即可.
* 即将前序遍历的代码 改为 中 右 左 ,在添加到list集合时候,用 addFirst方法
*/
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> list = new LinkedList<>();
if (root == null){
return list;
}
// 双端队列 做 栈
// Deque<TreeNode> stack = new ArrayDeque<>();
Deque<TreeNode> stack = new LinkedList<>();
stack.addLast(root);
while (!stack.isEmpty()) {
TreeNode node = stack.pollLast();
// 添加到头部
list.addFirst(node.val);
// 入栈顺序相反
if (node.left != null){
stack.addLast(node.left);
}
if (node.right != null){
stack.addLast(node.right);
}
}
return list;
}
- 中序遍历
- 中序遍历思路: 中序遍历迭代法思路不同于前序和后序.
- 首先针对对当前节点,一直对其左子树迭代并将非空节点入栈
- 节点指针迭代为空(到树底了)后不再入栈,然后取栈顶元素,存结果;
- 将当前指针用出栈的节点的右子节点替代,然后回到第一步继续迭代,直到当前节点为空且栈为空.
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) return list;
Deque<TreeNode> stack = new LinkedList<>();
//
while (root != null || !stack.isEmpty()){
// 达到左下角叶子结点的左节点时,退出
while(root != null){
stack.addLast(root);
root = root.left;
}
TreeNode node = stack.pollLast();
list.add(node.val);
root = node.right;
}
return list;
}
(2)广度优先(BFS)
广度优先遍历(Breath First Search)
用队列实现:
private List<Integer> bfs(TreeNode root) {
List<Integer> list = new ArrayList<>();
if (root == null) {
return list;
}
Queue<TreeNode> stack = new LinkedList<>();
stack.add(root);
while (!stack.isEmpty()) {
TreeNode node = stack.poll();
list.add(node.val);
TreeNode left = node.left;
if (left != null) {
stack.add(left);
}
TreeNode right = node.right;
if (right != null) {
stack.add(right);
}
}
return list;
}
例题:
102. 二叉树的层序遍历
107. 二叉树的层次遍历 II
1. 栈
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> lists = new LinkedList<>();
if (root == null) {
return lists;
}
Queue<TreeNode> stack= new LinkedList<>();
stack.add(root);
while (!stack.isEmpty()) {
// 存放本层元素
LinkedList<Integer> list = new LinkedList<>();
int size = stack.size();
// 遍历本层,并删除,添加下一层
while (size-- > 0) {
TreeNode node = stack.poll();
list.add(node.val);
if (node.left != null){
stack.add(node.left);
}
if (node.right != null){
stack.add(node.right);
}
}
lists.add(list);
}
return lists;
}
2. 递归
List<List<Integer>> lists = new LinkedList<>();
// 2. 深度优先· 给层编号 , size 与 层 的 关系
// 树从零层开始 层 == 集合下标
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return lists;
dfs(root,0);
return lists;
}
public void dfs(TreeNode root, int level){
if (root == null) {
return;
}
// 初始化总集合 的层集合
if(lists.size() < level+1){
lists.add(new LinkedList<>());
}
List<Integer> list = lists.get(level);
list.add(root.val);
// 注意左右顺序
dfs(root.left,level+1);
dfs(root.right,level+1);
}