概述
之前有说到二叉树的建树,这次讲讲二叉树的遍历过程。二叉树的遍历分为深度优先遍历和广度优先遍历,二叉树的逻辑结构如下所示:
class TreeNode{int val;TreeNode left;TreeNode right;public TreeNode(){}public TreeNode(int val){this.val = val;}
}
本文将用示例来详细描述二叉树深度优先遍历中后序遍历以及层序遍历的详细过程,而二叉树的前序遍历和中序遍历与前序遍历类似,就不再展开阐述。示例如下图所示。
深度优先遍历
根据父结点的遍历顺序的不同,分为如下三种遍历。
- 前序遍历:先遍历父结点,之后是左节点,最后是右结点。
- 中序遍历:先遍历左结点,之后是父结点,最后是右结点。
- 后序遍历:先遍历左节点,之后是右节点,最后是父结点。
前序遍历
List<Integer> res = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {Tarversal(root);return res;
}
void Tarversal(TreeNode root){if(root == null) return;res.add(root.val);Tarversal(root.left);Tarversal(root.right);
}
中序遍历
List<Integer> res = new ArrayList<>();
public List<Integer> inorderTraversal(TreeNode root) {Tarversal(root);return res;
}
void Tarversal(TreeNode root){if(root == null) return;Tarversal(root.left);res.add(root.val);Tarversal(root.right);
}
后序遍历
List<Integer> res = new ArrayList<>();
public List<Integer> postorderTraversal(TreeNode root) {Tarversal(root);return res;
}
void Tarversal(TreeNode root){if(root == null) return;Tarversal(root.left);Tarversal(root.right);res.add(root.val);
}
首先,根结点为1,不为空,进入根结点的left,即2结点,结点2不为空,进入结点2的left,结点2的左结点为空返回,进入结点2的右结点为空返回,结点2左右子结点Tarversal遍历结束,将结点2放入res中,结点2的Tarversal方法遍历完成,回到根结点1的Tarversal方法继续递归根结点1的right,结点3不为空,进入结点3的left,结点4不为空,进入结点4的left,结点4的left为空返回,进入结点4的right为空返回,将结点4加入res中,返回结点3的right,结点5不为空,进入结点5的left为空返回,进入结点5的right为空返回,将结点5加入res中,返回结点3,结点的左右子结点递归结束,将结点3加入res中,返回结点1,结点1左右子结点递归结束,将结点1加入res中,后序遍历整个过程完成。
广度优先遍历(层序遍历)
public List<List<Integer>> bfs(TreeNode root) {List<List<Integer>> ans = new ArrayList<>();Deque<TreeNode> queue = new ArrayDeque<>();if(root == null) return ans;queue.offer(root);while(!queue.isEmpty()){int size = queue.size();List<Integer> list = new ArrayList<>();for(int i = 0;i < size;i++){TreeNode node = queue.poll();list.add(node.val);if(node.left != null){queue.offer(node.left);} if(node.right != null){queue.offer(node.right);}}ans.add(list);}return ans;
}
该代码中巧妙之处在于用队列的大小,即size来控制二叉树的每层树结点个数,进而得到每层的遍历结果。首先判断根结点是否为空,显然根节点为1不为空,将根结点放入队列中,之后,开始进行外层while循环判断,队列是否为空,显然不为空,获取队列的大小为1,仅有一个根节点,创建一个存放每层元素的队列list,之后进入第二层for循环,将根结点1弹出并加入队列中,之后判断根结点的左右结点是否为空,都不为空,将左结点2和右结点3加入队列中,for循环结束,list中仅存放根结点,将list放入ans中。继续外层while循环,判断队列不为空,有两个元素2和3,因此size等于2,第二层for循环两次,重新创建一个放第二层元素的list,进入内层for循环,将2弹出并加入list中,判断2的左右结点,都为空,什么也不做,继续将结点3弹出并加入list中,判断结点3是否为空,左右结点都不为空,将左结点4和右结点5加入队列中,第二层for循环结束,list中存放元素2和3,将list放入ans中。外层循环while判断队列是否为空,不为空,有结点4和5,size为2,第二层for循环遍历2次,重新创建一个放第三层元素的list,进入内层for循环,将结点4弹出并加入list中,判断结点4左右结点是否为空,为空,什么也不做,弹出结点5并加入list中,判断结点5左右结点是否为空,为空,什么也不做,内层for循环结点,将list放入ans中,此时队列为空,外层while循环结束,就此得到了层序遍历的所有结果。
实战
- 二叉树的前序遍历
- 二叉树的中序遍历
- 二叉树的后序遍历
- 二叉树的层序遍历
- 二叉树的层序遍历II
- 二叉树的锯齿形层序遍历