深度优先遍历(DFS)
DFS是一种遍历策略,它从根节点开始,尽可能深地探索树的分支,直到达到叶节点,然后回溯至上一层节点的未访问子节点。
对于二叉树,DFS有三种形式的遍历方式:
- 前序遍历(Preorder Traversal):根节点 -> 左子树 -> 右子树
- 中序遍历(Inorder Traversal):左子树 -> 根节点 -> 右子树
- 后序遍历(Postorder Traversal):左子树 -> 右子树 -> 根节点
二叉树前、中、后序遍历
前序遍历
遍历方式为先根节点,再左节点,最后右节点。
- 递归实现
class treeNode{
treeNode left;
treeNode right;
int val;
public treeNode(int val){
this.val = val;
}
}
public void preOrder(treeNode root){
if(root == null){
return;
}
System.out.print(root.val + ",");
preOrder(root.left);
preOrder(root.right);
// 递归实现
}
- 非递归实现
// 使用栈这个数据结构
public ArrayList<Integer> preOrderTraversal(TreeNode root){
Stack<TreeNode> stack = new Stack<TreeNode>();
ArrayList<Integer> ans = new ArrayList<Integer>();
if(root == null){
return ans;
}
TreeNode cur = root;
// 先将头节点push进来
stack.push(cur);
while(!stack.isEmpty()){
cur = stack.pop();
ans.add(cur.val);
if(cur.right != null){
stack.push(cur.right);
}
if(cur.left != null){
stack.push(cur.left);
}
}
return ans;
}
中序遍历
遍历方式为先左节点,再根节点,最后右节点。
- 递归实现
public void inOrder(treeNode root){
if(root == null){
return;
}
inOrder(root.left);
System.out.print(root.val + ",");
inOrder(root.right);
// 递归实现
}
- 非递归实现
public ArrayList<Integer> inOrderTraversal(TreeNode root){
Stack<TreeNode> stack = new Stack<TreeNode>();
ArrayList<Integer> ans = new ArrayList<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()){
if(cur != null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
ans.add(cur.val);
if(cur.rigth == null){
cur = null;
}else{
cur = cur.right;
stack.push(cur);
cur = cur.left;
}
}
}
return ans;
}
后序遍历
遍历方式为先左节点,再右节点,最后根节点。
- 递归实现
public void postOrder(treeNode root){
if(root == null){
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val + ",")
}
- 非递归实现
/**
主要思想:首先遍历root根节点的所有左节点,并依次入栈。对出栈的元素,如果没有右儿子或者虽然有右儿子但右儿子已完成遍历,即可完成出栈;否则,再次入栈,并把右儿子入栈,遍历右儿子的所有左儿子。
*/
public ArrayList<Integer> postOrder(treeNode root){
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode cur = root;
/*
* 用来记录最新出栈的节点,如果当前节点的右儿子与flag相同,说明当前节点右子树已完成遍历
*/
TreeNode flag = null;
// 先找到最左边的儿子
while(cur != null){
stack.push(cur);
cur = cur.left;
}
while(cur != null || !stack.isEmpty()){
cur = stack.pop();
// 判断该节点右子树是否为空或者已完成遍历
if(cur.right == null || cur.right == flag){
ans.add(cur.val);
flag = cur;
}else{
// 反之右子树不为空,则需要重新入栈,直到右子树遍历完或右子树为空才可出栈
stack.push(cur);
cur = cur.right;
// 找右子树的左儿子
while(cur != null){
stack.push(cur);
cur = cur.left;
}
}
}
return ans;
}
广度优先遍历(BFS)
BFS是一种从根节点开始,逐层遍历树的节点,每一层的所有节点都在下一层节点之前被访问。对于二叉树,BFS实现的是层次遍历,按照从上到下、从左到右的顺序访问节点:层次遍历(Level Order Traversal):首先访问第一层(根节点),然后是第二层的所有节点,接着第三层……直到最后一层。
BFS使用队列数据结构来存储待访问节点,每次从队列头部取出节点并访问,然后将其子节点(如果存在且未访问过)添加到队列尾部。
例如,对于一棵二叉树,假设它的结构如下:
层次遍历
一层一层的遍历:基于队列实现的自上而下,从左到右按层遍历二叉树,记录每一层节点的个数n,并出栈n次,这样就可以遍历完一层
public ArrayList<Integer> levelTraversal(TreeNode root){
if(root == null){
return null;
}
// 使用双向链表(LinkedList)来表示队列(Queue)
Queue<TreeNode> queue = new LinkedList<TreeNode>();
ArrayList<Integer> ans = new ArrayList<>();
TreeNode cur = root;
// 根节点进队
queue.offer(cur);
while(!queue.isEmpty()){
// size记录当前层的节点数,用于完整遍历当前层节点
for(int i = 0, size = queue.size(); i < size; i++){
cur = queue.poll();
ans.add(cur.val);
// 先入栈left,自上而下,从左到右遍历
if(cur.left != null){
queue.offer(cur.left);
}
if(cur.right != null){
queue.offer(cur.right);
}
}
}
return ans;
}