1、判断二叉树是否是搜索二叉树(左>根>右)
方法一:设置一个值记录前一个数,和当前数做比较,(中序遍历)若一直递增则为搜索二叉树,一旦发现当前数没有大于后者,违反了搜索二叉树定义
package learn;
public class Test {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){//构造方法
this.value=value;
}
}
public static int preValue=Integer.MIN_VALUE;//记录中序遍历当前节点的前一个节点值
public static boolean checkBST(Node head) {//左根右
if (head == null) {
return true;
}
if(checkBST(head.left)==false){//左子树不是二叉搜索树,则此树不可能是二叉搜索树
return false;
}
if(head.value<=preValue){
return false;
}else {
preValue= head.value;
}
return checkBST(head.right);
}
}
方法二:中序遍历,将二叉树的值依次放入一个链表存储,然后打印观察
public static void checkBST2(Node head) {//左根右
List<Node> l = new ArrayList<>();
process(head, l);
for(int i=0;i<l.size();i++){
System.out.print(l.get(i)+" ");
}
}
public static void process(Node head,List<Node> l) {
if(head==null)return;
process(head.left,l);
l.add(head.value);
process(head.right,l);
}
方法三:按二叉树题目的套路解题,分为左子树、右子树,返回值类型为需要左子树提供的值和需要右子树提供的值的汇总
package learn;
public class Test {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){//构造方法
this.value=value;
}
}
public static class returnType{//定义递归返回值类型
public boolean isBST;//是否为搜索二叉树
public int min;//当前子树的最小值
public int max;
public returnType(boolean is,int min,int max){
isBST=is;
this.min=min;
this.max=max;
}
}
public static boolean isBST(Node head) {
return process(head).isBST;
}
public static returnType process(Node head) {
if(head==null){
return null;
}
int min=head.value;
int max=head.value;
returnType left=process(head.left);
returnType right=process(head.right);
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);
}
//当前树的min为其左子树最小值和根和右子树最小值 中的最小值
boolean isBST=true;
if(left!=null && (!left.isBST || left.max>=head.value)){//左子树不是二叉搜索树 或 左子树最大值不小于根
isBST=false;
}
if(right!=null && (!right.isBST || right.min<=head.value)){//右子树不是二叉搜索树 或 右子树最小值不大于根
isBST=false;
}
return new returnType(isBST,min,max);
}
}
2、判断是否为完全二叉树
节点不能有右无左,宽度优先遍历过程若遇到一个节点孩子不双全,从此节点后都应为叶子节点
public static boolean checkCBT(Node head) {
if(head==null){
return true;
}
boolean flag=false;//还未遇到孩子不双全的节点
Queue<Node> q=new LinkedList<>();
q.add(head);
Node l=null;
Node r=null;
while (!q.isEmpty()){
head=q.poll();
l=head.left;
r=head.right;
if(r!=null && l==null){//有右无左
return false;
}
if(flag && (l!=null || r!=null)){//已经遇到孩子不双全节点后,还遇到不为叶子的节点
return false;
}
if(l!=null){
q.add(l);
}
if (r!=null){
q.add(r);
}
if(l==null || r==null){
flag=true;
}
}
return true;
}
3、判断是否为平衡二叉树
package learn;
public class Test {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){//构造方法
this.value=value;
}
}
public static class returnType{//定义递归返回值类型
public boolean isBalanced;//是否为平衡二叉树
public int height;//树高度
public returnType(boolean is,int h){
isBalanced=is;
height=h;
}
}
public static boolean isBalanced(Node head) {
return process(head).isBalanced;
}
public static returnType process(Node head) {
if(head==null){
return new returnType(true,0);
}
returnType left=process(head.left);
returnType right=process(head.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);
}
}
4、判断是否为满二叉树
最后需要整棵树的节点值和深度,满足N=2^h-1,即为满二叉树
public class Test {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){//构造方法
this.value=value;
}
}
public static class returnType{//定义递归返回值类型
public int height;
public int nodes;
public returnType(int h,int n){
height=h;
nodes=n;
}
}
public static boolean isFull(Node head) {
returnType rt=process(head);
int h=rt.height;
int n=rt.nodes;
return n==Math.pow(2,h)-1;
}
public static returnType process(Node head) {
if(head==null){
return new returnType(0,0);
}
returnType left=process(head.left);
returnType right=process(head.right);
int height=Math.max(left.height, right.height)+1;
int nodes=left.nodes+right.nodes+1;
return new returnType(height,nodes);
}
}
5、给两个二叉树的节点o1,o2,找它们的最低公共祖先节点
(1)方法一:用一个HashMap来记录每个节点的双亲,然后o1往上走,在s中记录o1的各个祖先和自身(自身也可能为公共祖先),o2往上走,看o2自身和各祖先是否在s中
package learn;
import java.util.HashMap;
import java.util.HashSet;
public class Test {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){//构造方法
this.value=value;
}
}
public static Node lca(Node head,Node o1,Node o2) {
HashMap<Node,Node> h=new HashMap<>();
h.put(head,head);//设定head的祖先为它自己
process(head,h);
Node cur=o1;
HashSet<Node> s=new HashSet<>();
while (cur!=h.get(cur)){//往上走,直到根 根未放入s 根不放也没事 根是必然的公共祖先,若无其余非根祖先,则返回根
s.add(cur);
cur=h.get(cur);
}
s.add(head);
Node cur2=o2;
while (cur2!=h.get(cur2)){//o2往上走,看o2是否在s中
if(s.contains(cur2)){
return cur2;
}
cur2=h.get(cur2);
}
return head;
}
//此处利用先序遍历添加元素和其父节点的联系(任意二叉树遍历方式都可)
public static void process(Node head,HashMap<Node,Node> h) {
if(head==null){
return ;
}
if(head.left!=null){
h.put(head.left,head);
}
if(head.right!=null){
h.put(head.right, head);
}
process(head.left,h);
process(head.right,h);
}
}
(2)方法二:
public static Node lca(Node head,Node o1,Node o2) {
if(head==null || head==o1 || head==o2){
return head;
}
Node left=lca(head.left,o1,o2);
Node right=lca(head.right,o1,o2);
if(left!=null && right!=null){//说明左右各有o1、o2
return head;
}
return left!=null ? left: right;//返回有给定节点的
}
6、在二叉树中找到一个节点的后继节点(中序遍历)
该二叉树节点结构有指向其父亲的指针
package learn;
public class Test {
public static class Node{
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int value){//构造方法
this.value=value;
}
}
public static Node getNextNode(Node node) {
if(node==null){
return node;
}
if(node.right!=null){//有右子树 找node右孩子的最左
return getLeftMost(node.right);
}else {//无右子树
Node parent=node.parent;
while (parent!=null && node!=parent.left){
node=parent;
parent=node.parent;
}
return parent;
}
}
public static Node getLeftMost(Node node) {
if(node==null){
return node;
}
while (node.left!=null){
node=node.left;
}
return node;
}
}
7、二叉树的序列化和反序列化
若按先序:
(1)序列化:
public static String serialByPre(Node node) {//按先序 序列化
if(node==null){
return "#_";
}
String res=node.value+"_";//根
res+=serialByPre(node.left);//左
res+=serialByPre(node.right);//右
return res;
}
(2)反序列化:
package learn;
import java.util.LinkedList;
import java.util.Queue;
public class Test {
public static class Node{
public int value;
public Node left;
public Node right;
public Node(int value){//构造方法
this.value=value;
}
}
public static Node deserializeByPre(String s) {//按先序 序列化
String[] x=s.split("_");//x存储各节点信息
Queue<String> q=new LinkedList<>();
for(int i=0;i< x.length;i++){
q.add(x[i]);
}
//设置队列在于 每建好一个节点 此节点已经出队 找到下个节点很方便
return process(q);
}
public static Node process(Queue<String> q) {
String s=q.poll();
if(s.equals("#")) {//判断字符串是否相等 用equals
return null;
}
Node head=new Node(Integer.valueOf(s));//建根
head.left=process(q);//建左子树
head.right=process(q);//建右子树
return head;
}
}
8、题目:将纸条折叠N次,输出纸条打开后,从左至右,折痕的凹凸情况
public static void printALLFolds(int N) {//N:总需折叠次数
printProcess(1,N,true);
}
public static void printProcess(int i,int n,boolean x) {//i:当前折叠次数 x:标记为“凹”还是“凸”
if(i>n){
return;
}
printProcess(i+1,n,true);
System.out.println(x?"凹":"凸");
printProcess(i+1,n,false);
}