剑指offer39:平衡二叉树
1 题目描述
2 思路和方法
平衡二叉树,又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。https://blog.csdn.net/qq_43091156/article/details/88558966
从叶节点开始,依次往上求其子树高度,如果在某一子树上不满足要求,则一路返回,不再继续遍历。即,先依次遍历左子树,如果左子树是平衡二叉树,再依次遍历右子树。时间最坏O(n),空间O(n)。
3 C++核心代码
class Solution {
public:
// 返回值:树的深度
bool IsBalanced_Solution(TreeNode* pRoot){
if (pRoot == nullptr)
return true; // ko
return TreeDepth(pRoot)!=-;
}
// 返回值:
// -1:子树不平衡
// >0:子树深度
int TreeDepth(TreeNode* pRoot){
if (pRoot == nullptr)
return ;
int left = TreeDepth(pRoot->left);
if(left==-) //若左子树不满足平衡,则整个树已不是平衡二叉树了,直接返回,不处理右子树
return -;
int right = TreeDepth(pRoot->right);
if(right ==-)
return -;
if(left-right > || left - right <-)
return -;
return left>right ? left+:right+;
}
};
4 AVL平衡二叉树的代码
#include <iostream>
#include <algorithm> using namespace std; class AVLNode{
public:
int data;
int height;//结点的高度,叶子结点高度为1
AVLNode* lChild;
AVLNode* rChild;
public:
AVLNode(int data) :data(data), height(), lChild(), rChild(){}
}; class AVL{
public:
AVLNode* root;
public:
AVL(){
root = nullptr;
}
~AVL(){
delete root;
}
int height(AVLNode* root){
if (root){
return root->height;
}
return ;
}
//找到树中最大结点并将其返回
AVLNode* finMaxNode(AVLNode* root){
//一直往右找
if (root->rChild){
root = root->rChild;
}
return root;
}
//找到树中最小结点并将其返回
AVLNode* finMinNode(AVLNode* root){
//一直往左找
if (root->lChild){
root = root->lChild;
}
return root;
}
//以p为根结点右旋转,返回新的根结点
AVLNode* llRotate(AVLNode* p){
AVLNode* pleft = p->lChild;
p->lChild = pleft->rChild;
pleft->rChild = p;
//结点的高度由该节点的子树唯一决定,所以只有子树发生变化的结点才需要更新高度值
pleft->height = max(height(pleft->lChild), height(pleft->rChild)) + ;
p->height = max(height(p->lChild), height(p->rChild)) + ;
return pleft;
}
//左旋转
AVLNode* rrRotate(AVLNode* p){
AVLNode* pright = p->rChild;
p->rChild = pright->lChild;
pright->lChild = p;
pright->height = max(height(pright->lChild), height(pright->rChild)) + ;
p->height = max(height(p->lChild), height(p->rChild)) + ;
return pright;
}
//先左,再右
AVLNode* lrRotate(AVLNode* p){
AVLNode* pleft = rrRotate(p->lChild);
return llRotate(p);
}
//先右,再左
AVLNode* rlRotate(AVLNode* p){
AVLNode* pright = llRotate(p->rChild);
return rrRotate(p);
}
//插入新结点,保持平衡
void insert(int data, AVLNode*& root){
if (!root){
root = new AVLNode(data);
}
else{
if (data < root->data){
insert(data, root->lChild);
//插入新结点后,如果打破平衡,则需要动态调整
if (height(root->lChild) - height(root->rChild) == ){
if (data < root->lChild->data)
root = llRotate(root);
else
root = lrRotate(root);
}
}
else if (data > root->data){
insert(data, root->rChild);
//插入新结点后,如果打破平衡,则需要动态调整
if (height(root->rChild) - height(root->lChild) == ){
if (data > root->rChild->data)
root = rrRotate(root);
else
root = rlRotate(root);
}
}
else{
cout << "AVL中已存在该值:" << data << endl;
}
}
//平衡后,需要更新根结点的高度值
root->height = max(height(root->lChild), height(root->rChild)) + ;
}
//删除结点,保持平衡
void del(int data, AVLNode*& root){
if (data < root->data){
del(data, root->lChild);
//删除点之后,若AVL树失去平衡,则进行调整
if (height(root->rChild) - height(root->lChild) == ){
AVLNode* r = root->rChild;
if (height(r->lChild) > height(r->rChild))
root = rlRotate(root);
else
root = rrRotate(root);
}
}
else if (data > root->data){
del(data, root->rChild);
//删除点之后,若AVL树失去平衡,则进行调整
if (height(root->lChild) - height(root->rChild) == ){
AVLNode* l = root->lChild;
if (height(l->lChild) > height(l->rChild))
root = llRotate(root);
else
root = lrRotate(root);
}
}
else{
//此时root为要删除的点
if (root->lChild && root->rChild){
if (height(root->lChild) > height(root->rChild)){
// 如果root的左子树比右子树高;
// 则(01)找出root的左子树中的最大节点
// (02)将该最大节点的值赋值给root。
// (03)删除该最大节点。
// 这类似于用"root的左子树中最大节点"做"root"的替身;
// 采用这种方式的好处是:删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。
AVLNode* maxNode = finMaxNode(root->lChild);
root->data = maxNode->data;
del(maxNode->data, root->lChild);
}
else{
AVLNode* minNode = finMinNode(root->rChild);
root->data = minNode->data;
del(minNode->data, root->rChild);
}
}
else{
if (root->lChild){
root->data = root->lChild->data;
root->lChild = nullptr;
}
else if (root->rChild){
root->data = root->rChild->data;
root->rChild = nullptr;
}
else{
root = nullptr;//参数是引用,所以此处修改了主函数中的root值
}
}
}
}
void inOrder(AVLNode* root){
if (root){
inOrder(root->lChild);
cout << root->data << endl;
inOrder(root->rChild);
}
}
}; int main(){
AVL tree;
tree.insert(, tree.root);
tree.insert(, tree.root);
tree.insert(, tree.root);
tree.insert(, tree.root);
tree.insert(, tree.root);
tree.insert(, tree.root);
tree.del(, tree.root);
tree.inOrder(tree.root); system("pause");
return ;
}
参考资料
https://blog.csdn.net/qq_39559641/article/details/83720734(代码很详细全面,写的很好,知识点讲解详细)
https://blog.csdn.net/zjwreal/article/details/88833908
https://blog.csdn.net/qq_43091156/article/details/88558966
https://blog.csdn.net/vaemusicsky/article/details/81607251(AVL平衡二叉树的代码)
剑指offer39:平衡二叉树的更多相关文章
- 剑指offer39 平衡二叉树
剑指上用了指针传递,这里用的引用传递 class Solution { public: bool IsBalanced_Solution(TreeNode* pRoot) { ; return IsB ...
- 剑指offer-39:平衡二叉树
题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 解题思路 在做这题是,我第一反应就是遍历两次二叉树.第一遍记录每个节点的深度,并将信息存入HashMap中,key = node,value ...
- 剑指Offer——平衡二叉树
题目描述: 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 分析: 平衡二叉树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质 ...
- 剑指Offer-38.平衡二叉树(C++/Java)
题目: 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 分析: 可以从根节点开始遍历每一个节点,求得节点左右子树的最大高度,判断是不是平衡二叉树.这样做的问题在于会重复遍历节点,造成不必要的浪费. 所 ...
- 用java刷剑指offer(平衡二叉树)
题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 牛客网链接 java代码 import java.lang.Math; public class Solution { public bool ...
- 剑指Offer39 数组中寻找和为sum的两个数字
/************************************************************************* > File Name: 39_TwoNum ...
- 剑指offer--39. 跳台阶
时间限制:1秒 空间限制:32768K 热度指数:375795 题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). cla ...
- 剑指Offer-39.把数组排成最小的数(C++/Java)
题目: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 分析: 将数组 ...
- C++版 - 剑指offer 面试题39:判断平衡二叉树(LeetCode 110. Balanced Binary Tree) 题解
剑指offer 面试题39:判断平衡二叉树 提交网址: http://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId= ...
随机推荐
- 1626:【例 2】Hankson 的趣味题
1626:[例 2]Hankson 的趣味题题解 [题目描述] Hanks 博士是 BT(Bio-Tech,生物技术)领域的知名专家,他的儿子名叫 Hankson.现在,刚刚放学回家的 Hankson ...
- Selenium高亮显示定位到的元素
在调试Selenium脚本中,有时因为操作太快或操作不明显而不清楚是否定位到了正确的元素.我们可用通过执行js为定位到的元素添加样式,来高亮显示定位到的元素. 在Selenim Webdriver中, ...
- wqy的B题
wqy的B题 题意: 和一道叫机器翻译的题差不多,不过这道题要难一些,没有规定必须删除最早入队的. 解法: 解法和[POI2005]SAM-Toy Cars这道题差不多,考虑贪心. 每次选取下一次使用 ...
- JDK1.6历史版本的下载(關於TLSv1.2)Oracle的官方文檔
[资源描述]:对于部分老项目 仍然采用的是JDK1.6 版本 但是打开官方 JDK 都是最新的 版本 想找 历史版本 不容易找到 [资源详情]:提供下载链接: http://www.oracle.co ...
- fsLayuiPlugin附件上传使用说明
fsLayuiPlugin 是一个基于layui的快速开发插件,支持数据表格增删改查操作,提供通用的组件,通过配置html实现数据请求,减少前端js重复开发的工作. GitHub下载 码云下载 测试环 ...
- 冲刺阶段——Day6
[今日进展] 完成登录代码 userRegister类 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.ev ...
- oracle 常用工具类及函数
j_param json; jl_keys json_list; -- 创建json对象j_param j_param := json(p_in_str); -- 校验param域是否缺少必填参数 j ...
- Mysql触发器详解以及union的使用
---恢复内容开始--- Mysql触发器定义: 当一个表中有insert update delete事件发生,触发一个事件,执行一段代码.作用: 同步数据创建: create trigger 名称 ...
- 图像质量评价-NQM和WPSNR
王保全. 基于混合专家模型的快速图像超分辨率方法研究与实现[D]. 2015. PSNR 和SSIM 在有时候并不能很确切的表示图像质量 标准,该论文中根据一定量的人为的感知评分作为参考,用斯皮尔曼等 ...
- vue2.0+vue-dplayer实现hls播放
vue2.0+vue-dplayer实现hls播放 开始 安装依赖 npm install vue-dplayer -S 1,编写组件HelloWorld.vue <template> & ...