数据结构【树】-题目总结
树的宽度优先遍历(Java)
思路没什么好讲的,主要是用队列去实现。直接看code就可以明白。
class Node {
Node left;
Node right;
int value;
}
public static void bfs(Node head) {
if (head == null) {
return;
}
LinkedList<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()) {
Node x = queue.poll();
System.out.print(x.value);
if (x.left != null) {
queue.add(x.left);
}
if (x.right != null) {
queue.add(x.right);
}
}
}
求二叉树的宽度
宽度就是在二叉树中,如果某层的节点数最多,那么该节点数目就是这棵二叉树的宽度。
实现思路:在宽度优先遍历的基础上,定义一个HashMap,key存Node,value存层数。
import java.util.HashMap;
import java.util.LinkedList;
public class TreeMaxWidth {
public class Node {
Node left;
Node right;
int value;
}
public static int getMaxWidth(Node head) {
if (head == null) {
return 0;
}
LinkedList<Node> queue = new LinkedList<>();
HashMap<Node, Integer> levelMap = new HashMap<>();
queue.add(head);
levelMap.put(head, 1);
int curLevel = 0; //当前层数
int curLevelNodeNumber = 0; //当前层数的节点数
int max = 0; //最大
while (!queue.isEmpty()) {
Node x = queue.poll();
int xLevel = levelMap.get(x);
if (xLevel == curLevel) {
curLevelNodeNumber++;
} else {
//初始化当前层数和当前层个数
curLevel = xLevel;
max = Math.max(max, curLevelNodeNumber);
curLevelNodeNumber = 1;
}
System.out.print(x.value);
if (x.left != null) {
queue.add(x.left);
levelMap.put(x.left, curLevel + 1);
}
if (x.right != null) {
queue.add(x.right);
levelMap.put(x.right, curLevel + 1);
}
}
return max;
}
}
树的解题套路
1)前提:是否能把判断的流程定义为检查每一个节点的子树符合判断标准,并且答案一定在其中;
2)只要前提符合,就进行可能性分析(以左、右、中为顺序)
3)整合信息,求全集
套路的时间复杂度:O(n)。因为每个节点都给自己的父节点返回信息,而
总共有n个节点。
如何判断一棵二叉树是否为搜索二叉树
套路的思路:可以把判断分解为判断每一颗子树是否是搜索二叉树。所以前提符合,进行可能性分析:
1.左子树为搜索二叉树
2.右子树为搜索二叉树
3.左子树的最大值<节点值
4.右子树的最小值>节点值
最后再把四种可能性合并即可。
基于可能性分析,可以建立相应的类去判断:
public static class ReturnType {
public boolean isBST; //是否是搜索二叉树
public int max; //最大值
public int min; //最小值
public ReturnType(boolean isBST, int max, int min) {
this.isBST = isBST;
this.max = max;
this.min = min;
}
}
整体的code如下:
public class IsBST {
//节点定义
public static class Node {
public int value;
public Node left;
public Node right;
}
//主函数
public static boolean isBST(Node head) {
return process(head).isBST;//
}
/**
* 只要分析可能性,后面的套路都是一样的
* 四种可能性:左子树为bst,右子树为bst,左子树最大值<节点值,右子树最小值>节点值
*/
public static class ReturnType {
public boolean isBST;
public int max;
public int min;
public ReturnType(boolean isBST, int max, int min) {
this.isBST = isBST;
this.max = max;
this.min = min;
}
}
public static ReturnType process(Node x) {
if (x == null) {
//防止被干扰
return new ReturnType(true, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
//加工黑盒
ReturnType leftData = process(x.left);
ReturnType rightData = process(x.right);
//拆分黑盒
int max = Math.max(x.value, Math.max(leftData.max, rightData.max));
int min = Math.min(x.value, Math.min(leftData.min, rightData.min));
boolean isBST = leftData.isBST
& rightData.isBST
& leftData.max < x.value
& rightData.min > x.value;
return new ReturnType(isBST, max, min);
}
}
如何判断一棵二叉树是否为平衡二叉树
平衡二叉树的要求:左子树与右子树的高度差的绝对值不超过1
该题目符合套路的前提,所以直接进行可能性的分析:
1.左子树平衡
2.右子树平衡
3.左子树与右子树的高度差的绝对值不超过1
public class Code06_IsBalancedTree {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isBalanced(Node head) {
return process(head).isBalanced;
}
/**
* 可能性分析:左子树平衡、右子树平衡、高度差不超过1
*/
public static class ReturnType {
public boolean isBalanced;
public int height;
public ReturnType(boolean isBalanced, int height) {
this.isBalanced = isBalanced;
this.height = height;
}
}
public static ReturnType process(Node x) {
if (x == null) {
return new ReturnType(true, 0);
}
ReturnType leftData = process(x.left);
ReturnType rightData = process(x.right);
int height = Math.max(leftData.height, rightData.height);
boolean isBalanced = leftData.isBalanced && rightData.isBalanced
&& Math.abs(leftData.height - rightData.height) < 2;
return new ReturnType(isBalanced, height);
}
}
如何判断一棵二叉树为满二叉树
在二叉树中,高度为height,总节点树为nodes,若满足:
2^height-1 == nodes
则该二叉树为满二叉树。
public class isFullTree {
public static boolean isFull(Node head) {
ReturnType all = process(head);
int height = all.height;
int allNodes = all.nodes;
return (1 << height) - 1 == allNodes;
}
public static class ReturnType {
public int height; //高度
public int nodes; //节点数
public ReturnType (int height, int nodes) {
this.height = height;
this.nodes = nodes;
}
}
public static ReturnType process(Node x) {
if (x == null) {
return ReturnType(0, 0);
}
ReturnType left = process(x.left);
ReturnType right = process(x.right);
int height = Math.max(left.height, right.height);
int nodes = left.nodes + 1 + right.nodes;
return ReturnType(height, nodes);
}
}
如何判断一棵二叉树为完全二叉树
该题目可以用宽度优先遍历去解决。
思路分解:
1.如果一个节点有右无左节点,则返回false,否则返回true;
2.再1返回true的情况下,遇到第一个左右不双全的节点时,后继遇到的节点必须是叶子节点,否则false。
import java.util.LinkedList;
public class Code05_IsCBT {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isCBT(Node head) {
if (head == null) {
return true;
}
LinkedList<Node> queue = new LinkedList<>();
boolean leaf = false; //叶子节点阶段是否开启
Node left = null;
Node right = null;
queue.add(head);
while (!queue.isEmpty()) {
head = queue.poll();
left = head.left;
right = head.right;
//若叶子结点开启了,但左右还有节点,则false;若左空右不空,也返回false
if ((leaf && (left != null || right != null)) || (left == null && right != null)) {
return false;
}
//开启叶子节点阶段
if (left == null || right == null) {
leaf = true;
}
if (left != null) {
queue.add(l);
}
if (right != null) {
queue.add(r);
}
}
return true;
}
}
在一棵二叉树中,求两个给定节点的最低、公共祖先节点
实现思路:
将2个给定节点放入树中进行搜索,当碰到给定节点时,将节点向上返回,当两个节点相遇时,这个节点就是最低、公共祖先节点。
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static Node lowestAncestor(Node head, Node o1, Node o2) {
if (head == null || head == o1 || head == o2) {
return head;
}
Node left = lowestAncestor(head.left, o1, o2);
Node right = lowestAncestor(head.right, o1, o2);
if (left != null && right != null) {
return head;
}
return left != null ? left : right;
}