目录
二叉树前中后序遍历
递归
public static void preOrder(Node root) { if(root == null) { return; } System.out.println(root.value); preOrder(root.left); preOrder(root.right); } public static void inOrder(Node root) { if(root == null) { return; } preOrder(root.left); System.out.println(root.value); preOrder(root.right); } public static void postOrder(Node root) { if(root == null) { return; } preOrder(root.left); preOrder(root.right); System.out.println(root.value); }
非递归
二叉树非递归前序遍历: 准备一个栈,将头节点压栈,栈不为空时弹出打印当前节点,先压右再压左(弹出时就是左右)
非递归后序遍历: 准备两个栈,将头节点压栈,栈不为空时弹出,加入收集栈,先压左再压右(收集栈中加入顺序就是先右再左,弹出就是左右)
非递归中序遍历: 准备一个栈,如果当前节点不为null将当前节点压入栈,该节点更新为该节点的左孩子,如果为null,弹出一个节点(父节点)赋给当前并打印,将当前节点设为右孩子,遍历当前节点的右子树。
public static void pre(Node root) { if(root == null) { return; } Stack<Node> stack = new Stack<>(); stack.push(root); while(!stack.isEmpty()) { Node node = stack.pop(); System.out.println(node.value); if(node.right != null) { stack.push(node.right); } if(node.left != null) { stack.push(node.left); } } } public static void in(Node root) { if(root == null) { return; } Stack<Node> stack = new Stack<>(); while(!stack.isEmpty() || root != null) { if(root != null) { stack.push(root); root = root.left; }else { root = stack.pop(); System.out.println(root.value);//整棵树被分解为左头 左头打印 root = root.right; } } } public static void post(Node root) { if(root == null) { return; } Stack<Node> stack = new Stack<>(); Stack<Node> temp = new Stack<>(); stack.push(root); while(!stack.isEmpty()) { Node node = stack.pop(); temp.push(node); if(node.left != null) { stack.push(node.left); } if(node.right != null) { stack.push(node.right); } } while(!temp.isEmpty()) { System.out.println(temp.pop().value); } }
层序遍历
准备一个队列,先将根节点加入到队列中,循环弹出打印,依次将左右孩子加入队列
求二叉树层中最大元素的个数:
1、用哈希表记录每个节点的层数,如果从队列中弹出的不是当前层就更新,循环结束后再更新一下最后一层
2、准备三个变量curend(当前层的最后一个节点)初始置为根节点, nextend(下一层最后一个节点)初始置为null,num = 0记录个数。 每次弹出队列时与当前curend作比较,若不是最后一个将左右孩子加入队列并更新nextend值,若是最后一个就将nextend的值赋给curend,nextend置为空,更新最大节点数。
额外空间(哈希表)
public static int process(Node root) { if(root == null) { return 0; } Queue<Node> queue = new LinkedList<>(); queue.add(root); //记录节点在那一层 Map<Node,Integer> map = new HashMap<>(); int curlevel = 1; int max = Integer.MIN_VALUE; int count = 0;//记录当前层有几个节点 map.put(root, 1); while(!queue.isEmpty()) { root = queue.remove(); int curNodeLevel = map.get(root); if(curlevel != curNodeLevel) { curlevel++; max = Math.max(max, count); count = 0; }else count++; if(root.left != null) { queue.add(root.left); map.put(root.left,curNodeLevel + 1); } if(root.right != null) { queue.add(root.right); map.put(root.right,curN odeLevel + 1); } } return Math.max(max, count); }
不用额外空间
public static int process2(Node root) { if(root == null) { return 0; } int max = Integer.MIN_VALUE; int count = 1; Node curend = root;//当前层的最后节点 Node nextend = null;//下一层的最后节点 Queue<Node> queue = new LinkedList<>(); while(!queue.isEmpty()) { root = queue.remove(); if(root.left != null) { queue.add(root.left); nextend = root.left; } if(root.right != null) { queue.add(root.right); nextend = root.right; } //如果当前节点为最后节点就结算 if(root == curend) { curend = nextend;//滚动更新 nextend = null; max = Math.max(max, count); count = 0; }else count++; } return max; }
判断一棵树是否是二叉搜索树
中序遍历,肯定有序,若后遍历的小于前个节点的value就不是
package com.wtp.二叉树; import java.util.Stack; public class 判断一棵树是否是搜索二叉树 { public static void main(String[] args) { } static int preValue = Integer.MIN_VALUE; public static boolean is1(Node root) { if(root == null){ return true; } //左树不是则整体不是 boolean left = is1(root.left); if(!left) return false; if(root.value >= preValue) { preValue = root.value; }else return false;//当前节点小于左子树也不是 return is1(root.right); } public static boolean is2(Node root) { if(root == null) { return true; } int preValue = Integer.MIN_VALUE; Stack<Node> stack = new Stack<>(); boolean is = true; while(root != null || !stack.isEmpty()) { if(root != null) { stack.push(root); root = root.left; }else { root = stack.pop(); if(root.value >= preValue) { preValue = root.value; }else return false; root = root.right; } } return true; } public static boolean is3(Node root) { return process1(root).is; } public static class Info{ int max; int min; boolean is; public Info(boolean is,int min,int max) { this.min = min; this.max = max; this.is = is; } } public static Info process1(Node root) { if(root == null) { return null; } Info left = process1(root.left); Info right = process1(root.right); boolean is = true; int min = root.value; int max = root.value; if(left != null) { min = Math.min(min,left.min); max = Math.max(max,left.max); } if(right != null) { min = Math.min(min,right.min); max = Math.max(max,right.max); } if(left != null && (left.max > root.value || !left.is)){ is = false; } if(right != null && (right.min < root.value || !right.is)){ is = false; } return new Info(is,min,max); } }
判断一棵树是否是完全二叉树
层序遍历,如果有右孩子没左孩子则不是,如果都有继续判断,如果有左没右则判断剩余节点是不是叶子节点,不是则不是
package com.wtp.二叉树; import java.util.LinkedList; import java.util.Queue; public class 判断一棵树是否是完全二叉树 { public static void main(String[] args) { } public static boolean is1(Node root) { if(root == null) { return true; } Queue<Node> queue = new LinkedList<>(); boolean is = false; queue.add(root); while(!queue.isEmpty()) { root = queue.remove(); //如果有右孩子无左孩子 则一定不是完全二叉树 if(root.left == null && root.right != null) { return false; } //如果遇到左右孩子不双全的节点后 有节点不是叶子节点就不是完全二叉树 if(is && (root.right != null || root.left != null)) { return false; } if(root.left != null) { queue.add(root.left); } if(root.right != null) { queue.add(root.right); } //左右孩子不双全 if(root.left == null || root.right == null) { //遇到该事件后 后面的所有节点都应为叶子节点 is = true; } } return true; } }
判断一棵树是否是平衡二叉树
递归遍历左右子树,返回类型自定义为树高和是否平衡的对象
package com.wtp.二叉树; public class 判断一棵树是否是平衡二叉树 { public static void main(String[] args) { } public static boolean is1(Node root) { return process1(root).isAVL; } public static class Info { int height; boolean isAVL; public Info(int height, boolean isAVL) { this.height = height; this.isAVL = isAVL; } } public static Info process1(Node root) { if(root == null) { return new Info(0,true); } Info left = process1(root.left); Info right = process1(root.right); int height = Math.max(left.height, left.height) + 1; boolean is = Math.abs(left.height - right.height) < 2 && left.isAVL && right.isAVL; return new Info(height,is); } }
判断一棵树是否是满二叉树
求树深l 节点个数N 是否满足关系:N = 2^l - 1
package com.wtp.二叉树; public class 判断一棵树是否是满二叉树 { public static void main(String[] args) { } public static class info{ int nodeCount; int shen; public info(int count,int s) { shen = s; nodeCount = count; } } public static boolean is1(Node root) { if(root == null) { return true; } info info = process1(root); return (1 << info.shen) - 1 == info.nodeCount; } public static info process1(Node root) { if(root == null) { return new info(0,0); } info left = process1(root.left); info right = process1(root.right); int count; int shen; count = left.nodeCount + right.nodeCount + 1; shen = Math.max(left.shen, right.shen) + 1; return new info(count,shen); } }
最低公共祖先
找同处于一棵树的两节点的最低公共祖先: 1、先遍历树,将每个节点加入到map中,value-为父节点,再让o1往上窜将整个链加入到set中,最后让o2往上窜在set中找共同节点 2、深搜,搜索到o1或者o2直接返回,null就返回null,返回左右节点不为空的点,如果有节点左右都不为null说明就是公共祖先返回这个节点
package com.wtp.二叉树; import java.util.HashMap; import java.util.HashSet; import java.util.Map; public class 最低公共祖先 { public static void main(String[] args) { } public static Node lca2(Node root,Node o1,Node o2) { //在左右遍历时要么返回null 要么返回找到的o1或o2节点 if(root == null || root == o1 || root == o2) { return root; } Node left = lca2(root.left,o1,o2); Node right = lca2(root.right,o1,o2); //如果左右子树都各自找到了o1及o2节点就返回此节点 if(left != null && right != null) { return root; } //谁不为null就返回谁 return left == null ? right : left; } public static Node lca(Node root,Node o1,Node o2) { //key-树中的每个节点 value-各个节点对应的父节点 HashMap<Node,Node> fatherMap = new HashMap<>(); process(root,fatherMap); fatherMap.put(root, root); //记录o1或o2 往上窜的链 HashSet<Node> set = new HashSet<>(); Node cur = o1; while(cur != fatherMap.get(cur)) { set.add(cur); cur = fatherMap.get(cur); } set.add(root); cur = o2; //如果o2在往上窜的过程中遇到o1中的链中的节点 此节点就为最低公共祖先 while(!set.contains(cur)) { cur = fatherMap.get(cur); } return cur; } //将每个节点及其父节点放入map public static void process(Node root,HashMap<Node,Node> map) { if(root == null) { return ; } map.put(root.left, root); map.put(root.right, root); process(root.left,map); process(root.right,map); } }
后继节点
给定一个节点,返回该节点的后继节点
后继节点:中序遍历中一个节点的下一个节点 前驱节点:中序遍历中一个节点的前一个节点
找一个节点的后继节点: 若该节点有右节点,返回右子树的最左节点,若该节点没右节点判断该节点是否是父节点的左子树,是就返回父节点,否则就往上移动寻找
package com.wtp.二叉树; public class 后继节点 { public static void main(String[] args) { } //后继节点是指 中序遍历的顺序中任一节点的下一个节点 public static Node process(Node root) { if(root == null) { return null; } //如果有右子树 中序遍历的后继节点为右子树的最左的节点 if(root.right != null) { return getright(root.right); } Node parent = root.parent; //走到这一步时无右子树 看该节点是否为父节点的左孩子 while(root != parent.left && parent != null) { root = parent; parent = root.parent; } return parent; } //返回以root为根的最左边的节点 public static Node getright(Node root) { if(root == null) return null; while(root.left != null) { root = root.left; } return root; } }
序列化与反序列化
内存结构=>字符串:序列化 字符串=>内存结构:反序列化
package com.wtp.二叉树; import java.util.LinkedList; import java.util.Queue; public class 序列化与反序列化 { public static String xu(Node root) { if(root == null) return "#_"; String v = root.value + "_"; v += xu(root.left); v += xu(root.right); return v; } public static Node fan(String str) { String[] values = str.split("_"); Queue<String> queue = new LinkedList<>(); for(String s : values) { queue.add(s); } return f(queue); } public static Node f(Queue<String> queue) { String value = queue.poll(); if(value.equals("#")) { return null; } Node node = new Node(Integer.parseInt(value)); node.left = f(queue); node.right = f(queue); return node; } }
折纸
给一张长条纸,捏住一端,反复折叠n次后打开,打印从捏住端往下的凹凸折痕顺序
package com.wtp.二叉树; public class 折纸 { public static void main(String[] args) { process(1,true); } static int count = 3; public static void process(int n,boolean b) { if(n > count) { return; } process(n + 1,true); System.out.println(b ? "凹" : "凸"); process(n + 1,false); } }