树的遍历 | Tree Traversal
树的遍历方式总体上有两种:DFS和BFS;
其中DFS包含了前序、中序和后序遍历,而BFS则为层次遍历。
DFS的实现方式:
(1) 递归;
(2) 非递归,使用辅助栈;
递归程序
public class Recursion { public void preorderRec(TreeNode root) { if (root == null) { return; } System.out.println(root.val); // visit the node preorderRec(root.left); preorderRec(root.right); } public void inorderRec(TreeNode root) { if (root == null) { return; } preorderRec(root.left); System.out.println(root.val); // visit the node preorderRec(root.right); } public void postorderRec(TreeNode root) { if (root == null) { return; } preorderRec(root.left); preorderRec(root.right); System.out.println(root.val); // visit the node } }
非递归程序
public class NoRecursion { public void preorder(TreeNode root) { if (root == null) { return; } Stack<TreeNode> s = new Stack<TreeNode>(); TreeNode node = root; while (node != null || !s.isEmpty()) { while (node != null) { System.out.println(node.val); // visit the node s.push(node); node = node.left; } if (!s.isEmpty()) { node = s.pop(); node = node.right; } } } public void inorder(TreeNode root) { if (root == null) { return; } Stack<TreeNode> s = new Stack<TreeNode>(); TreeNode node = root; while (node != null || !s.isEmpty()) { while (node != null) { s.push(node); node = node.left; } if (!s.isEmpty()) { node = s.pop(); System.out.println(node.val); node = node.right; } } } public void postorder(TreeNode root) { if (root == null) { return; } Stack<TreeNode> s = new Stack<TreeNode>(); TreeNode node = root; TreeNode pre = null; while (node != null || !s.isEmpty()) { while (node != null) { s.push(node); node = node.left; } if (!s.isEmpty()) { node = s.peek(); if (node.right != null && node.right != pre) { node = node.right; } else { node = s.pop(); pre = node; // pre point the last visited node System.out.println(node.val); // visit the node node = null; } } } } }
其中,后序遍历稍微困难了一点,主要原因在于在遍历树中节点的同时需要记录最后访问节点。举例说明,如有一棵树如下:
1
| \
2 3
\
4
后序遍历的做法如下:
(1) 将根节点的左节点们依次加入栈中,最后栈顶元素为左子树的最左节点;
(2) 拿到栈顶元素(此时不出栈),如果没有右孩子并且右孩子没有被访问过,则出栈,此时标记下该出栈元素(表示该元素已被访问过);否则节点指向其右孩子。然后到(1);
(3) 遍历程序的结束条件为栈为空并且节点为空;
时间/空间复杂度分析
时间复杂度均为O(n);空间复杂度平均情况下为O(logn),最坏情况下为O(n).
BFS的实现方式:
层次遍历,使用一个辅助队列。
public void levelTraversal(TreeNode root){ if (root == null) { return ; } Queue<TreeNode> q = new LinkedList<TreeNode>(); q.offer(root); while (!q.isEmpty()) { int size = q.size(); for (int i = 0; i < size; i++) { TreeNode node = q.poll(); System.out.println(node.val); // visit the node if (node.left!=null) { q.offer(node.left); } if (node.right!=null) { q.offer(node.right); } } } }
时间复杂度和空间复杂度均为O(n).