剑指offer39:平衡二叉树

Posted wxwreal

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指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平衡二叉树的代码)

以上是关于剑指offer39:平衡二叉树的主要内容,如果未能解决你的问题,请参考以下文章

《剑指offer》:[39-1]判断是否为平衡二叉树

剑指Offer39:平衡二叉树(Java)

剑指OFFER 平衡二叉树

Java 剑指offer(55-2) 平衡二叉树

剑指Offer平衡二叉树(树)

java剑指offer55.平衡二叉树