二叉树是什么?
任意一个节点的子节点个数小于等于2的树为二叉树。
二叉树遍历分类:
前序遍历:根结点 ---> 左子树 ---> 右子树
中序遍历:左子树---> 根结点 ---> 右子树
后序遍历:左子树 ---> 右子树 ---> 根结点
层次遍历:只需按层次遍历即可
节点数据结构:
public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } }
前序遍历:
递归方式:
public void preorderTraversalRecursive(TreeNode node, List<Integer> result) { if (node == null) { return; } result.add(node.val); preorderTraversalRecursive(node.left, result); preorderTraversalRecursive(node.right, result); }
非递归方式
访问节点 -> 入栈 -> 访问左子树 -> 出栈 -> 访问右子树
public List<Integer> preorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); Stack<TreeNode> stack = new Stack<>(); TreeNode node = root; while (node != null || !stack.isEmpty()) { if (node != null) { // 先访问再入栈 result.add(node.val); stack.push(node); node = node.left; } else { // 此时栈顶节点左子树已经访问过了,开始访问右子树 node = stack.pop(); node = node.right; } } return result; }
中序遍历:
递归方式:
public void inorderTraversalRecursive(TreeNode node, List<Integer> result) { /** * 递归一定要记得写结束条件然后再处理逻辑 */ if (node == null) { return; } inorderTraversalRecursive(node.left, result); result.add(node.val); inorderTraversalRecursive(node.right, result); }
非递归方式:
入栈 -> 访问左子树 -> 出栈 -> 访问根节点 -> 访问右节点
public List<Integer> inorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); Stack<TreeNode> stack = new Stack<>(); TreeNode node = root; while (node != null || !stack.isEmpty()) { if (node != null) { stack.push(node); node = node.left; } else { // 此时栈顶节点左子树已经访问完成,可以访问节点本身,然后继续访问右子树 node = stack.pop(); result.add(node.val); node = node.right; } } return result; }
后序遍历:
递归方式:
public void postorderTraversalRecursive(TreeNode node, List<Integer> result) { if ( node == null) { return; } postorderTraversalRecursive(node.left, result); postorderTraversalRecursive(node.right, result); result.add(node.val); }
非递归方式:
中序遍历会在左子树访问完成后将根节点出栈,然后访问根节点后再访问右子树,而后序遍历需要在右子树访问完成后访问根节点,访问完左子树之后根节点不能出栈,因此后序遍历的非递归方式需要为每个节点添加一个变量用来标识该节点的左右子树是否已经被访问,如果左右子树都被访问了才可以出栈。
入栈 -> 访问左子树 -> 将根节点的左右子树是否已经访问设置为true -> 访问右子树 -> 根节点出栈,访问根节点
public List<Integer> postorderTraversal(TreeNode root) { List<Integer> result = new ArrayList<>(); //postorderTraversalRecursive(root, result); Stack<TreeNode> stack = new Stack<>(); Stack<Boolean> lastVisited = new Stack<>(); // 用来标识左右子树是否都已经访问 TreeNode node = root; while (node != null || !stack.isEmpty()) { if (node != null) { stack.push(node); node = node.left; lastVisited.push(false); } else { node = stack.peek(); if (false == lastVisited.peek()) { // 右子树还没访问,开始访问右子树 lastVisited.pop(); lastVisited.push(true); node = node.right; } else { // 右子树已经访问 result.add(node.val); stack.pop(); lastVisited.pop(); node = null; } } } return result; }
层序遍历
在每一层结束后添加一个空节点来标识该层结束
public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> result = new ArrayList<>(); Queue<TreeNode> queue = new LinkedList<>(); queue.offer(root); queue.offer(null); List<Integer> level = new ArrayList<>(); while (!queue.isEmpty()) { TreeNode node = queue.poll(); if (node == null) { result.add(level); if (!queue.isEmpty()) { level = new ArrayList<>(); queue.offer(null); } continue; } level.add(node.val); if (node.left != null) { queue.offer(node.left); } if (node.right != null) { queue.offer(node.right); } } return result; }
在遍历每层开始时先获取本层节点个数
public List<List<Integer>> levelOrder2(TreeNode root) { List<List<Integer>> result = new ArrayList<>(); Queue<TreeNode> queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { int count = queue.size(); List<Integer> level = new ArrayList<>(); while (count > 0) { TreeNode node = queue.poll(); level.add(node.val); if (node.left != null) { queue.offer(node.left); } if (node.right != null) { queue.offer(node.right); } count--; } result.add(level); } return result; }