二叉树之平衡二叉搜索树
平衡树
平衡树的定义
平衡二叉搜索树(英语:Balanced Binary Tree)是一种结构平衡的二叉搜索树,即叶节点高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
- 先画出一棵树备用 ,后面都用这棵树进行分析。
- 先给出结论,这不是一颗平衡树
- 根据定义,每一个叶节点的高度差的绝对值不超过1,左右子树均满足这个条件
- j 高度 1,j 左节点 高度0,右节点 高度0,左右高度相差0,j 节点是平衡的
- h 高度2,h 左节点 j 高度1,右节点 高度0,左右高度相差1,h 节点是平衡的
- g 高度1,g 左节点 高度0,右节点 高度0,左右高度相差0,g 节点是平衡的
- e 高度3,e 左节点 g 高度1,右节点 h 高度2,左右高度相差1,e 节点是平衡的
- b 高度4,b 左节点 e 高度3,右节点 高度0,左右高度相差3,b 节点不是平衡的
- 啊,已经有节点不平衡了,那这棵树也不平衡了
怎么判断是平衡树呢?
通过上面的分析,我们可以先做出一个节点是否是平衡树的判断,并且记录一下这个节点的高度信息,之后一层一层判断,一直到整棵树判断结束为止。
可是我不知道最深的节点是谁啊,我怎么才能知道从 j 开始呢?
这个时候其实就用到我们的递归逻辑了,递归基本流程就是先进去再出来,那照这个逻辑的话,我们只需要在递归的出来部分 写上判断逻辑和记录高度信息然后返回就可以了嘛!
- 假设我们有这么一个类Info,只有两个属性,isBalanced、height;分别表示是否平衡、高度,这个类就用于返回的信息
- 假设我们有这么一个方法recursive,参数就是头节点head,方法里面写逻辑,这个实现递归调用
- recursive 只要head不为空,继续
- recursive 递归调用recursive,参数为head的左 返回一个左节点的Info对象 leftInfo
- recursive 递归调用recursive,参数为head的右 返回一个右节点的Info对象 rightInfo
- 吼吼,这就进去了,接下来就是判断和高度咯
- recursive isBalanced就是leftInfo是平衡的,且rightInfo是平衡的,且leftInfo和rightInfo的高度差的绝对值小于等于1
- recursive height就是 (leftInfo的高度,rightInfo的高度)的最大值 再加上自己 ==》max(l,r) + 1
- 返回新Info对象
好了,逻辑理出来了,下面写代码
public static class Info {
public boolean isBalanced;
public int height;
public Info(boolean i, int h) {
isBalanced = i;
height = h;
}
}
public static Info recursive(TreeNode head) {
if (head == null) {
return new Info(true, 0);
}
Info leftInfo = recursive(head.left);
Info rightInfo = recursive(head.right);
boolean isBalanced = leftInfo.isBalanced && rightInfo.isBalanced
&& Math.abs(leftInfo.height - rightInfo.height) <= 1;
int height = Math.max(leftInfo.height, rightInfo.height) + 1;
return new Info(isBalanced, height);
}
力扣原题:110. 平衡二叉树
/(ㄒoㄒ)/~~
看样子还是太low了
搜索树
搜索树的定义
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。二叉搜索树作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势;所以应用十分广泛,例如在文件系统和数据库系统一般会采用这种数据结构进行高效率的排序与检索操作。
- 老规矩先画出一棵树备用 ,后面都用这棵树进行分析。
- 先给结论,这是一颗二叉搜索树
- 2 节点,左右节点为空,不管
- 1 节点,左节点为空,不管,右节点是 2 大于1,满足规则
- 3 节点,左节点,1,2都小于3,右节点 4 大于3 ,满足规则
- 5 节点,左节点 1,2,3,4都小于5,右节点 5,7,8,9大于5,满足规则
- 6、7、8、9同理,都满足规则
怎么判断是搜索树呢?
中序验证
上面的例子有没有看出什么规律?
不知道大家是否还记得中序遍历的规则:先左再头再右
有不记得或不清晰的小伙伴可以看我的另一篇【好记性不如烂笔头】二叉树的遍历方式
总结: 这其实这不就是中序遍历的结果是递增的吗,1,2,3,4,5,6,7,8,9
这个逻辑就比较清晰了,我完全可以先中序打印,然后判断是否是有序递增不就完了
代码如下:
public static void main(String[] args) {
TreeNode head = new TreeNode(5);
head.left = new TreeNode(3);
head.left.left = new TreeNode(1);
head.left.left.right = new TreeNode(2);
head.left.right = new TreeNode(4);
head.right = new TreeNode(6);
head.right.right = new TreeNode(8);
head.right.right.left = new TreeNode(7);
head.right.right.right = new TreeNode(9);
List<Integer> list = new ArrayList<>();
recursive3(head, list);
if (isIncreasing(list)) {
System.out.print("是二叉搜索树!");
} else {
System.out.print("不是二叉搜索树!");
}
}
public static void recursive3(TreeNode head, List<Integer> list) {
if (head == null) {
return;
}
recursive3(head.left, list);
System.out.print(head.val + " ");
list.add(head.val);
recursive3(head.right, list);
}
public static boolean isIncreasing(List<Integer> list) {
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i) >= list.get(i + 1)) {
return false;
}
}
return true;
}
力扣原题:98. 验证二叉搜索树
这个性能也太低了吧,有没有好一点的方法啊?
进阶验证
好家伙,上一个也太拉了,既然递归可以得到信息,就没必要拿出来再判断了,直接在递归里判断不就完事了吗?
理一下规则:
- 左小于头,头小于右呗
- 对于左边来说,头就是最大值max
- 对于右边来说,头就是最小值min
- 规则不就出来了
- 左边的max < 头 且 右边的min > 头
大致思路:
- 假设我有个类Info,记录max、min、是否是搜索树isB,记录信息用
- 假设我有个方法recursive4,参数就是TreeNode,返回Info
- recursive4 如果节点是空的,返回空呗
- recursive4 递归调用recursive4,参数head.left,返回leftInfo
- recursive4 递归调用recursive4,参数head.right,返回rightInfo
- 默认max = min = head.val
- 如果leftInfo不为空,max = max(leftInfo.max,max ); min = min(leftInfo.min,min );
- 如果leftInfo不为空,max = max(leftInfo.max,max ); min = min(leftInfo.min,min );
- 吼吼,这样我就得到了 这个节点的最大值max 和最小值min
- 默认isB = true
- 如果leftInfo或rightInfo 不是搜索树isB=false,isB =false,没啥说的,直接return new Info吧
- 走到这里
- 判断左边的max是不是真的小于当前值 leftB
- 判断右边的min是不是真的大于当前值 right B
- 两个判断有一个为false,isB就是false
- return new info
好了,开始写代码
public static class Info {
public Boolean isB;
public int max;
public int min;
public Info(boolean isB, int max,int min) {
this.isB = isB;
this.max = max;
this.min = min;
}
}
public static Info recursive4(TreeNode head) {
if (head == null) {
return null;
}
Info leftInfo = recursive4(head.left);
Info rightInfo = recursive4(head.right);
int max = head.val, min = head.val;
if (leftInfo != null) {
max = Math.max(leftInfo.max, max);
min = Math.min(leftInfo.min, min);
}
if (rightInfo != null) {
max = Math.max(rightInfo.max, max);
min = Math.min(rightInfo.min, min);
}
boolean isB = true;
if (leftInfo != null && !leftInfo.isB) {
return new Info(false, max, min);
}
if (rightInfo != null && !rightInfo.isB) {
return new Info(false, max, min);
}
boolean leftB = leftInfo == null ? true : leftInfo.max < head.val;
boolean rightB = rightInfo == null ? true : rightInfo.min > head.val;
if (!leftB || !rightB) {
isB = false;
}
return new Info(isB, max, min);
}
搞定,嘿嘿
平衡二叉搜索树
那就是 是平衡树又是二叉搜索树呗,上面的判断逻辑都为true呗,这个代码我就不贴了。
总结
觉得有用的话给我点个赞吧!