简述
你真的了解二叉树吗?
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。
这是表面上的二叉树,本文将基于二叉树的前中后序遍历解决一些求解二叉树的相关问题,感兴趣的就继续往下看吧。
定义二叉树的结点
二叉树是结点的有限集合,那么结点就必不可少啦:
public class TreeNode {
public TreeNode left;
public TreeNode right;
public int value;
public TreeNode(int value) {
this.value = value;
}
}
二叉树的前中后序遍历
二叉树的前中后序遍历运用了递归的方法,根结点单独考虑,然后对左右子树采用相同的方法:
public class TreeTraversal {
//前序遍历
public static void preTraversal(Node root){
if(root!=null) {
System.out.printf("%c",root.val);
preTraversal(root.left);
preTraversal(root.right);
}else{
//不处理
}
}
//中序遍历
public static void inTraversal(Node root){
if(root!=null){
inTraversal(root.left);
System.out.printf("%c",root.val);
inTraversal(root.right);
}else{}
}
//后序遍历
public static void postTraversal(Node root){
if(root!=null){
postTraversal(root.left);
postTraversal(root.right);
System.out.printf("%c",root.val);
}else{}
}
}
你品,你细品,这方法是不是很巧妙,那么接下来,别眨眼,套路他这就来了…
计算结点个数
计算二叉树结点的个数
public static int sumNodeSize(Node root){
if(root==null){
return 0;
}else {
int rootNodeSize = 1;//根结点单独考虑
//对左右子树采用相同的方法
int leftNodeSize = sumNodeSize(root.left);
int rightNOdeSize = sumNodeSize(root.right);
return rootNodeSize + leftNodeSize + rightNOdeSize;
}
}
第k层结点个数
求二叉树第k层结点个数
public static int sumKlevelNodeSize(TreeNode root,int k){
//根结点单独考虑
if(root==null){
return 0;
}else if(k==1){
return 1;
}else{
//对左右子树采用相同的方法
int leftsumk_1=sumKlevelNodeSize(root.left,k-1);
int rightsumk_1=sumKlevelNodeSize(root.right,k-1);
return leftsumk_1+rightsumk_1;
}
}
二叉树的高度
给定一棵二叉树,求它的高度:
public static int getHeight(TreeNode root){
//根结点单独考虑
if(root==null){
return 0;
}else if(root.left==null&&root.right==null){
return 1;
}else{
//对左右子树采用相同的方法
int leftheight=getHeight(root.left);
int rightheight=getHeight(root.right);
return Math.max(leftheight,rightheight)+1;
}
}
是否有结点值为v
给定一棵二叉树,给定一个值,判断二叉树中是否包含值为指定值的结点:
public static boolean contains(TreeNode root,int v){
//根结点单独考虑
if(root==null){
return false;
}else if(root.value==v){
return true;
}else{
//对左右子树采用相同的方法
boolean leftCon=contains(root.left,v);
if(leftCon){
return true;
}else {
boolean rightCon=contains(root.right,v);
if(rightCon){
return true;
}else{
return false;
}
}
}
}
怎么样是不是很惊喜,我连注释的文案都没改呢。
下面再奉上一些相关面试题,里面也有相关应用,入股不亏!
平衡二叉树
输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
此处提供一种思路:求结点左右子树高度再通过高度差判断是否为平衡二叉树。
public class balanceTreeJZ55 {
public boolean isBalanced(TreeNode root) {
//单独考虑根结点
if(root==null){
return true;
}
//用到刚才求高度的方法
int lefth=getHeight(root.left);
int righth=getHeight(root.right);
int dif=lefth-righth;
//判断高度差是否<=1
if(!(dif==-1||dif==0||dif==1)){
return false;
}
//对左右子树采用相同的方法 得到的结果结合得出最终结果
return isBalanced(root.left)&&isBalanced(root.right);
}
private int getHeight(TreeNode root) {
if(root==null){
return 0;
}
return Math.max(getHeight(root.right),getHeight(root.left))+1;
}
}
另一个树的子树
给定两个非空二叉树 s 和 t,检验 s 中是否包含和 t 具有相同结构和节点值的子树。s 的一个子树包括 s 的一个节点和这个节点的所有子孙。s 也可以看做它自身的一棵子树。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subtree-of-another-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
此处提供一种思路:如果s为空树,那么一定返回false,如果s跟q的值相等,那么需要单独判断他们两是否为相同的树,相同的话,就返回true,不相同继续判断,最后,继续判断左子树右子树是否包含就可以了。
public class isSonTree572 {
//判断是否为相同树
public boolean isSameTree(TreeNode p, TreeNode q) {
//两者皆为空树
if(p==null&&q==null){
return true;
}
//有一个是空树
if(p==null||q==null){
return false;
}
//根结点相等并且左右子树也互为相同树
return p.value==q.value&&isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);
}
public boolean isSubtree(TreeNode s, TreeNode t) {
//s为空时
if(s==null){
return false;
}
//根结点就相等时
if(s.value==t.value){
if(isSameTree(s,t)){
return true;
}
}
//通过对左右子树采用相同的方法 判断左右子树是否有该子树
if(isSubtree(s.left,t)){
return true;
}
return isSubtree(s.right,t);
}
}
二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
此处提供一种方法,当两个结点都在左子树中那么最近公共祖先也在里面(右同),如果一个在左子树,一个在右子树那么最近公共祖先就是根结点。需要单独写一个方法判断结点是在左子树还是右子树,详见代码:
public class nearestAncestor236 {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//根结点单独考虑
if(p==root||q==root){
return root;
}
//对左右子树采用相同的方法
boolean pInleft=search(root.left,p);
boolean qInleft=search(root.left,q);
//两个结点都在左子树
if(pInleft&&qInleft){
return lowestCommonAncestor(root.left,p,q);
}
//两个结点都在右子树
else if(!pInleft&&!qInleft){
return lowestCommonAncestor(root.right,p,q);
}
//一个在左 一个在右 最近祖先为根结点
else{
return root;
}
}
//单独写一个方法判断结点在左子树还是右子树 即判断以root为跟的子树里是否有t结点
private boolean search(TreeNode root, TreeNode t) {
//根为空
if(root==null){
return false;
}
//跟结点就是
if(root==t){
return true;
}
//对左右子树采用相同的方法
return search(root.left,t)||search(root.right,t);
}
}
好啦,看了这么多题目是不是有晕,反正小编是有点脑壳疼了,慢慢消化吧,我们下期再见,如有误之处还请批评指正。