剑指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= ...
随机推荐
- c实现队列
使用链表实现队列的入队和出队 #include <iostream> #include <stdio.h> #include <string.h> #include ...
- c++ 数据类型长度
#include <iostream> using namespace std; int main() { cout << "char: " << ...
- Kafaka详细介绍机制原理
1. kafka介绍 1.1. 主要功能 根据官网的介绍,ApacheKafka®是一个分布式流媒体平台,它主要有3种功能: 1:It lets you publish and ...
- JDK8 新特性 Lambda表达式
1.java8中Lambda表达式基础语法: (x,y) -> {} 左侧是一个小括号,里面是要实现的抽象方法的参数,有几个参数就写几个参数名,无参可写空括号,无需声明参数类型: 中间是一个jd ...
- 手游折扣app票选结果公布哪个好哪个靠谱一目了然
2018年,是中国改革开放40年,也是中国互联网20年.“互联网推动了精神文明向更高水平的迈进,实现人的价值第一,创造美好生活,从生产高于生活.艺术高于成活,转向发现与实现生活本身美好,让想象成真.如 ...
- Oracle JDBC 连接池
1.简介 数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据 ...
- IOS项目集成ShareSDK实现第三方登录、分享、关注等功能
(1)官方下载ShareSDK iOS 2.8.8,地址:http://sharesdk.cn/ (2)根据实际情况,引入相关的库,参考官方文档. (3)在项目的AppDelegate中一般情况下有三 ...
- 文件上传使用FileUpload组件进行代码实现
使用FileUpload组件进行代码实现 实现步骤 1. 获取解析器工厂: DiskFileItemFactory 2. 获取解析器对象: ServletFileUpload 3. 解析request ...
- centos出现磁盘坏道,怎么检索和修复
故障现象,在/var/log/message这个目录中出现下面的error: [ [ [ [ [ [ [ [ [ [ dmesg的输出结果也是上面的error. 1.检测下坏道,将结果保存在bb.lo ...
- 011-通过网络协议解析网络请求-DNS-ARP-TCPIP
一.概述 1.1.tcp/ip概述 TCP/IP不是一个协议,而是一个协议族的统称.里面包括IP协议.IMCP协议.TCP协议.跨越了多层模型的多层 TCP/IP协议族按照层次由上到下,层层包装.最上 ...