二叉树的遍历
·1.Binary Tree Preorder Traversal
使用栈,时间复杂度O(n),空间复杂度O(n) public List<Integer> preorderTraversal(TreeNode root) { ArrayList<Integer> result = new ArrayList<>(); Stack<TreeNode> s = new Stack<>(); if (root != null) s.push(root); while (!s.isEmpty()) { final TreeNode p = s.pop(); result.add(p.val); if (p.right != null) s.push(p.right); if (p.left != null) s.push(p.left); } return result; }
递归先序遍历,时间复杂度O(n),空间复杂度O(n) public static void preOrderRec(Node root){ if(root!=null){ System.out.println(root.value); preOrderRec(root.left); preOrderRec(root.right); } }
Morris先序遍历,时间复杂度O(n),空间复杂度O(1)
步骤:
1.如果当前节点的左孩子为空,则输出当前节点并将其右孩子作为当前节点。
2.如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点。
a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点。输出当前节点(在这里输出,这是与中序遍历唯一一点不同)。当前节点更新为当前节点的左孩子。
b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空。当前节点更新为当前节点的右孩子。
3.重复以上1、2直到当前节点为空。
public List<Integer> preorderTraversal(TreeNode root) { ArrayList<Integer> result = new ArrayList<>(); TreeNode cur = root; TreeNode prev = null; while (cur != null) { if (cur.left == null) { result.add(cur.val); prev = cur; cur = cur.right; } else { /* 查找前驱 */ prev = cur.left; while (prev.right != null && prev.right != cur) { prev = prev.right; } if (prev.right == null) { /* 还没线索化,则建立线索 */ result.add(cur.val); /* 仅这一行的位置与中序不同 */ prev.right = cur; prev = cur; /* cur刚刚被访问过 */ cur = cur.left; } else { /* 已经线索化,则访问节点,并删除线索 */ prev.right = null; cur = cur.right; } } } return result; }
2.Binary Tree Inorder Traversal
使用栈,时间复杂度O(n),空间复杂度O(n) public List<Integer> inorderTraversal(TreeNode root) { ArrayList<Integer> result = new ArrayList<>(); Stack<TreeNode> s = new Stack<>(); TreeNode pNode = root; while (!s.isEmpty() || pNode != null) { if (pNode != null) { s.push(pNode); pNode = pNode.left; } else { pNode = s.pop(); result.add(pNode.val); pNode = pNode.right; } } return result; }
递归中序遍历,时间复杂度O(n),空间复杂度O(n) public static void inOrderRec(Node root){ if(root!=null){ preOrderRec(root.left); System.out.println(root.value); preOrderRec(root.right); } }
使用栈,时间复杂度O(n),空间复杂度O(n)
步骤:
1.如果当前节点的左孩子为空,则输出当前节点并将其右孩子作为当前节点。
2.如果当前节点的左孩子不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点。
a) 如果前驱节点的右孩子为空,将它的右孩子设置为当前节点。当前节点更新为当前节点的左孩子。
b) 如果前驱节点的右孩子为当前节点,将它的右孩子重新设为空(恢复树的形状)。输出当前节点。当前节点更新为当前节点的右孩子。
3.重复以上1、2直到当前节点为空。
public List<Integer> inorderTraversal1(TreeNode root) { ArrayList<Integer> result = new ArrayList<>(); TreeNode cur = root; TreeNode prev = null; while (cur != null) { if (cur.left == null) { result.add(cur.val); prev = cur; cur = cur.right; } else { /* 查找前驱 */ prev = cur.left; while (prev.right != null && prev.right != cur) { prev = prev.right; } if (prev.right == null) {/* 还没线索化,则建立线索 */ prev.right = cur; cur = cur.left; } else {/* 已经线索化,则访问节点,并删除线索 */ result.add(cur.val); prev.right = null; prev = cur; /* cur刚刚被访问过 */ cur = cur.right; } } } return result; }
3.Binary Tree Postorder Traversal
使用栈,时间复杂度O(n),空间复杂度O(n) /* p,正在访问的结点,q,刚刚访问过的结点 */ public static void postOrderRec(Node root){ TreeNode p = root; TreeNode q = null; while (!s.isEmpty()) { while (p != null) { s.push(p); p = p.left; } q = null; while (!s.isEmpty()) { p = s.pop(); if (p.right == q) { result.add(p.val); q = p; } else { s.push(p); p = p.right; break; } } } }
递归后序遍历,时间复杂度O(n),空间复杂度O(n) public static void postOrderRec(Node root){ if(root!=null){ preOrderRec(root.left); preOrderRec(root.right); System.out.println(root.value); } }