1.树形dp套路
树形dp套路使用前提:
如果题目求解目标是S规则,则求解流程可以定成以每一个节点为头节点的子树在S规则下的每一个答案,并且最终答案一定在其中。
树形dp套路第一步:
以某个节点X为头节点的子树中,分析答案有哪些可能性,并且这种分析是以X的左子树、X的右子树和X整棵树的角度来考虑可能性的。
树形dp套路第二步:
根据第一步的可能性分析,列出所有需要的信息。
树形dp套路第三步:
合并第二步的信息,对左树和右树提出同样的要求,并写出信息结构。
树形dp套路第四步:
设计递归函数,递归函数是处理以X为头节点的情况下的答案。
包括设计递归的basecase,默认直接得到左树和右树的所有信息,以及把可能性做整合,并且要返回第三步的信息结构这四个小步骤。
2.二叉树节点间的最大距离
从二叉树的节点a出发,可以向上或者向下走,但沿途的节点只能经过一次,到达节点b时路径上的节点个数叫作a到b的距离,那么二叉树任何两个节点之间都有距离,求整棵树上的最大距离。(leetcode543)
例如:
a
/ \
/ \
b c
/ \
/ \
d f
/ \
/ \
k s
d-f的距离为2;d-k的距离为k。
思路:假设以x为节点,先求以x为根节点的这棵树的最大深度是多少(具体情况区分为包含头节点和不包含头节点)。最大距离划分:
(1)x不参与。此时可以划分为左边的最大距离和以右边为最大距离。总最大距离为max{左最大距离,右最大距离}
(2)x参与。此时最大距离为x左树上的最大距离,加上x右树上的最大距离。此时可以通过比较左右两树的深度(高度)来比较,总最大距离为:左高+1+右高
对于任意节点 x:
时间复杂度:O(N),每个节点只处理一次。
空间复杂度:O(H),递归调用栈最多占用树的高度 H;最坏情况下退化为 O(N)。
这正好对应树形 DP 的四步:分析可能性 → 确定需要的信息 → 设计 Info → 递归整合左右子树的信息。
3.派对的最大快乐值
员工信息的定义如下:
class Employee {
public int happy; // 这名员工可以带来的快乐值
List<Employee> subordinates; // 这名员工有哪些直接下级
}
公司的每个员工都符合 Employee 类的描述。整个公司的人员结构可以看作是一棵标准的、没有环的多叉树。树的头节点是公司唯一的老板。除老板之外的每个员工都有唯一的直接上级。叶节点是没有任何下属的基层员工(subordinates列表为空),除基层员工外,每个员工都有一个或多个直接下级。
这个公司现在要办party,你可以决定哪些员工来,哪些员工不来。但是要遵循如下规则:
-
如果某个员工来了,那么这个员工的所有直接下级都不能来。
-
派对的整体快乐值是所有到场员工快乐值的累加。
-
你的目标是让派对的整体快乐值尽量大。
给定一棵多叉树的头节点boss,请返回派对的最大快乐值。
例如:
10x
/ | \
/ | \
3x 20y 40y
/ | / \
/ | / \
60y 3x 5x 6x
如此,能够做到最大快乐值为120。
x(头)
/ | \
/ | \
a b c
分析设x为头节点,
在x参与情况下:
x(乐)+a(a不来/a整棵树,最大快乐值)+b(b不来/b整棵树,最大快乐值)+c(b不来/无c整棵树,最大快乐值)
在x不参与的情况下:
0+max{a来时整棵树最大快乐值,a不来整棵树最大快乐值}+max{b来时整棵树最大快乐值,b不来整棵树最大快乐值}+max{c来时整棵树最大快乐值,c不来整棵树最大快乐值}
示例代码:
package Class012;
import java.util.ArrayList;
import java.util.List;
public class Code_MaxHappy {
public static int maxHappy(int[][] matrix){
int[][] dp=new int[matrix.length][2];
boolean[] visited=new boolean[matrix.length];
int root=0;
for (int i=0;i<matrix.length;i++){
if (i==matrix[i][0]){
root=i;
}
}
process(matrix,dp,visited,root);
return Math.max(dp[root][0],dp[root][1]);
}
public static void process(int[][] matrix,int[][] dp,boolean[] visited,int root){
visited[root]=true;
dp[root][1]=matrix[root][1];
for (int i=0;i<matrix.length;i++){
if (matrix[i][0]==root&&!visited[i]){
process(matrix,dp,visited,i);
dp[root][1]+=dp[i][0];
dp[root][0]+=Math.max(dp[i][1],dp[i][0]);
}
}
}
public static class Employee{
public int happy;//这名员工可以带来的快乐道
public List<Employee>nexts;
}
public static int maxHappy(Employee boss){
Info headInfo=process(boss);
return Math.max(headInfo.laiMaxHappy,headInfo.buMaxHappy);
}
public static class Info{
//x来的情况下,整棵树最大收益
public int laiMaxHappy;
//x不来的情况下,整棵树的最大收益
public int buMaxHappy;
public Info(int lai,int bu){
laiMaxHappy=lai;
buMaxHappy=bu;
}
}
public static Info process(Employee x){
//base case
if (x.nexts.isEmpty()){//x是基层员工的时候
return new Info(x.happy,0);
}
int lai=x.happy;//x来的情况下,整棵树最大收益
int bu=0;//x不来的情况下,整棵树的最大收益
for (Employee next:x.nexts){
Info nextInfo=process(next);
lai+=nextInfo.buMaxHappy;
bu+=Math.max(nextInfo.laiMaxHappy,nextInfo.buMaxHappy);
}
return new Info(lai,bu);
}
public static void main(String[] args) {
// ==========================================
// 测试1:题目中的多叉树
// ==========================================
// 10
// / | \
// 3 20 40
// | | / \
// 60 3 5 6
Employee boss = new Employee();
boss.happy = 10;
Employee a = new Employee();
a.happy = 3;
Employee b = new Employee();
b.happy = 20;
Employee c = new Employee();
c.happy = 40;
Employee d = new Employee();
d.happy = 60;
Employee e = new Employee();
e.happy = 3;
Employee f = new Employee();
f.happy = 5;
Employee g = new Employee();
g.happy = 6;
// 初始化下属列表
Employee[] employees = {boss, a, b, c, d, e, f, g};
for (Employee employee : employees) {
employee.nexts = new ArrayList<>();
}
// 建立上下级关系
boss.nexts.add(a);
boss.nexts.add(b);
boss.nexts.add(c);
a.nexts.add(d);
b.nexts.add(e);
c.nexts.add(f);
c.nexts.add(g);
// 调用原有的process()和maxHappy()
Info info = process(boss);
System.out.println("测试1:普通多叉树");
System.out.println("老板参加:" + info.laiMaxHappy);
System.out.println("老板不参加:" + info.buMaxHappy);
System.out.println("最大快乐值:" + maxHappy(boss));
// 测试2:只有一个员工
Employee boss2 = new Employee();
boss2.happy = 50;
boss2.nexts = new ArrayList<>();
System.out.println("\n测试2:只有一个员工");
System.out.println("最大快乐值:" + maxHappy(boss2));
// 测试3:老板参加更有利
Employee boss3 = new Employee();
boss3.happy = 100;
boss3.nexts = new ArrayList<>();
Employee x = new Employee();
x.happy = 20;
x.nexts = new ArrayList<>();
Employee y = new Employee();
y.happy = 30;
y.nexts = new ArrayList<>();
boss3.nexts.add(x);
boss3.nexts.add(y);
System.out.println("\n测试3:老板参加更有利");
System.out.println("最大快乐值:" + maxHappy(boss3));
}
}
运行结果:
测试1:普通多叉树
老板参加:84
老板不参加:120
最大快乐值:120
测试2:只有一个员工
最大快乐值:50
测试3:老板参加更有利
最大快乐值:100
4.Morris遍历
一种遍历二叉树的方式,并且时间复杂度O(N),额外空间复杂度O(1)。
通过利用原树中大量空闲指针的方式,达到节省空间的目的。类似于线索二叉树。
Morris遍历细节
假设来到当前节点cur,开始时cur来到头节点位置。
1)如果cur没有左孩子,cur向右移动(cur = cur.right)。
2)如果cur有左孩子,找到左子树上最右的节点mostRight:
a. 如果mostRight的右指针指向空,让其指向cur,然后cur向左移动(cur = cur.left)。
b. 如果mostRight的右指针指向cur,让其指向null,然后cur向右移动(cur = cur.right)。
3)cur为空时遍历停止。
分析:
1
/ \
/ \
2 3
/ \ / \
/ \ / \
4 5 6 7
/ \ / \ / \ / \
n n n n n n n n
| 步骤 | cur 当前指向 | cur.left |
cur.right | mostRight | 指针修改 | cur 移动路径 | 当前保留的临时指针 |
| 1 | 1(第一次) | 2 | 3 | 5 | 5.right: null → 1 | 1 → 2(左) | 5 → 1 |
| 2 | 2(第一次) | 4 | 5 | 4 | 4.right: null → 2 | 2 → 4(左) | 5 → 1,4 → 2 |
| 3 | 4 | null | 2(临时) | 无 | 不修改 | 4 → 2(右) | 5 → 1,4 → 2 |
| 4 | 2(第二次) | 4 | 5 | 4 | 4.right: 2 → null | 2 → 5(右) | 5 → 1 |
| 5 | 5 | null | 1(临时) | 无 | 不修改 | 5 → 1(右) | 5 → 1 |
| 6 | 1(第二次) | 2 | 3 | 5 | 5.right: 1 → null | 1 → 3(右) | 无 |
| 7 | 3(第一次) | 6 | 7 | 6 | 6.right: null → 3 | 3 → 6(左) | 6 → 3 |
| 8 | 6 | null | 3(临时) | 无 | 不修改 | 6 → 3(右) | 6 → 3 |
| 9 | 3(第二次) | 6 | 7 | 6 | 6.right: 3 → null | 3 → 7(右) | 无 |
| 10 | 7 | null | null | 无 | 不修改 | 7 → null(右) | 无 |
指针完整移动过程:
初始:
cur → 1
第1步:
cur = 1
mostRight = 5
5.right → 1(建立临时指针)
cur = cur.left → 2
第2步:
cur = 2
mostRight = 4
4.right → 2(建立临时指针)
cur = cur.left → 4
第3步:
cur = 4
4没有左孩子
4.right → 2(临时指针)
cur = cur.right → 2
第4步:
cur = 2(第二次)
mostRight = 4
发现4.right → 2
恢复4.right → null
cur = cur.right → 5
第5步:
cur = 5
5没有左孩子
5.right → 1(临时指针)
cur = cur.right → 1
第6步:
cur = 1(第二次)
mostRight = 5
发现5.right → 1
恢复5.right → null
cur = cur.right → 3
第7步:
cur = 3
mostRight = 6
6.right → 3(建立临时指针)
cur = cur.left → 6
第8步:
cur = 6
6没有左孩子
6.right → 3(临时指针)
cur = cur.right → 3
第9步:
cur = 3(第二次)
mostRight = 6
发现6.right → 3
恢复6.right → null
cur = cur.right → 7
第10步:
cur = 7
7没有左孩子
7.right = null
cur = cur.right → null
遍历结束。
遍历一轮后,得到:遍历序列:1,2,4,2,5,1,3,6,3,7
遍历完后,指针记录如下图:

观察 Morris 遍历可以发现:如果某个节点有左子树,那么该节点会被访问两次;如果没有左子树,那么该节点只会被访问一次。另:只要节点存在左子树,不管有没有右子树,在标准 Morris 遍历过程中都会来到该节点两次。
|
节点情况 |
Morris 到达次数 |
|---|---|
|
同时具有左、右子树 |
2 |
|
只有左子树 |
2 |
|
只有右子树 |
1 |
|
没有任何孩子 |
1 |
如何判断是第一次还是第二次到达?
对于有左子树的节点 cur,找到其左子树的最右节点 mostRight。
如果 mostRight.right == null,说明第一次到达 cur,将 mostRight.right 指向 cur,然后进入左子树。
如果 mostRight.right == cur,说明第二次到达 cur,将 mostRight.right 恢复为 null,然后进入右子树。
因此,Morris 遍历利用临时右指针记录节点的访问状态,实现不使用递归栈的二叉树遍历,时间复杂度为 O(N),额外空间复杂度为 O(1)。分析所有节点遍历左子树右边界的总代价,分析:
1
/ \
/ \
2 3
/ \ / \
/ \ / \
4 5 6 7
/ \ / \ / \ / \
8 9 10 11 12 13 14 15
1:2,5,11;
2:4,9
3:6,13
4:8
5:10
6:12
7:14
我们发现所有右边界节点都是不同的节点,如果全部算上,时间复杂度为O(n)。
此外,从morris遍历重建先序,中序和后序遍历。
1
/ \
/ \
2 3
/ \ / \
/ \ / \
4 5 6 7
morris序:1,2,4,2,5,1,3,6,3,7
改造:
先序遍历:如果一个节点只到达一次,直接打印;如果一个节点到达两次,只打印第一次
最后变成:1,2,4,5,3,6,7
中序遍历:如果一个节点只到达一次,直接打印;如果一个节点到达两次,只打印第二次
最后变成:4,2,5,1,6,3,7
后序遍历:把打印时机只放在能回到自己两次的节点,当这个前提确定时,逆序打印左树的右边界;整棵树遍历完,单独逆序打印整棵树的右边界。
1,2,4,2,5,1,3,6,3,7
x,x,x,y,x,y,x,x,y,x,y
最后变成:4,5,2,6,7,3,1
另:后序遍历的验证:
1
/ \
/ \
2 3
/ \ / \
/ \ / \
3 4 10 9
/ \
/ \
5 11
/ /
/ /
6 12
\ \
\ \
7 13
\
\
8
对于这样的一棵极其丑陋的树(ikun),
直接后序遍历的结果为:
3,8,7,6,5,4,2,13,12,11,10,9,3,1
morris遍历的结果为:
1,2,3,2,4,5,6,7,8,5,4,1,3,10,11,12,13,11
最后改造morris得到的后序遍历为:
3,8,7,6,5,4,2,13,12,11,10,9,3,1
发现两者完全相同,测试通过
另:逆序打印右边界可以使用单链表操作实现。
代码:
package Class012;
public class Code_MorrisTraversal {
public static class Node{
public int value;
Node left;
Node right;
public Node(int data){
this.value=data;
}
}
public static void process(Node head){
if (head==null){
return;
}
//这里的实质是系统压栈的方法告诉你是第几次遍历
//1,如果有打印语句,先序遍历
process(head.left);
//2.如果有打印语句,中序遍历
process(head.right);
//3.如果有打印语句,后序遍历
//另,在递归版本中,对于带节点的二叉树,遍历流程如此:
// 1
// / \
// 2 3
// / \ / \
// n n n n
//
//递归遍历经过的节点:1,2,2,2,1,3,3,3,1
//一个节点遍历三次
}
public static void morris(Node head){
if (head==null){
return;
}
Node cur=head;
Node mostRight=null;
while (cur!=null){//过流程
mostRight=cur.left;//mostRight是cur左孩子
if(mostRight!=null){//有左子树
//1.mostRight不断往右移动的过程中most的右指针不能为空,
//2.mostRight不断往右移动的过程中most的右指针不能指向当前节点
while (mostRight.right!=null&&mostRight.right!=cur){
mostRight=mostRight.right;
}
//mostRight变成了cur左子树上最右的节点
if (mostRight.right==null){//这是第一次来到cur
mostRight.right=cur;
cur=cur.left;
continue;
//continue指向的地点:while (cur!=null){//过流程
// mostRight=cur.left;//mostRight是cur左孩子
}else {//mostRight==cur,第二次来到当前节点
mostRight.right=null;
}
}
cur=cur.right;
}
}
public static void morrisPre(Node head){
if (head==null){
return;
}
Node cur=head;
Node mostRight=null;
while (cur!=null){//过流程
mostRight=cur.left;//mostRight是cur的左孩子
if (mostRight!=null){//有左子树的情形,对应能够到两次的情形
while (mostRight.right!=null&&mostRight.right!=cur){
mostRight=mostRight.right;
}
//mostRight变成了cur左子树上最右的节点
if(mostRight.right==null){//这是第一次来到cur
System.out.println(cur.value);
mostRight.right=cur;
cur=cur.left;
continue;
}else {//mostRight.right==cur
mostRight.right=null;
}
}else {//没有左子树的情况,对应只能到一次的情形
System.out.println(cur.value);
}
cur=cur.right;
}
}
public static void morrisIn(Node head){
if (head==null){
return;
}
Node cur=head;
Node mostRight=null;
while (cur!=null){//过流程
mostRight=cur.left;//mostRight是cur左孩子
if(mostRight!=null){//有左子树
while (mostRight.right!=null&&mostRight.right!=cur){
mostRight=mostRight.right;
}
//mostRight变成了cur子树上,最右的节点
if(mostRight.right==null){//这是第一次来到cur
mostRight.right=cur;
cur=cur.left;
continue;
}else {//mostRight.right==cur;
mostRight.right=null;
}
}
//能够遍历两次的节点
System.out.println(cur.value);
cur=cur.right;
}
}
public static void morrisPos(Node head){
if (head==null){
return;
}
Node cur=head;
Node mostRight=null;
while (cur!=null){
mostRight=cur.left;
if (mostRight!=null){
while (mostRight.right!=null&&mostRight.right!=cur){
mostRight=mostRight.right;
}
if (mostRight.right==null){
mostRight.right=cur;
cur=cur.left;
continue;
}else {
mostRight.right=null;
printEdge(cur.left);
}
}
cur=cur.right;
}
printEdge(head);
System.out.println();
}
//以x为头的树,逆序打印这棵树的有边界
public static void printEdge(Node X){
//先reverse右边界,打印完后再返还回去
Node tail=reverseEdge(X);
Node cur=tail;
while (cur!=null){
System.out.println(cur.value+" ");
cur=cur.right;
}
reverseEdge(tail);
}
public static Node reverseEdge(Node from){
Node pre=null;
Node next=null;
while (from!=null){
next=from.right;
from.right=pre;
pre=from;
from=next;
}
return pre;
}
//for test--print tree
public static void printTree(Node head){
System.out.println("Binary Tree:");
printInOrder(head,0,"H",17);
System.out.println();
}
public static void printInOrder(Node head,int height,String to,int len){
if (head==null){
return;
}
printInOrder(head.right,height+1,"v",len);
String val=to+head.value+to;
int lenM=val.length();
int lenL=(len-lenM)/2;
int lenR=len-lenM-lenL;
val=getSpace(lenL)+val+getSpace(lenR);
System.out.println(getSpace(height*len)+val);
printInOrder(head.left,height+1,"^",len);
}
public static String getSpace(int num){
String space=" ";
StringBuffer buf=new StringBuffer("");
for (int i=0;i<num;i++){
buf.append(space);
}
return buf.toString();
}
public static void main(String[] args){
Node head=new Node(4);
head.left=new Node(2);
head.right=new Node(6);
head.left.left=new Node(1);
head.left.right=new Node(3);
head.right.left=new Node(5);
head.right.right=new Node(7);
printTree(head);
// morris(head);
morrisIn(head);
morrisPre(head);
morrisPos(head);
printTree(head);
}
}
运行结果:
Binary Tree:
v7v
v6v
^5^
H4H
v3v
^2^
^1^
1
2
3
4
5
6
7
4
2
1
3
6
5
7
1
3
2
5
7
6
4
Binary Tree:
v7v
v6v
^5^
H4H
v3v
^2^
^1^
传统二叉树遍历与morris遍历的区别:
|
比较项目 |
传统递归遍历 |
传统非递归遍历 |
Morris 遍历 |
|---|---|---|---|
|
遍历方式 |
系统递归调用 |
手动维护栈 |
临时修改右指针 |
|
时间复杂度 |
O(N) |
O(N) |
O(N) |
|
额外空间复杂度 |
O(H) |
O(H) |
O(1) |
|
是否需要栈 |
系统调用栈 |
显式栈 |
不需要 |
|
是否临时修改原树 |
否 |
否 |
是 |
|
遍历后树结构 |
不变 |
不变 |
恢复原状 |
|
节点处理方式 |
递归调用与返回 |
出栈、入栈 |
第一次或第二次到达 |
|
实现难度 |
简单 |
中等 |
较高 |
|
先序遍历 |
支持 |
支持 |
支持 |
|
中序遍历 |
支持 |
支持 |
支持 |
|
后序遍历 |
支持 |
支持 |
支持,需要逆序打印右边界 |
|
主要优势 |
逻辑清晰、代码简洁 |
避免递归调用 |
额外空间 O(1) |
|
主要不足 |
深树可能栈溢出 |
需要额外存储节点 |
指针操作复杂,不能随意中断 |
详细对比:
|
比较项目 |
传统先序 |
Morris 先序 |
传统中序 |
Morris 中序 |
传统后序 |
Morris 后序 |
|---|---|---|---|---|---|---|
|
遍历规则 |
根→左→右 |
根→左→右 |
左→根→右 |
左→根→右 |
左→右→根 |
左→右→根 |
|
有左子树节点的打印时机 |
递归进入节点时 |
第一次到达 |
左子树处理完后 |
第二次到达 |
左右子树处理完后 |
第二次到达时打印左子树右边界 |
|
无左子树节点的处理 |
进入时打印 |
唯一一次到达时打印 |
进入时打印 |
唯一一次到达时打印 |
右子树处理完后打印 |
由祖先处理右边界时打印 |
|
是否使用递归栈 |
是 |
否 |
是 |
否 |
是 |
否 |
|
是否反转右边界 |
否 |
否 |
否 |
否 |
否 |
是 |
|
时间复杂度 |
O(N) |
O(N) |
O(N) |
O(N) |
O(N) |
O(N) |
|
额外空间复杂度 |
O(H) |
O(1) |
O(H) |
O(1) |
O(H) |
O(1) |
morris遍历的应用:
如何判断一棵树是搜索二叉树?
在中序遍历中,如果一棵树是升序的,它就是搜索二叉树
代码:
package Class012;
public class Code_MorrisBST {
public static class Node{
public int value;
Node left;
Node right;
public Node(int data){
this.value=data;
}
}
public static void process(Node head){
if (head==null){
return;
}
//这里的实质是系统压栈的方法告诉你是第几次遍历
//1,如果有打印语句,先序遍历
process(head.left);
//2.如果有打印语句,中序遍历
process(head.right);
//3.如果有打印语句,后序遍历
//另,在递归版本中,对于带节点的二叉树,遍历流程如此:
// 1
// / \
// 2 3
// / \ / \
// n n n n
//
//递归遍历经过的节点:1,2,2,2,1,3,3,3,1
//一个节点遍历三次
}
//以x为头的树,逆序打印这棵树的有边界
public static void printEdge(Node X){
//先reverse右边界,打印完后再返还回去
Node tail=reverseEdge(X);
Node cur=tail;
while (cur!=null){
System.out.println(cur.value+" ");
cur=cur.right;
}
reverseEdge(tail);
}
public static Node reverseEdge(Node from){
Node pre=null;
Node next=null;
while (from!=null){
next=from.right;
from.right=pre;
pre=from;
from=next;
}
return pre;
}
//for test--print tree
public static void printTree(Node head){
System.out.println("Binary Tree:");
printInOrder(head,0,"H",17);
System.out.println();
}
public static void printInOrder(Node head,int height,String to,int len){
if (head==null){
return;
}
printInOrder(head.right,height+1,"v",len);
String val=to+head.value+to;
int lenM=val.length();
int lenL=(len-lenM)/2;
int lenR=len-lenM-lenL;
val=getSpace(lenL)+val+getSpace(lenR);
System.out.println(getSpace(height*len)+val);
printInOrder(head.left,height+1,"^",len);
}
public static String getSpace(int num){
String space=" ";
StringBuffer buf=new StringBuffer("");
for (int i=0;i<num;i++){
buf.append(space);
}
return buf.toString();
}
public static boolean isBST(Node head){
if (head==null){
return true;
}
Node cur=head;
Node mostRight=null;
//前一个中序遍历节点
Node pre=null;
//判断结果
boolean isBST=true;
while (cur!=null){//过流程
mostRight=cur.left;//mostRight是cur左孩子
if(mostRight!=null){//有左子树
//1.mostRight不断往右移动的过程中most的右指针不能为空,
//2.mostRight不断往右移动的过程中most的右指针不能指向当前节点
while (mostRight.right!=null&&mostRight.right!=cur){
mostRight=mostRight.right;
}
//mostRight变成了cur左子树上最右的节点
if (mostRight.right==null){//这是第一次来到cur
mostRight.right=cur;
cur=cur.left;
continue;
//continue指向的地点:while (cur!=null){//过流程
// mostRight=cur.left;//mostRight是cur左孩子
}else {//mostRight==cur,第二次来到当前节点
mostRight.right=null;
}
}
if (pre!=null&&cur.value<=pre.value){
isBST=false;
}
//更新前一个节点
pre=cur;
//进入右子树
cur=cur.right;
}
return isBST;
}
public static void main(String[] args){
// 测试1:正常的搜索二叉树
Node head = new Node(4);
head.left = new Node(2);
head.right = new Node(6);
head.left.left = new Node(1);
head.left.right = new Node(3);
head.right.left = new Node(5);
head.right.right = new Node(7);
System.out.println("测试1:正常搜索二叉树");
printTree(head);
System.out.println("是否为搜索二叉树:" + isBST(head));
// 测试2:不符合搜索二叉树规则
// 将节点3改成8
head.left.right.value = 8;
System.out.println("\n测试2:非搜索二叉树");
printTree(head);
System.out.println("是否为搜索二叉树:" + isBST(head));
// 测试3:Integer.MIN_VALUE边界情况
Node head3 = new Node(Integer.MIN_VALUE);
System.out.println("\n测试3:只有一个最小整数节点");
printTree(head3);
System.out.println("是否为搜索二叉树:" + isBST(head3));
}
}
运行结果:
测试1:正常搜索二叉树
Binary Tree:
v7v
v6v
^5^
H4H
v3v
^2^
^1^
是否为搜索二叉树:true
测试2:非搜索二叉树
Binary Tree:
v7v
v6v
^5^
H4H
v8v
^2^
^1^
是否为搜索二叉树:false
测试3:只有一个最小整数节点
Binary Tree:
H-2147483648H
是否为搜索二叉树:true
总结:
如果方法要求遍历完左子树和右子树后,再回到原来的节点做第三次强整合,最后才能得出答案,那么用搜索二叉树的套路解法是最优解。如果不用做第三次强整合,那么morris遍历是最优解
1万+



被折叠的 条评论
为什么被折叠?



