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:平衡二叉树的更多相关文章

  1. 剑指offer39 平衡二叉树

    剑指上用了指针传递,这里用的引用传递 class Solution { public: bool IsBalanced_Solution(TreeNode* pRoot) { ; return IsB ...

  2. 剑指offer-39:平衡二叉树

    题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 解题思路 在做这题是,我第一反应就是遍历两次二叉树.第一遍记录每个节点的深度,并将信息存入HashMap中,key = node,value ...

  3. 剑指Offer——平衡二叉树

    题目描述: 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 分析: 平衡二叉树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质 ...

  4. 剑指Offer-38.平衡二叉树(C++/Java)

    题目: 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 分析: 可以从根节点开始遍历每一个节点,求得节点左右子树的最大高度,判断是不是平衡二叉树.这样做的问题在于会重复遍历节点,造成不必要的浪费. 所 ...

  5. 用java刷剑指offer(平衡二叉树)

    题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 牛客网链接 java代码 import java.lang.Math; public class Solution { public bool ...

  6. 剑指Offer39 数组中寻找和为sum的两个数字

    /************************************************************************* > File Name: 39_TwoNum ...

  7. 剑指offer--39. 跳台阶

    时间限制:1秒 空间限制:32768K 热度指数:375795 题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). cla ...

  8. 剑指Offer-39.把数组排成最小的数(C++/Java)

    题目: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 分析: 将数组 ...

  9. C++版 - 剑指offer 面试题39:判断平衡二叉树(LeetCode 110. Balanced Binary Tree) 题解

    剑指offer 面试题39:判断平衡二叉树 提交网址:  http://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId= ...

随机推荐

  1. HDU 1069 Monkey and Banana ——(DP)

    简单DP. 题意:给出若干种长方体,如果摆放时一个长方体的长和宽小于另一个的长宽,那么它可以放在另一个的上面,问最高能放多少高度.每种长方体的个数都是无限的. 做法:因为每种个数都是无限,那么每种按照 ...

  2. sql语句 基本

    1.sql不区分大小写,一般结尾要加分号: 2.select 列,列,列 from 表 3.distinct ,返回列中不同的值.需要哪个列不同,关键词哪个列 4.where子句,select 列 f ...

  3. Leetcode题目292.Nim游戏(脑筋急转弯)

    题目描述: 你和你的朋友,两个人一起玩 Nim 游戏:桌子上有一堆石头,每次你们轮流拿掉 1 - 3 块石头. 拿掉最后一块石头的人就是获胜者.你作为先手. 你们是聪明人,每一步都是最优解. 编写一个 ...

  4. Android自定义控件之基本图形绘制

    入门示例代码 在Android中Paint类就是画笔,Canvas 就是画布 对于画笔的大小,粗细,颜色,透明度都在paint类中设置,对于画出的成品,比如圆,方形,等在canvas类中的函数生成 入 ...

  5. Qt编写安防视频监控系统9-自动隐藏光标

    一.前言 这个效果的灵感来自于大屏电子看板系统,在很多系统中尤其是上了大屏的时候,其实在用户不在操作的时候,是很不希望看到那个鼠标箭头指针的,只有当用户操作的时候才显示出来,这个就需要开个定时器定时计 ...

  6. thymeleaf中img标签图片src路径问题

    转载自:解决java - Thymeleaf conditional img src 正确写法. <img class="layui-nav-img" th:src=&quo ...

  7. javascript两个数组内容合并

    需求: ,,]; ,,]; 最终结果: [,,,,,] 代码: Array.prototype.addAll= function(arr) { this.push.apply(this, arr); ...

  8. pip安装软件报错 utf-8 code can't decode byte 0xcf in position7

    pip安装软件报错 utf-8 code can't decode byte 0xcf in position7 根据错误提示的路径找到__init__.py文件 根据错误提示的最后几句话找到对应的行 ...

  9. webdriervAPI基础元素定位

    from  selenium  import  webdriver driver  =  webdriver.Chorme() driver.get("http://www.baidu.co ...

  10. Leetcode之分治法专题-654. 最大二叉树(Maximum Binary Tree)

    Leetcode之分治法专题-654. 最大二叉树(Maximum Binary Tree) 给定一个不含重复元素的整数数组.一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素. 左 ...