zoukankan      html  css  js  c++  java
  • 平衡二叉树

    参考: http://www.cppblog.com/cxiaojia/archive/2012/08/20/187776.html

    一 定义

      平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树。1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵树,所以它又叫AVL树。平衡二叉树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。

      平衡二叉树实现的大部分过程和二叉查找树是一样的(学平衡二叉树之前一定要会二叉查找树),区别就在于插入和删除之后要写一个旋转算法去维持平衡.

    二 难点操作

    1 旋转

      对于一棵AVL树,由于一次插入删除操作造成该树高度不平衡时,根节点的两棵子树的高度只能差2. 而不平衡的情况只能是以下四种:

      1、6节点的左子树3节点高度比右子树7节点大2,左子树3节点的左子树1节点高度大于右子树4节点,这种情况成为左左。

      2、6节点的左子树2节点高度比右子树7节点大2,左子树2节点的左子树1节点高度小于右子树4节点,这种情况成为左右。

      3、2节点的左子树1节点高度比右子树5节点小2,右子树5节点的左子树3节点高度大于右子树6节点,这种情况成为右左。

      4、2节点的左子树1节点高度比右子树4节点小2,右子树4节点的左子树3节点高度小于右子树6节点,这种情况成为右右。

      从图2中可以可以看出,1和4两种情况是对称的,这两种情况的旋转算法是一致的,只需要经过一次旋转就可以达到目标,我们称之为单旋转。2和3两种情况也是对称的,这两种情况的旋转算法也是一致的,需要进行两次旋转,我们称之为双旋转。

    (1) 单旋转

      单旋转是针对于左左和右右这两种情况的解决方案,这两种情况是对称的,只要解决了左左这种情况,右右就很好办了。图3是左左情况的解决方案,节点k2不满足平衡特性,因为它的左子树k1比右子树Z深2层,而且k1子树中,更深的一层的是k1的左子树X子树,所以属于左左情况。

      为使树恢复平衡,我们把k2变成这棵树的根节点,因为k2大于k1,把k2置于k1的右子树上,而原本在k1右子树的Y大于k1,小于k2,就把Y置于k2的左子树上,这样既满足了二叉查找树的性质,又满足了平衡二叉树的性质。

      这样的操作只需要一部分指针改变,结果我们得到另外一颗二叉查找树,它是一棵AVL树,因为X向上一移动了一层,Y还停留在原来的层面上,Z向下移动了一层。使得根节点两棵子树的高度差小于2

    (2) 双旋转

      对于左右和右左这两种情况,单旋转不能使它达到一个平衡状态,要经过两次旋转。双旋转是针对于这两种情况的解决方案,同样的,这样两种情况也是对称的,只要解决了左右这种情况,右左就很好办了。图4是左右情况的解决方案,节点k3不满足平衡特性,因为它的左子树k1比右子树Z深2层,而且k1子树中,更深的一层的是k1的右子树k2子树,所以属于左右情况。

       为使树恢复平衡,我们需要进行两步,第一步,把k1作为根,进行一次右右情况下的旋转操作,旋转之后就变成了左左情况,所以第二步再进行一次左左情况下的旋转操作,最后得到了一棵以k2为根的平衡二叉树。

    2 插入

      插入的方法和二叉查找树基本一样,区别是,插入完成后需要从插入的节点开始维护一个到根节点的路径,每经过一个节点都要维持树的平衡。维持树的平衡要根据高度差的特点选择不同的旋转算法。

    3 删除

      删除的方法也和二叉查找树的一致,区别是,删除完成后,需要从删除节点的父亲开始向上维护树的平衡一直到根节点。

    下面是完整的代码展示

      1 #include<iostream>
      2 //AVL树节点信息
      3 template<typename T>
      4 class TreeNode
      5 {
      6 public:
      7     TreeNode() :
      8         lson_(NULL), rson_(NULL)
      9     {
     10 
     11     }
     12     T data_;//
     13     TreeNode* lson_;//指向左儿子的地址
     14     TreeNode* rson_;//指向右儿子的地址
     15 };
     16 //AVL树类的属性和方法声明
     17 template<typename T>
     18 class AVLTree
     19 {
     20 public:
     21     AVLTree(); 
     22     ~AVLTree();
     23     void insert(T x);//插入接口
     24     TreeNode<T>* find(T x);//查找接口
     25     void Delete(T x);//删除接口
     26     void traversal();//遍历接口
     27 
     28 private:
     29     void insertpri(TreeNode<T>* &node, T x);//插入
     30     void Deletepri(TreeNode<T>* &node, T x);//删除
     31 
     32     TreeNode<T>* findpri(TreeNode<T>* node, T x);//查找
     33     void insubtree(TreeNode<T>* node);//中序遍历
     34 
     35     int height(TreeNode<T>* node);//求树的高度
     36 
     37     void SingRotateLeft(TreeNode<T>* &k2);//左左情况下的旋转
     38     void SingRotateRight(TreeNode<T>* &k2);//右右情况下的旋转
     39     void DoubleRotateLR(TreeNode<T>* &k3);//左右情况下的旋转
     40     void DoubleRotateRL(TreeNode<T>* &k3);//右左情况下的旋转
     41 
     42     void Delete(TreeNode<T>* &root);
     43 private:
     44     TreeNode<T>* root_;//根节点
     45 };
     46 template<typename T>
     47 AVLTree<T>::AVLTree()
     48     : root_(NULL)
     49 {
     50 }
     51 template<typename T>
     52 AVLTree<T>::~AVLTree()
     53 {
     54     Delete(root_);
     55 }
     56 //计算节点的高度
     57 template<typename T>
     58 int AVLTree<T>::height(TreeNode<T>* node)
     59 {
     60     if (node != NULL)
     61     {
     62         int lh = height(node->lson_);
     63         int rh = height(node->rson_);
     64         return lh >= rh ? (lh + 1) : (rh + 1);
     65     }
     66     return -1;
     67 }
     68 template<typename T>
     69 void AVLTree<T>::Delete(TreeNode<T>* &root)
     70 {
     71     if (root->lson_)
     72     {
     73         Delete(root->lson_);
     74         root->lson_ =nullptr;
     75     }
     76     if (root->rson_)
     77     {
     78         Delete(root->rson_);
     79         root->rson_ = nullptr;
     80     }
     81        
    82
    83 delete root; 84 root = nullptr; 85
    86 } 87 //左左情况下的旋转 88 template<typename T> 89 void AVLTree<T>::SingRotateLeft(TreeNode<T>* &k2) 90 { 91 if (!k2) 92 return; 93 94 TreeNode<T> *k1 = k2->lson_; 95 if (k1) 96 { 97 k2->lson_ = k1->rson_; 98 k1->rson_ = k2; 99 k2 = k1; 100 } 101 102 } 103 //右右情况下的旋转 104 template<typename T> 105 void AVLTree<T>::SingRotateRight(TreeNode<T>* &k2) 106 { 107 if (!k2) 108 return; 109 110 TreeNode<T> *k1 = k2->rson_; 111 if (k1) 112 { 113 k2->rson_ = k1->lson_; 114 k1->lson_ = k2; 115 k2 = k1; 116 } 117 } 118 //左右情况的旋转 119 template<typename T> 120 void AVLTree<T>::DoubleRotateLR(TreeNode<T>* &k3) 121 { 122 if (!k3) 123 return; 124 125 SingRotateRight(k3->lson_); 126 SingRotateLeft(k3); 127 } 128 //右左情况的旋转 129 template<typename T> 130 void AVLTree<T>::DoubleRotateRL(TreeNode<T>* &k3) 131 { 132 if (!k3) 133 return; 134 135 SingRotateLeft(k3->rson_); 136 SingRotateRight(k3); 137 } 138 //插入 139 template<typename T> 140 void AVLTree<T>::insertpri(TreeNode<T>* &node, T x) 141 { 142 if (node == NULL)//如果节点为空,就在此节点处加入x信息 143 { 144 node = new TreeNode<T>(); 145 node->data_ = x; 146 } 147 else if (node->data_ >= x)//如果x小于节点的值,就继续在节点的左子树中插入x 148 { 149 insertpri(node->lson_, x); 150 if (2 == height(node->lson_) - height(node->rson_)) 151 { 152 if (x < node->lson_->data_) 153 SingRotateLeft(node); 154 else 155 DoubleRotateLR(node); 156 } 157 } 158 else//如果x大于节点的值,就继续在节点的右子树中插入x 159 { 160 insertpri(node->rson_, x); 161 if (2 == height(node->rson_) - height(node->lson_))//如果高度之差为2的话就失去了平衡,需要旋转 162 { 163 if (x > node->rson_->data_) 164 SingRotateRight(node); 165 else 166 DoubleRotateRL(node); 167 } 168 } 169 } 170 //插入接口 171 template<typename T> 172 void AVLTree<T>::insert(T x) 173 { 174 insertpri(root_, x); 175 int lh = height(root_); 176 } 177 //查找 178 template<typename T> 179 TreeNode<T>* AVLTree<T>::findpri(TreeNode<T>* node, T x) 180 { 181 if (!node)//如果节点为空说明没找到,返回NULL 182 return NULL; 183 if (node->data_ > x)//如果x小于节点的值,就继续在节点的左子树中查找x 184 return findpri(node->lson_, x); 185 else if (node->data_ < x)//如果x大于节点的值,就继续在节点的右子树中查找x 186 return findpri(node->rson_, x); 187 else//如果相等,就找到了此节点 188 return node; 189 } 190 //查找接口 191 template<typename T> 192 TreeNode<T>* AVLTree<T>::find(T x) 193 { 194 return findpri(root_, x); 195 } 196 //删除 197 template<typename T> 198 void AVLTree<T>::Deletepri(TreeNode<T>* &node, T x) 199 { 200 if (!node) 201 return;//没有找到值是x的节点 202 203 if (x < node->data_) 204 { 205 Deletepri(node->lson_, x);//如果x小于节点的值,就继续在节点的左子树中删除x 206 if (height(node->rson_) - height(node->lson_) == 2) 207 { 208 if (height(node->rson_->lson_)>height(node->rson_->rson_)) 209 DoubleRotateRL(node); 210 else 211 SingRotateRight(node); 212 } 213 } 214 else if (x > node->data_) 215 { 216 Deletepri(node->rson_, x);//如果x大于节点的值,就继续在节点的右子树中删除x 217 if (height(node->lson_) - height(node->rson_) == 2) 218 { 219 if (height(node->lson_->rson_) > height(node->lson_->lson_)) 220 DoubleRotateLR(node); 221 else 222 SingRotateLeft(node); 223 } 224 } 225 else//如果相等,此节点就是要删除的节点 226 { 227 if (node->lson_&&node->rson_)//此节点有两个儿子 228 { 229 TreeNode<T>* temp_fathor = node; 230 TreeNode<T>* temp = node->rson_;//temp指向节点的右儿子 231 while (temp->lson_)//找到右子树中值最小的节点 232 { 233 temp_fathor = temp; 234 temp = temp->lson_; 235 } 236 237 //把右子树中最小节点的值赋值给本节点 238 node->data_ = temp->data_; 239 delete temp_fathor->lson_; 240 temp_fathor->lson_ = nullptr; 241 242 if (2 == height(node->lson_) - height(node->rson_)) 243 { 244 if (height(node->lson_->rson_) > height(node->lson_->lson_)) 245 DoubleRotateLR(node); 246 else 247 SingRotateLeft(node); 248 } 249 } 250 else//此节点有1个或0个儿子 251 { 252 TreeNode<T>* temp = node; 253 if (node->lson_ == NULL)//有右儿子或者没有儿子 254 node = node->rson_; 255 else if (node->rson_ == NULL)//有左儿子 256 node = node->lson_; 257 delete(temp); 258 temp = NULL; 259 } 260 } 261 } 262 //删除接口 263 template<typename T> 264 void AVLTree<T>::Delete(T x) 265 { 266 Deletepri(root_, x); 267 } 268 //中序遍历函数 269 template<typename T> 270 void AVLTree<T>::insubtree(TreeNode<T>* node) 271 { 272 if (node == NULL) 273 return; 274 insubtree(node->lson_);//先遍历左子树 275 std::cout << node->data_ << " ";//输出根节点 276 insubtree(node->rson_);//再遍历右子树 277 } 278 //中序遍历接口 279 template<typename T> 280 void AVLTree<T>::traversal() 281 { 282 insubtree(root_); 283 }
  • 相关阅读:
    浙大数据结构课后习题 练习二 7-2 Reversing Linked List (25 分)
    浙大数据结构课后习题 练习二 7-2 一元多项式的乘法与加法运算 (20 分)
    浙大数据结构课后习题 练习一 7-1 Maximum Subsequence Sum (25 分)
    浙大数据结构课后习题 练习一 7-1 最大子列和问题 (20 分)
    PAT Basic 1019 数字黑洞 (20 分)
    PAT Basic 1017 A除以B (20 分)
    PAT Basic 1013 数素数 (20 分)
    PAT Basic 1007 素数对猜想 (20 分)
    PAT Basic 1003 我要通过! (20 分)
    自动化运维——HelloWorld(一)
  • 原文地址:https://www.cnblogs.com/talenth/p/6880094.html
Copyright © 2011-2022 走看看