二叉树
0、二叉树结点的构造
1 public static class Node { 2 public int value; 3 public Node left; 4 public Node right; 5 6 public Node(int data) { 7 this.value = data; 8 } 9 }
1、前序的非递归遍历:
栈中每次弹出的当前结点后:打印弹出结点val值,有右先压右,有左后压左
1 public static void preOrderUnRecur(Node head) { 2 System.out.print("pre-order: "); 3 if (head != null) { 4 Stack<Node> stack = new Stack<Node>(); 5 stack.add(head); 6 while (!stack.isEmpty()) { 7 head = stack.pop(); 8 System.out.print(head.value + " "); 9 if (head.right != null) { 10 stack.push(head.right); 11 } 12 if (head.left != null) { 13 stack.push(head.left); 14 } 15 } 16 } 17 System.out.println(); 18 }
2、中序的非递归遍历
当前结点不为空:压栈,当前结点往左走
当前结点为空:弹栈,打印弹出结点的val值,当前结点往右走
1 public static void inOrderUnRecur(Node head) { 2 System.out.print("in-order: "); 3 if (head != null) { 4 Stack<Node> stack = new Stack<Node>(); 5 while (!stack.isEmpty() || head != null) { 6 if (head != null) { 7 stack.push(head); 8 head = head.left; 9 } else { 10 head = stack.pop(); 11 System.out.print(head.value + " "); 12 head = head.right; 13 } 14 } 15 } 16 System.out.println(); 17 }
3、后序的非递归遍历
已知前序是:中--左--右,先转换成:中--右--左,然后申请一个辅助栈颠倒成:左--右--中,接着遍历打印辅助栈内结点的val值
那么如何使用辅助栈颠倒成:左--右--中呢?
在弹栈的时候不打印结点val值而是将其压入辅助栈
1 public static void posOrderUnRecur(Node head) { 2 System.out.print("pos-order: "); 3 if (head != null) { 4 Stack<Node> s1 = new Stack<Node>(); 5 Stack<Node> s2 = new Stack<Node>(); 6 s1.push(head); 7 while (!s1.isEmpty()) { 8 head = s1.pop(); 9 s2.push(head); 10 if (head.left != null) { 11 s1.push(head.left); 12 } 13 if (head.right != null) { 14 s1.push(head.right); 15 } 16 } 17 while (!s2.isEmpty()) { 18 System.out.print(s2.pop().value + " "); 19 } 20 } 21 System.out.println(); 22 }
4、判断二叉树是否完全相同
同样可以用来判断二叉树是否对称,如下所示:
1
/ \
2 2
/ \ / \
3 4 4 3
1 boolean isSameTree(TreeNode root1, TreeNode root2) { 2 // 都为空的话,显然相同 3 if (root1 == null && root2 == null) return true; 4 // 一个为空,一个非空,显然不同 5 if (root1 == null || root2 == null) return false; 6 // 两个都非空,但 val 不一样也不行 7 if (root1.val != root2.val) return false; 8 9 // root1 和 root2 该比的都比完了 10 return isSameTree(root1.left, root2.left) 11 && isSameTree(root1.right, root2.right); 12 }
5、判断一个树是否为二叉搜索树
1 boolean isValidBST(TreeNode root) { 2 return isValidBST(root, null, null); 3 } 4 5 boolean isValidBST(TreeNode root, TreeNode min, TreeNode max) { 6 if (root == null) return true; 7 if (min != null && root.val <= min.val) return false; 8 if (max != null && root.val >= max.val) return false; 9 return isValidBST(root.left, min, root) 10 && isValidBST(root.right, root, max); 11 }
6、在BST中查找数字target是否存在
1 boolean isInBST(TreeNode root, int target) { 2 if (root == null) return false; 3 if (root.val == target) 4 return true; 5 if (root.val < target) 6 return isInBST(root.right, target); 7 if (root.val > target) 8 return isInBST(root.left, target); 9 }
7、在BST中插入一个数
1 TreeNode insertIntoBST(TreeNode root, int val) { 2 // 找到空位置插入新节点 3 if (root == null) return new TreeNode(val); 4 // if (root.val == val) 5 // BST 中一般不会插入已存在元素 6 if (root.val < val) 7 root.right = insertIntoBST(root.right, val); 8 if (root.val > val) 9 root.left = insertIntoBST(root.left, val); 10 return root; 11 }
8、在BST中删除一个数
情况 1:A 恰好是末端节点,两个子节点都为空,那么它可以当场去世了。
情况 2:A 只有一个非空子节点,那么它要让这个子节点接替自己的位置。
情况 3:A 有两个子节点,麻烦了,为了不破坏 BST 的性质,A 必须找到左子树中最大的那个节点,或者右子树中最小的那个节点来接替自己。这里我门用后者来解决这种情况。
1 TreeNode deleteNode(TreeNode root, int key) { 2 if (root == null) return null; 3 if (root.val == key) { 4 // 这两个 if 把情况 1 和 2 都正确处理了 5 if (root.left == null) return root.right; 6 if (root.right == null) return root.left; 7 // 处理情况 3 8 TreeNode minNode = getMin(root.right); 9 root.val = minNode.val; 10 root.right = deleteNode(root.right, minNode.val); 11 } else if (root.val > key) { 12 root.left = deleteNode(root.left, key); 13 } else if (root.val < key) { 14 root.right = deleteNode(root.right, key); 15 } 16 return root; 17 } 18 19 TreeNode getMin(TreeNode node) { 20 // BST 最左边的就是最小的 21 while (node.left != null) node = node.left; 22 return node; 23 }