二叉树的遍历
先序遍历
递归方法
public static void preOrder1(TreeNode root){ if (root != null) { System.out.print(root.value+" "); preOrder1(root.left); preOrder1(root.right); } }
非递归方法。使用栈结构,每次出栈后,按照先右后左的方式将子树入栈。
public static void preOrder2(TreeNode root){ if (root == null) return; LinkedList<TreeNode> stack = new LinkedList<TreeNode>(); stack.push(root); while (!stack.isEmpty()){ TreeNode tn = stack.pop(); System.out.print(tn.value+" "); TreeNode left = tn.left; TreeNode right = tn.right; if (right != null) stack.push(right); if (left != null) stack.push(left); } }
中序遍历
递归方法
public static void inOrder1(TreeNode root){ if (root != null) { inOrder1(root.left); System.out.print(root.value+" "); inOrder1(root.right); } }
非递归方法
public static void inOrder2(TreeNode root) { if (root == null) return; LinkedList<TreeNode> stack = new LinkedList<TreeNode>(); TreeNode cur = root; while (cur != null || !stack.isEmpty()) {//cur!=null为了保证第一次能进入循环 if (cur == null){//当前节点为空要进行出栈操作,访问节点后再进入右子树 cur = stack.pop(); System.out.print(cur.value+" "); cur = cur.right; } else {//一直从左子树入栈 stack.push(cur); cur = cur.left; } } }
public static void inOrder3(TreeNode root) { if (root == null) return; LinkedList<TreeNode> stack = new LinkedList<TreeNode>(); TreeNode cur = root; while(cur !=null || !stack.isEmpty()) { while(cur != null) {//每次从当前节点的最左叶子节点开始访问,将遍历过的节点入栈 stack.push(cur); cur = cur.left; } if (!stack.isEmpty()) { cur = stack.pop(); System.out.print(cur.value+" "); cur = cur.right;//进入当前节点的右子树,用同样的方法访问 } } }
后序遍历
递归方法
//后序遍历 public static void postOrder1(TreeNode root){ if (root != null) { postOrder1(root.left); postOrder1(root.right); System.out.print(root.value+" "); } }
非递归方法
public static void postOrder2(TreeNode root) { LinkedList<TreeNode> stack = new LinkedList<TreeNode>(); TreeNode last = null;//记录上一次访问节点 TreeNode cur = root; while(cur != null || !stack.isEmpty()) { while (cur != null) {//找到当前节点的最左叶子节点 stack.push(cur); cur = cur.left; } cur = stack.peekFirst(); if (cur.right == null || cur.right == last) {//如果没有右子树或者右子树已经被访问过 cur = stack.pop(); last = cur; System.out.print(cur.value+" "); cur = null;//将当前节点置空,下次直接从栈中获取父节点信息 } else {//右子树没有访问过,访问右子树 cur = cur.right; } } }
层序遍历
public static void leverTraverse(TreeNode root) { if (root == null) return; LinkedList<TreeNode> queue = new LinkedList<TreeNode>(); queue.add(root); while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { TreeNode tn = queue.poll(); System.out.print(tn.value+" "); TreeNode left = tn.left; TreeNode right = tn.right; if (left != null) queue.add(left); if (right != null) queue.add(right); } } }
判断是否完全二叉树
- 完全二叉树:只有最下层节点的度可以小于2,并且最下面一层节点都集中在最左边。
- 方法:层序遍历,若出现一个节点的子树为空,则后面节点的子树均必须为空。
代码
public static boolean isComplateTree(TreeNode root) { LinkedList<TreeNode> queue = new LinkedList<TreeNode>(); boolean flag = true; queue.add(root); while (!queue.isEmpty()) { TreeNode tn = queue.poll(); TreeNode left = tn.left; TreeNode right = tn.right; if (flag) { if (left == null) flag = false; else queue.add(left); } else { if (left != null) return false; } if (flag) { if (right == null) flag = false; else queue.add(right); } else { if (right != null) return false; } } return true; }
判断是否同一棵树
代码
public static boolean compareTree(TreeNode root1, TreeNode root2) { if ((root1 == null && root2 != null) || (root1 != null && root2 == null)) return false; else if (root1 == null && root2 == null) return true; if (root1.value == root2.value) { return compareTree(root1.left, root2.left) && compareTree(root1.right, root2.right); } else { return false; } }
判断是否二叉排序树
- 方法:中序遍历的方法,保存上一次访问节点的值。
代码
static int pre = Integer.MIN_VALUE; //判断是否二叉排序树 public static boolean isBST(TreeNode root) { if (root == null) return true; if (isBST(root.left)) { if (pre < root.value) { pre = root.value; return isBST(root.right); } else return false; } else return false; }
是否平衡二叉树
- 方法:后序遍历,保证两颗子树高度差不超过1
代码
//是否平衡二叉树,小于0表示不是 public static int isBalanced(TreeNode root) { if (root == null) return 0; int lh = isBalanced(root.left); int rh = isBalanced(root.right); if (Math.abs(lh-rh) <= 1) { return Math.max(lh, rh)+1; } else return -1; }
查找最近公共祖先节点
- 方法:递归。
结束条件:root为其中一个节点或者root为null,返回root
分别对左右子树递归查找
左子树查找返回值为null,则两个节点肯定都在右子树上,公共祖先节点即为右递归的返回值;若左子树查找返回值不为null,判断右子树查找返回值,若为null,说明两个节点都在左子树上,公共祖先节点即为左递归返回值,若两个都不为null,则root即为公共祖先节点。 代码
//查找最近公共祖先节点 public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if (root == null || root == p || root == q) return root; TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); return left == null ? right : right == null ? left : root; }
构造树
已知先序和中序
public static TreeNode constructPreAndIn(int[] preOrder, int[] inOrder) { if (preOrder==null || inOrder == null || preOrder.length != inOrder.length) return null; return constructPreAndIn(preOrder, 0, preOrder.length-1, inOrder, 0, inOrder.length-1); } public static TreeNode constructPreAndIn(int[] preOrder, int pl, int pr, int[] inOrder, int il, int ir){ if (pl > pr){ return null; } TreeNode root = new TreeNode(preOrder[pl]); int pos = il; for (; pos <= ir; pos++) { if (inOrder[pos] == root.value) break; } root.left = constructPreAndIn(preOrder, pl+1, pl+pos-il, inOrder, il, pos-1); root.right = constructPreAndIn(preOrder, pl+pos-il+1, pr, inOrder, pos+1, ir); return root; }
已知后序和中序
public static TreeNode constructPostAndIn(int[] postOrder, int[] inOrder) { if (postOrder==null || inOrder == null || postOrder.length != inOrder.length) return null; return constructPostAndIn(postOrder, 0, postOrder.length-1, inOrder, 0, inOrder.length-1); } public static TreeNode constructPostAndIn(int[] postOrder, int pl, int pr, int[] inOrder, int il, int ir){ if (pl > pr){ return null; } TreeNode root = new TreeNode(postOrder[pr]); int pos = il; for (; pos <= ir; pos++) { if (inOrder[pos] == root.value) break; } root.left = constructPostAndIn(postOrder, pl, pl+pos-il-1, inOrder, il, pos-1); root.right = constructPostAndIn(postOrder, pr-(ir-pos), pr-1, inOrder, pos+1, ir); return root; }