zoukankan      html  css  js  c++  java
  • 剑指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++核心代码

     1 class Solution {
     2 public:
     3     // 返回值:树的深度
     4     bool IsBalanced_Solution(TreeNode* pRoot){
     5         if (pRoot == nullptr)
     6             return true;    // ko
     7         return TreeDepth(pRoot)!=-1;
     8     }
     9 
    10     // 返回值:
    11     // -1:子树不平衡
    12     // >0:子树深度
    13     int TreeDepth(TreeNode* pRoot){
    14         if (pRoot == nullptr)
    15             return 0;
    16 
    17         int left = TreeDepth(pRoot->left);
    18         if(left==-1)    //若左子树不满足平衡,则整个树已不是平衡二叉树了,直接返回,不处理右子树
    19             return -1;
    20         int right = TreeDepth(pRoot->right);
    21         if(right ==-1)
    22             return -1;
    23         if(left-right > 1 || left - right <-1)
    24             return -1;
    25         return left>right ? left+1:right+1;
    26     }
    27 };
    View Code

    4 AVL平衡二叉树的代码

      1 #include <iostream>
      2 #include <algorithm>
      3 
      4 using namespace std;
      5 
      6 class AVLNode{
      7 public:
      8     int data;
      9     int height;//结点的高度,叶子结点高度为1 
     10     AVLNode* lChild;
     11     AVLNode* rChild;
     12 public:
     13     AVLNode(int data) :data(data), height(1), lChild(0), rChild(0){}
     14 };
     15 
     16 class AVL{
     17 public:
     18     AVLNode* root;
     19 public:
     20     AVL(){
     21         root = nullptr;
     22     }
     23     ~AVL(){
     24         delete root;
     25     }
     26     int height(AVLNode* root){
     27         if (root){
     28             return root->height;
     29         }
     30         return 0;
     31     }
     32     //找到树中最大结点并将其返回 
     33     AVLNode* finMaxNode(AVLNode* root){
     34         //一直往右找 
     35         if (root->rChild){
     36             root = root->rChild;
     37         }
     38         return root;
     39     }
     40     //找到树中最小结点并将其返回 
     41     AVLNode* finMinNode(AVLNode* root){
     42         //一直往左找 
     43         if (root->lChild){
     44             root = root->lChild;
     45         }
     46         return root;
     47     }
     48     //以p为根结点右旋转,返回新的根结点 
     49     AVLNode* llRotate(AVLNode* p){
     50         AVLNode* pleft = p->lChild;
     51         p->lChild = pleft->rChild;
     52         pleft->rChild = p;
     53         //结点的高度由该节点的子树唯一决定,所以只有子树发生变化的结点才需要更新高度值 
     54         pleft->height = max(height(pleft->lChild), height(pleft->rChild)) + 1;
     55         p->height = max(height(p->lChild), height(p->rChild)) + 1;
     56         return pleft;
     57     }
     58     //左旋转 
     59     AVLNode* rrRotate(AVLNode* p){
     60         AVLNode* pright = p->rChild;
     61         p->rChild = pright->lChild;
     62         pright->lChild = p;
     63         pright->height = max(height(pright->lChild), height(pright->rChild)) + 1;
     64         p->height = max(height(p->lChild), height(p->rChild)) + 1;
     65         return pright;
     66     }
     67     //先左,再右 
     68     AVLNode* lrRotate(AVLNode* p){
     69         AVLNode* pleft = rrRotate(p->lChild);
     70         return llRotate(p);
     71     }
     72     //先右,再左 
     73     AVLNode* rlRotate(AVLNode* p){
     74         AVLNode* pright = llRotate(p->rChild);
     75         return rrRotate(p);
     76     }
     77     //插入新结点,保持平衡 
     78     void insert(int data, AVLNode*& root){
     79         if (!root){
     80             root = new AVLNode(data);
     81         }
     82         else{
     83             if (data < root->data){
     84                 insert(data, root->lChild);
     85                 //插入新结点后,如果打破平衡,则需要动态调整 
     86                 if (height(root->lChild) - height(root->rChild) == 2){
     87                     if (data < root->lChild->data)
     88                         root = llRotate(root);
     89                     else
     90                         root = lrRotate(root);
     91                 }
     92             }
     93             else if (data > root->data){
     94                 insert(data, root->rChild);
     95                 //插入新结点后,如果打破平衡,则需要动态调整 
     96                 if (height(root->rChild) - height(root->lChild) == 2){
     97                     if (data > root->rChild->data)
     98                         root = rrRotate(root);
     99                     else
    100                         root = rlRotate(root);
    101                 }
    102             }
    103             else{
    104                 cout << "AVL中已存在该值:" << data << endl;
    105             }
    106         }
    107         //平衡后,需要更新根结点的高度值
    108         root->height = max(height(root->lChild), height(root->rChild)) + 1;
    109     }
    110     //删除结点,保持平衡 
    111     void del(int data, AVLNode*& root){
    112         if (data < root->data){
    113             del(data, root->lChild);
    114             //删除点之后,若AVL树失去平衡,则进行调整
    115             if (height(root->rChild) - height(root->lChild) == 2){
    116                 AVLNode* r = root->rChild;
    117                 if (height(r->lChild) > height(r->rChild))
    118                     root = rlRotate(root);
    119                 else
    120                     root = rrRotate(root);
    121             }
    122         }
    123         else if (data > root->data){
    124             del(data, root->rChild);
    125             //删除点之后,若AVL树失去平衡,则进行调整
    126             if (height(root->lChild) - height(root->rChild) == 2){
    127                 AVLNode* l = root->lChild;
    128                 if (height(l->lChild) > height(l->rChild))
    129                     root = llRotate(root);
    130                 else
    131                     root = lrRotate(root);
    132             }
    133         }
    134         else{
    135             //此时root为要删除的点 
    136             if (root->lChild && root->rChild){
    137                 if (height(root->lChild) > height(root->rChild)){
    138                     // 如果root的左子树比右子树高;
    139                     // 则(01)找出root的左子树中的最大节点
    140                     //   (02)将该最大节点的值赋值给root。
    141                     //   (03)删除该最大节点。
    142                     // 这类似于用"root的左子树中最大节点"做"root"的替身;
    143                     // 采用这种方式的好处是:删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。
    144                     AVLNode* maxNode = finMaxNode(root->lChild);
    145                     root->data = maxNode->data;
    146                     del(maxNode->data, root->lChild);
    147                 }
    148                 else{
    149                     AVLNode* minNode = finMinNode(root->rChild);
    150                     root->data = minNode->data;
    151                     del(minNode->data, root->rChild);
    152                 }
    153             }
    154             else{
    155                 if (root->lChild){
    156                     root->data = root->lChild->data;
    157                     root->lChild = nullptr;
    158                 }
    159                 else if (root->rChild){
    160                     root->data = root->rChild->data;
    161                     root->rChild = nullptr;
    162                 }
    163                 else{
    164                     root = nullptr;//参数是引用,所以此处修改了主函数中的root值 
    165                 }
    166             }
    167         }
    168     }
    169     void inOrder(AVLNode* root){
    170         if (root){
    171             inOrder(root->lChild);
    172             cout << root->data << endl;
    173             inOrder(root->rChild);
    174         }
    175     }
    176 };
    177 
    178 int main(){
    179     AVL tree;
    180     tree.insert(5, tree.root);
    181     tree.insert(15, tree.root);
    182     tree.insert(25, tree.root);
    183     tree.insert(35, tree.root);
    184     tree.insert(45, tree.root);
    185     tree.insert(55, tree.root);
    186     tree.del(55, tree.root);
    187     tree.inOrder(tree.root);
    188 
    189     system("pause");
    190     return 0;
    191 }
    View Code

    参考资料

    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平衡二叉树的代码)

  • 相关阅读:
    用elasticsearch分析中国大学省份分布
    【翻译】Kinect v1和Kinect v2的彻底比较
    翻译 Tri-Ace:在Shader里近似渲染公式
    翻译 基于物理渲染的美术资源设计流程
    翻译 次世代基于物理渲染的反射模型
    关于Depth Bounds Test (DBT)和在CE3的运用
    使用Xcode GPU Frame Caputre教程
    如何使用Xcode分析调试在真机运行的UE4 IOS版游戏
    个人翻译的cedec2010基于物理的光照
    使用Nsight查找CE3的渲染bug
  • 原文地址:https://www.cnblogs.com/wxwhnu/p/11421525.html
Copyright © 2011-2022 走看看