内容:
1、二叉树基础结构及常用函数
2、三种二叉树
3、二叉树的后继节点与前继节点
4、二叉树的序列化和反序列化
5、折纸问题
6、求树的节点
1、二叉树基础结构及常用函数
二叉树的基本结构:
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 // 递归先序遍历 2 public static void preOrderRecur(Node head){ 3 if(head == null){ 4 return; 5 } 6 System.out.print(head.value + " "); 7 preOrderRecur(head.left); 8 preOrderRecur(head.right); 9 } 10 11 // 递归中序遍历 12 public static void inOrderRecur(Node head){ 13 if(head == null){ 14 return; 15 } 16 inOrderRecur(head.left); 17 System.out.print(head.value + " "); 18 inOrderRecur(head.right); 19 } 20 21 // 递归后序遍历 22 public static void posOrderRecur(Node head){ 23 if(head == null){ 24 return; 25 } 26 posOrderRecur(head.left); 27 posOrderRecur(head.right); 28 System.out.print(head.value + " "); 29 } 30 31 // 非递归先序遍历 32 public static void preOrderUnRecur(Node head){ 33 System.out.print("pre-order: "); 34 if(head != null){ 35 Stack<Node> stack = new Stack<Node>(); 36 stack.add(head); 37 while(!stack.isEmpty()){ 38 head = stack.pop(); 39 System.out.print(head.value + " "); 40 if(head.right != null){ 41 stack.push(head.right); 42 } 43 if(head.left != null){ 44 stack.push(head.left); 45 } 46 } 47 } 48 } 49 50 // 非递归中序遍历 51 public static void inOrderUnRecur(Node head){ 52 System.out.print("in-order: "); 53 if(head != null){ 54 Stack<Node> stack = new Stack<Node>(); 55 while(!stack.isEmpty() || head != null){ 56 if(head != null){ 57 stack.push(head); 58 head = head.left; 59 } else{ 60 head = stack.pop(); 61 System.out.print(head.value + " "); 62 head = head.right; 63 } 64 } 65 } 66 } 67 68 // 非递归后序遍历 69 public static void posOrderUnRecur(Node head){ 70 System.out.print("pos-order: "); 71 if(head != null){ 72 Stack<Node> s1 = new Stack<Node>(); 73 Stack<Node> s2 = new Stack<Node>(); // 辅助栈 74 s1.push(head); 75 while(!s1.isEmpty()){ 76 head = s1.pop(); 77 s2.push(head); 78 if(head.left != null){ 79 s1.push(head.left); 80 } 81 if(head.right != null){ 82 s1.push(head.right); 83 } 84 } 85 86 while(!s2.isEmpty()){ 87 head = s2.pop(); 88 System.out.print(head.value + " "); 89 } 90 } 91 } 92 93 // 非递归按层遍历 -> 队列实现 94 public static void levelOrderUnRecur(Node head) { 95 System.out.print("level-order: "); 96 if (head != null) { 97 Queue<Node> que = new LinkedList<Node>(); 98 que.offer(head); 99 while (!que.isEmpty()) { 100 head = que.poll(); 101 System.out.print(head.value + " "); 102 if (head.left != null) { 103 que.offer(head.left); 104 } 105 if (head.right != null) { 106 que.offer(head.right); 107 } 108 } 109 } 110 System.out.println(); 111 }
打印二叉树:
下面是一个打印二叉树的福利函数,使用方法: 打印节点标志为H表示头节点 打印节点标志为v表示为右子树 打印节点标志为^表示为左子树
1 // 打印二叉树的入口函数 2 public static void printTree(Node head) { 3 System.out.println("Binary Tree:"); 4 printInOrder(head, 0, "H", 17); 5 System.out.println(); 6 } 7 8 // 打印二叉树的主逻辑函数 9 public static void printInOrder(Node head, int height, String to, int len) { 10 /* 11 * head 头节点 12 * height 当前高度 13 * to 代表是左子树还是右子树 => 为H时代表根节点 14 * len 代表每个节点最多占的宽度 15 * */ 16 if (head == null) { 17 return; 18 } 19 20 // 继续打印右子树 21 printInOrder(head.right, height + 1, "v", len); 22 23 String val = to + head.value + to; 24 int lenM = val.length(); // 节点(加上节点标志)的长度 25 int lenL = (len - lenM) / 2; // 节点左边的长度 26 int lenR = len - lenM - lenL; // 节点右边的长度 27 val = getSpace(lenL) + val + getSpace(lenR); // 为节点加上左右两边的空格 28 System.out.println(getSpace(height * len) + val); // 打印当前节点 29 30 // 继续打印左子树 31 printInOrder(head.left, height + 1, "^", len); 32 } 33 34 // 为节点加上左右两边的空格 35 public static String getSpace(int num) { 36 String space = " "; 37 StringBuffer buf = new StringBuffer(""); 38 for (int i = 0; i < num; i++) { 39 buf.append(space); 40 } 41 return buf.toString(); 42 }
2、三种二叉树
- 平衡二叉树:空树 或 二叉树的每个左右子树的高度差的绝对值不超过1
- 搜索二叉树:空树 或 左子树上所有结点的值均小于它的根结点的值以及右子树上所有结点的值均大于它的根结点的值
- 完全二叉树:空树 或 对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树
判断是否是平衡二叉树:
1 // 返回数据 2 public static class ReturnData{ 3 public boolean isB; 4 public int h; 5 6 public ReturnData(boolean isB, int h){ 7 this.isB = isB; 8 this.h = h; 9 } 10 } 11 12 // 判断一颗二叉树是否是平衡二叉树 13 public static boolean isB(Node head){ 14 return process(head).isB; 15 } 16 17 // 递归求解返回数据过程 => 列举多种可能性 18 // 不是平衡二叉树的情况: 1、左子树不是平衡二叉树 2、右子树不是平衡二叉树 3、左子树和右子树的高度差大于1 19 // 其他情况均是平衡二叉树: 空二叉树(高度为0)、不是以上三种情况的非空二叉树(高度为左右子树最大高度+1) 20 public static ReturnData process(Node head){ 21 if(head==null){ 22 return new ReturnData(true, 0); 23 } 24 ReturnData leftData = process(head.left); 25 if(!leftData.isB){ 26 return new ReturnData(false, 0); 27 } 28 ReturnData rightData = process(head.right); 29 if(!rightData.isB){ 30 return new ReturnData(false, 0); 31 } 32 if(Math.abs(leftData.h - rightData.h) > 1){ 33 return new ReturnData(false, 0); 34 } 35 return new ReturnData(true, Math.max(leftData.h, rightData.h) + 1); 36 }
判断是否是搜索二叉树:
1 // 借助非递归中序遍历实现(最简单的方法) -> 后一个节点必须大于前一个节点 2 public static boolean isBST(Node head) { 3 int pre = Integer.MIN_VALUE; 4 if (head != null) { 5 Stack<Node> stack = new Stack<Node>(); 6 while(!stack.isEmpty() || head!=null){ 7 if(head != null){ 8 stack.push(head); 9 head = head.left; 10 } else{ 11 head = stack.pop(); 12 if(head.value > pre){ 13 pre = head.value; 14 } else{ 15 return false; 16 } 17 head = head.right; 18 } 19 } 20 } 21 22 return true; 23 } 24 25 // 借助递归中序遍历实现 判断一棵二叉树是否是搜索二叉树 26 private static int pre = Integer.MIN_VALUE; 27 private static boolean flag; 28 public static void isBST2(Node head) { 29 if (head == null) { 30 return; 31 } 32 isBST2(head.left); 33 // 将当前节点和之前的数比较 如果大于说明满足搜索二叉树条件 否则不满足 34 if (head.value > pre) { 35 pre = head.value; 36 } else { 37 flag = false; 38 return; 39 } 40 isBST2(head.right); 41 }
判断是否是完全二叉树:
1 // 按层遍历 两种情况: 2 // 1、有右节点无左节点 直接返回false 3 // 2、有左节点无右节点或者左右节点都没有 那么如果接下来的节点都是叶节点就直接返回true 否则返回false 4 5 public static boolean isCBT(Node head) { 6 if (head == null) { 7 return true; 8 } 9 Queue<Node> queue = new LinkedList<Node>(); 10 boolean leaf = false; // 标志情况2是否发生 11 Node l = null; 12 Node r = null; 13 queue.offer(head); 14 while (!queue.isEmpty()) { 15 head = queue.poll(); 16 l = head.left; 17 r = head.right; 18 if (l == null && r != null) { 19 // 情况1 左空右不空 20 return false; 21 } 22 if (leaf && (l != null || r != null)) { 23 // 情况2 24 return false; 25 } 26 if (l != null) { 27 queue.offer(l); 28 } 29 if (r != null) { 30 queue.offer(r); 31 } else { 32 // 开启情况2 33 // 实质上就是左右均为空或左不空右空的情况 34 leaf = true; 35 } 36 } 37 return true; 38 }
3、二叉树的后继节点与前继节点
4、二叉树的序列化和反序列化
5、折纸问题
6、求树的节点