c/c++补完计划(五): 平衡二叉树和二叉搜索树
前言
来看维基的说明: AVL树:是最早被发明的自平衡二叉查找树。在AVL树中,任一节点对应的两棵子树的最大高度差为1,因此它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下的时间复杂度都是
。增加和删除元素的操作则可能需要借由一次或多次树旋转,以实现树的重新平衡。 从查找树的角度来看, 还是非常实用的结构, 面试也很喜欢考, 我回想了一下, 在3家以上公司遇到了, 当然有一次是因为我不会红黑树, 被降级要求写AVL树, 是我不配(手动无奈).
平衡二叉树判断
自顶向下
思路是, 左右子树都要是平衡二叉树, 且左右子树的高度差小于2. 核心代码也很简单, 基本就是把思路用代码写出来.
bool isBalanced(TreeNode *root) {
if (root == nullptr) {
return true;
}
return isBalanced(root->left) && isBalanced(root->right) &&
(abs(height(root->left) - height(root->right)) < 2);
}
然后就是高度的获取, 当前节点的高度, 就是, 左右子树的高度大的那个+1. 这里你可以用系统的max函数, 也可以自己写一个lambda, 建议自己写一个.
int height(TreeNode *node) {
if (node == nullptr) {
return -1;
}
// return max(height(node->left), height(node->right)) + 1;
auto max = [](int left, int right) { return left < right ? right : left; };
return max(height(node->left), height(node->right)) + 1;
}
放到力库跑一下, 看到效果还行.
image
自底向上
但是很明显有很多重复计算, 而且思路是自顶向下的. 那么考虑一个自底向上的. 也不用维护数据结构那么复杂, 考虑传入一个height引用.
bool isBalancedCore(TreeNode *root, int &h) {
if (root == nullptr) {
h = -1;
return true;
}
int l, r;
if (isBalancedCore(root->left, l) && isBalancedCore(root->right, r)
&& abs(l - r) < 2) {
auto max = [=] { return l > r ? l : r; };
h = max() + 1;
return true;
}
return false;
}
bool isBalanced(TreeNode *root) {
int height;
return isBalancedCore(root, height);
}
思路是其实是后序遍历, 先判断左, 后判断右, 最后是当前节点, 也就是中. 当某次不满足时, 会直接返回false, 然后一路返回到顶, 所以复杂度肯定要优于之前的.
image
你可能会觉得有点别扭, 因为这里的true和false似乎可以用height搞定, 那为啥不简化一下.
int isBalancedHelper(TreeNode *root) {
if (root == nullptr) {
return 0;
}
int left = isBalancedHelper(root->left);
if (left == -1) return -1;
int right = isBalancedHelper(root->right);
if (right == -1) return -1;
auto max = [](int l, int r) { return l > r ? l : r; };
return abs(right - left) < 2 ? max(left, right) + 1 : -1;
}
bool isBalanced(TreeNode *root) {
return isBalancedHelper(root) != -1;
}
可以看到, 等于是把之前的与判断拆分了, 当返回-1, 就意味着当前子树不是平衡树, 然后一路返回.
image
二叉搜索树的最近公共祖先
这个题思路很重要, 不是难题, 一个暴力做法, 我直接保存两个查找的路径, 然后比对, 但是问题是什么?
- 要维护一个数组记录路径
- 没有利用起二叉搜索树的特性, 人家帮你弄好了左小右大的树, 你当一般树, 不是很搞笑吗?
那思路其实很简单, 当两个节点都小于当前节点, 说明还未分叉, 继续找; 如果一个大于当前节点, 一个小于当前节点, 就是终止条件了. 当然, 可以先排序两个节点, 这样判断就少了, 不用每次判断2个.
TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) {
if (p->val > q->val) {
auto tmp = p;
p = q;
q = tmp;
}
while (root) {
if (root->val < p->val) {
root = root->right;
} else if (root->val > q->val) {
root = root->left;
} else {
break;
}
}
return root;
}
最后
这里没有说到AVL左旋和右旋的问题, 但是实际上不是很难, 还是要自己动动手, 才能记得住.
- python常用知识梳理
- 如何打击“假货、高仿”类小程序
- centos 6x系统下源码安装mysql操作记录
- 【3】利用Word模板生成文档的总结
- 【2】快速代码集的由来及概览
- silverlight数据绑定模式TwoWay,OneWay,OneTime的研究
- Silverlight数据绑定/IValueConverter学习笔记
- silverlight:DeepZoom版的图片局部放大效果
- Linq之ToDictionary<TSource, TKey, TElement>的写法
- vs.net的调试小技巧之#define debug(适合新手)
- byte[]数组下标的最大值
- silverlight图片局部放大效果
- 局域网与互联网环境下MTU的快速确定方法
- 【4】通过简化的正则表达式处理字符串
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android自定义View的使用及其原理知识点总结
- Android中Window的管理深入讲解
- Android UI绘制流程及原理详解
- flutter 轮播图动态加载网络图片的方法
- Kotlin如何捕获上下文中的变量与常量详解
- Android使用webView长按保存下载网络图片
- Android实现万能自定义阴影控件实例代码
- 浅析android studio3.5中使用recycleview的包
- Android自定义View实现拼图小游戏
- 解决android设备断电重启后WIFI不能自动重连的BUG(收藏)
- Android gradle配置抽取合并的操作步骤
- Android BottomNavigationBar底部导航的使用方法
- Android超清晰6.0权限申请AndPermission
- Android仿微信录制语音功能
- Android仿微信语音对讲录音功能