二叉树
二叉树结构面试题目及解法
用到的树形结构类
package Tree;
public class TreeNode {
int value;
TreeNode left;
TreeNode right;
public TreeNode(int value){
this.value = value;
this.left = null;
this.right = null;
}
}
二叉树的遍历(先中后)
主函数类:
package Tree;
public class TreeMatin {
public static void main(String[] agrs){
//生成树形结构数据
TreeNode root = new TreeNode(1);
TreeNode rootLeft = new TreeNode(2);
TreeNode rootRight = new TreeNode(3);
root.left= rootLeft;
root.right = rootRight;
TreeNode rootLeftLeft = new TreeNode(4);
TreeNode rootLeftRight = new TreeNode(5);
rootLeft.left = rootLeftLeft;
rootLeft.right = rootLeftRight;
TreeNode rootRightLeft = new TreeNode(6);
TreeNode rootRightRight = new TreeNode(7);
rootRight.left = rootRightLeft;
rootRight.right = rootRightRight;
TreePractice treePractice = new TreePractice();
/**
* 递归实现二叉树遍历
* */
treePractice.ergodic(root);
/**
* 非递归实现二叉树遍历
* */
//先序遍历
System.out.print("先序");
treePractice.preOrderErgodic(root);
System.out.println();
//后序遍历
System.out.print("后序");
treePractice.posOrderErgodic(root);
System.out.println();
//中序遍历
System.out.print("中序");
treePractice.inOrderErgodic(root);
System.out.println();
}
}
实现类:
俩种实现方式:递归实现和非递归实现
package Tree;
import java.util.*;
public class TreePractice {
/**
* 递归实现数遍历
* */
public void ergodic(TreeNode root){
if(root == null) return;
// System.out.print(root.value+" "); //先序遍历
ergodic(root.left);
// System.out.print(root.value+" "); //中序遍历
ergodic(root.right);
System.out.print(root.value+" "); //后序遍历
}
/**
* 非递归实现数遍历
* */
/**
* 先序遍历
* 1、将根节点压进栈(后中序遍历和后序遍历相同,省略此步)
* 2、弹出一个栈,打印
* 3、判断是否有右节点,压进栈
* 4、判断是否有左结点,压进栈
* 5、循环
* */
public void preOrderErgodic(TreeNode root){
if (root==null) return;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
System.out.print(node.value+" ");
if(node.right != null) stack.push(node.right);
if (node.left != null) stack.push(node.left);
}
}
/**
* 后序遍历
* 1、从第一个栈中弹出一个结点,存进收集栈
* 2、循环第一步,直至所有结点都进第二个收集栈
* 3、弹出并打印收集栈
* */
public void posOrderErgodic(TreeNode root){
if (root==null) return;
Stack<TreeNode> stack = new Stack<>();
Stack<TreeNode> collectStack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
collectStack.push(node);
if(node.left!=null) stack.push(node.left);
if(node.right!=null) stack.push(node.right);
}
while (!collectStack.isEmpty()){
TreeNode node = collectStack.pop();
System.out.print(node.value+" ");
}
}
/**
* 中序遍历
* 1、将循环将结点的左节点全部压进栈
* 2、当所有左节点压进去后,当前结点为null,弹出一个结点
* 3、打印弹出的结点,判断该结点是否有右节点。如果有,当前结点变为该右节点
* 4、循环
* */
public void inOrderErgodic(TreeNode root){
if (root==null) return;
Stack<TreeNode> stack = new Stack<>();
while (!stack.isEmpty() || root != null){
if(root != null){
stack.push(root);
root = root.left;
}else {
root = stack.pop();
System.out.print(root.value + " ");
root = root.right;
}
}
}
}
题目一:求结点数最多的层
主函数类:
package Tree;
public class TreeMatin {
public static void main(String[] agrs){
//生成树形结构数据
TreeNode root = new TreeNode(1);
TreeNode rootLeft = new TreeNode(2);
TreeNode rootRight = new TreeNode(3);
root.left= rootLeft;
root.right = rootRight;
TreeNode rootLeftLeft = new TreeNode(4);
TreeNode rootLeftRight = new TreeNode(5);
rootLeft.left = rootLeftLeft;
rootLeft.right = rootLeftRight;
TreeNode rootRightLeft = new TreeNode(6);
TreeNode rootRightRight = new TreeNode(7);
rootRight.left = rootRightLeft;
rootRight.right = rootRightRight;
TreePractice treePractice = new TreePractice();
/**
* 宽度优先遍历
* 题目一: 求最多结点数的层数
* */
//使用队列和哈希表
treePractice.getMaxByQueueAndMap(root);
//使用队列
treePractice.getMaxByQueue(root);
}
}
实现类:
package Tree;
import java.util.*;
public class TreePractice {
/**
* 获取结点最多的层数
*宽度优先遍历
* */
//使用队列和map
public void getMaxByQueueAndMap(TreeNode root){
if(root == null) return;
Queue<TreeNode> queue = new LinkedList<>();
((LinkedList<TreeNode>) queue).add(root);
HashMap<TreeNode, Integer> levelMap = new HashMap<TreeNode, Integer>();
int level = 1;
levelMap.put(root,level);
int number = 1;
int max = Integer.MIN_VALUE;
int maxLevel = Integer.MIN_VALUE;
while(!queue.isEmpty()){
TreeNode tmp = ((LinkedList<TreeNode>) queue).poll();
int nodeLevel = levelMap.get(tmp);
if(nodeLevel == level){ //还在同一层
number++;
}else {
max = max>number?max:number;
maxLevel = max > number?maxLevel:level;
level++;
number = 1;
}
if (tmp.left != null){
((LinkedList<TreeNode>) queue).add(tmp.left);
levelMap.put(tmp.left,level+1);
}
if(tmp.right != null){
((LinkedList<TreeNode>) queue).add(tmp.right);
levelMap.put(tmp.right,level+1);
}
}
max = max>number?max:number;
maxLevel = max > number?maxLevel:level;
System.out.println(maxLevel+" 层的结点数为:"+max+" ,为最多");
}
//使用队列 俩个变量分别记录本层的最后一个结点和下一层的最后一个结点
public void getMaxByQueue(TreeNode root){
if (root == null) return;
Queue<TreeNode> queue = new LinkedList<>();
((LinkedList<TreeNode>) queue).add(root);
TreeNode curEnd = root;
TreeNode nextEnd = null;
int level = 1;
int max = Integer.MIN_VALUE;
int number = 1;
int maxLevel = Integer.MIN_VALUE;
while (!queue.isEmpty()){
TreeNode cur = queue.poll();
if(cur.left != null){
((LinkedList<TreeNode>) queue).add(cur.left);
nextEnd = cur.left;
}
if(cur.right != null){
((LinkedList<TreeNode>) queue).add(cur.right);
nextEnd = cur.right;
}
if(cur != curEnd){
number++;
}else {
max = max>number?max:number;
maxLevel = max>number?maxLevel:level;
level++;
number = 1;
curEnd = nextEnd;
}
}
System.out.println(maxLevel+" 层的结点数为:"+max+" ,为最多");
}
}
题目二:判断是否为搜索二叉树
主函数类:
package Tree;
public class TreeMatin {
public static void main(String[] agrs){
//生成树形结构数据
TreeNode root = new TreeNode(1);
TreeNode rootLeft = new TreeNode(2);
TreeNode rootRight = new TreeNode(3);
root.left= rootLeft;
root.right = rootRight;
TreeNode rootLeftLeft = new TreeNode(4);
TreeNode rootLeftRight = new TreeNode(5);
rootLeft.left = rootLeftLeft;
rootLeft.right = rootLeftRight;
TreeNode rootRightLeft = new TreeNode(6);
TreeNode rootRightRight = new TreeNode(7);
rootRight.left = rootRightLeft;
rootRight.right = rootRightRight;
TreePractice treePractice = new TreePractice();
/**
* 搜索二叉树: 所有子树均满足: 左<中<右
* 题目二: 判断二叉树是否是一棵二叉树
* */
boolean result = treePractice.isBST(root);
System.out.println("是否为搜索二叉树:"+result);
}
}
实现类:
package Tree;
import java.util.*;
public class TreePractice {
/**
* 判断是否是一棵搜索二叉树
*使用中序遍历(中序遍历一定为升序)
* */
public int tmp = Integer.MIN_VALUE;
public boolean isBST(TreeNode root){
if(root == null) return true;
boolean isBstLeft = isBST(root.left);
if(!isBstLeft) return false;
if(root.value <= tmp) return false;
else tmp = root.value;
boolean isBstRight = isBST(root.right);
return isBstRight;
}
}
题目三: 判断是否为完全二叉树
主函数类:
package Tree;
public class TreeMatin {
public static void main(String[] agrs){
//生成树形结构数据
TreeNode root = new TreeNode(1);
TreeNode rootLeft = new TreeNode(2);
TreeNode rootRight = new TreeNode(3);
root.left= rootLeft;
root.right = rootRight;
TreeNode rootLeftLeft = new TreeNode(4);
TreeNode rootLeftRight = new TreeNode(5);
rootLeft.left = rootLeftLeft;
rootLeft.right = rootLeftRight;
TreeNode rootRightLeft = new TreeNode(6);
TreeNode rootRightRight = new TreeNode(7);
rootRight.left = rootRightLeft;
rootRight.right = rootRightRight;
TreePractice treePractice = new TreePractice();
/**
* 题目三: 判断是否是完全二叉树
* */
boolean result = treePractice.isCBT(root);
System.out.println("是否为完全二叉树:"+result);
}
}
实现类:
package Tree;
import java.util.*;
public class TreePractice {
/**
* 判断是否是完全二叉树
* 使用宽度优先遍历
* */
public boolean isCBT(TreeNode root){
if(root == null) return true;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.add(root);
boolean isLeft = false;
while (!queue.isEmpty()){
TreeNode node = queue.poll();
if((isLeft && (node.left != null || node.right != null)) || (node.left == null && node.right != null)){
return false;
}
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
if(node.left == null || node.left == null) isLeft = true;
}
return true;
}
}
题目四:判断是否为平衡二叉树(树形DP套路解法)
主函数类:
package Tree;
public class TreeMatin {
public static void main(String[] agrs){
//生成树形结构数据
TreeNode root = new TreeNode(1);
TreeNode rootLeft = new TreeNode(2);
TreeNode rootRight = new TreeNode(3);
root.left= rootLeft;
root.right = rootRight;
TreeNode rootLeftLeft = new TreeNode(4);
TreeNode rootLeftRight = new TreeNode(5);
rootLeft.left = rootLeftLeft;
rootLeft.right = rootLeftRight;
TreeNode rootRightLeft = new TreeNode(6);
TreeNode rootRightRight = new TreeNode(7);
rootRight.left = rootRightLeft;
rootRight.right = rootRightRight;
TreePractice treePractice = new TreePractice();
/**
* 题目四:判断是否是平衡二叉树
* */
ReturnType result = treePractice.isBalanced(root);
System.out.println("该二叉树的层数有:"+result.height+" 是否为平衡二叉树:"+result.isBalanced);
}
}
实现类:
package Tree;
import java.util.*;
public class TreePractice {
/**
* 判断是否为平衡二叉树
* 树形DP *************
* DP套路: 将整棵树递归分为左右子树,分别向左右子树获取需要的信息,在进行封装返回
* */
public ReturnType isBalanced(TreeNode root){
if (root == null) return new ReturnType(true,0);
ReturnType result = isBalancedproccess(root);
return result;
}
public ReturnType isBalancedproccess(TreeNode node){
if(node == null) return new ReturnType(true,0);
ReturnType left = isBalancedproccess(node.left);
ReturnType right = isBalancedproccess(node.right);
int height = Math.max(left.height,right.height)+1;
boolean isBalanced = left.isBalanced && right.isBalanced && Math.abs(left.height - right.height) <2;
return new ReturnType(isBalanced,height);
}
}
题目五:判断是否是满二叉树(同树形DP套路解法)
主函数类:
package Tree;
public class TreeMatin {
public static void main(String[] agrs){
//生成树形结构数据
TreeNode root = new TreeNode(1);
TreeNode rootLeft = new TreeNode(2);
TreeNode rootRight = new TreeNode(3);
root.left= rootLeft;
root.right = rootRight;
TreeNode rootLeftLeft = new TreeNode(4);
TreeNode rootLeftRight = new TreeNode(5);
rootLeft.left = rootLeftLeft;
rootLeft.right = rootLeftRight;
TreeNode rootRightLeft = new TreeNode(6);
TreeNode rootRightRight = new TreeNode(7);
rootRight.left = rootRightLeft;
rootRight.right = rootRightRight;
TreePractice treePractice = new TreePractice();
/**
* 题目五:判断是否是满二叉树
* */
boolean result = treePractice.isFullTree(root);
System.out.println("是否为满二叉树:"+result);
}
}
实现类:
package Tree;
import java.util.*;
public class TreePractice {
/**
* 判断是否是满二叉树
* */
public boolean isFullTree(TreeNode root){
if(root == null) return true;
ReturnType2 result = isFullTreeProccess(root);
int number = (int) (Math.pow(2,result.height)-1);
boolean isFull = result.number == (Math.pow(2,result.height)-1) ? true: false;
return isFull;
}
public ReturnType2 isFullTreeProccess(TreeNode root){
if(root == null) return new ReturnType2(0,0);
ReturnType2 left = isFullTreeProccess(root.left);
ReturnType2 right = isFullTreeProccess(root.right);
int height = Math.max(left.height,right.height)+1;
int number = left.number+right.number+1;
return new ReturnType2(height,number);
}
}
题目六:求俩个点的最低公共祖先
主函数类:
package Tree;
public class TreeMatin {
public static void main(String[] agrs){
//生成树形结构数据
TreeNode root = new TreeNode(1);
TreeNode rootLeft = new TreeNode(2);
TreeNode rootRight = new TreeNode(3);
root.left= rootLeft;
root.right = rootRight;
TreeNode rootLeftLeft = new TreeNode(4);
TreeNode rootLeftRight = new TreeNode(5);
rootLeft.left = rootLeftLeft;
rootLeft.right = rootLeftRight;
TreeNode rootRightLeft = new TreeNode(6);
TreeNode rootRightRight = new TreeNode(7);
rootRight.left = rootRightLeft;
rootRight.right = rootRightRight;
TreePractice treePractice = new TreePractice();
/**
* 获取俩个结点的最小公共祖先
* */
//解法1:
TreeNode result = treePractice.getPublicNode(root,rootRightLeft,rootRight);
System.out.println("最小公共祖先是:"+result.value);
// 解法2
TreeNode result = treePractice.getPublicNode2(root,rootRightLeft,rootRight);
System.out.println("最小公共祖先是:"+result.value);
}
}
实现类:
package Tree;
import java.util.*;
public class TreePractice {
/**
* 求俩个点的最低公共祖先
* */
//解法一:
public TreeNode getPublicNode(TreeNode root,TreeNode node1,TreeNode node2){
if(root == null) return null;
HashMap<TreeNode,TreeNode> fatherMap = new HashMap<TreeNode, TreeNode>();
fatherMap.put(root,root);
setFatherProccess(root,fatherMap);
HashSet<TreeNode> setNodeFather = new HashSet<TreeNode>();
TreeNode cur1 = node1;
while(cur1 != fatherMap.get(cur1)){
setNodeFather.add(cur1);
cur1 = fatherMap.get(cur1);
}
TreeNode cur2 = node2;
while (cur2 != fatherMap.get(cur2)){
if(setNodeFather.contains(cur2)) break;
else{
cur2 = fatherMap.get(cur2);
}
}
return cur2;
}
//将所有结点的父节点放进哈希表
public void setFatherProccess(TreeNode root,HashMap<TreeNode,TreeNode> fatherMap){
if(root == null)return;
fatherMap.put(root.left,root);
fatherMap.put(root.right,root);
setFatherProccess(root.left,fatherMap);
setFatherProccess(root.right,fatherMap);
}
//解法二
public TreeNode getPublicNode2(TreeNode root,TreeNode node1,TreeNode node2){
if(root == null || root == node1 || root == node2) return root;
TreeNode left = getPublicNode2(root.left,node1,node2);
TreeNode right = getPublicNode2(root.right,node1,node2);
if(left != null && right != null) return root;
return left != null? left:right;
}
}
题目七: 二叉树的序列化和反序列化
主函数类:
package Tree;
public class TreeMatin {
public static void main(String[] agrs){
//生成树形结构数据
TreeNode root = new TreeNode(1);
TreeNode rootLeft = new TreeNode(2);
TreeNode rootRight = new TreeNode(3);
root.left= rootLeft;
root.right = rootRight;
TreeNode rootLeftLeft = new TreeNode(4);
TreeNode rootLeftRight = new TreeNode(5);
rootLeft.left = rootLeftLeft;
rootLeft.right = rootLeftRight;
TreeNode rootRightLeft = new TreeNode(6);
TreeNode rootRightRight = new TreeNode(7);
rootRight.left = rootRightLeft;
rootRight.right = rootRightRight;
TreePractice treePractice = new TreePractice();
/**
* 序列化
* */
String str = treePractice.serialByPre(root);
System.out.println("序列化结果为:"+ str);
/**
* 反序列化
* */
TreeNode node = treePractice.reconByPreString(str);
System.out.print("反序列化结果为:");
treePractice.inOrderErgodic(node);
}
}
实现类:
package Tree;
import java.util.*;
public class TreePractice {
/**
* 序列化
* */
public String serialByPre(TreeNode root){
if(root == null) return "#_";
String str = root.value+"_";
str += serialByPre(root.left);
str += serialByPre(root.right);
return str;
}
/**
* 反序列化
* */
public TreeNode reconByPreString(String str){
String[] strList = str.split("_");
Queue<String> queue = new LinkedList<String>();
for (String string:strList) ((LinkedList<String>) queue).add(string);
return reconByPreStringProccess(queue);
}
public TreeNode reconByPreStringProccess(Queue<String> queue){
String str = queue.poll();
if(str.equals("#")) return null;
TreeNode node = new TreeNode(Integer.parseInt(str));
node.left = reconByPreStringProccess(queue);
node.right = reconByPreStringProccess(queue);
return node;
}
}