• 二叉查找树系列六:AVL树


    动态符号表可以用二叉查找树表示,最坏情况下,二叉查找树可完全偏斜,高度为n,其平均和最坏查找时间都是O(n);最好情况下,二叉查找树的结点尽可能靠近根节点,其平均和最坏查找时间都是O(log2n)。因而,为了得到较好的查询效率,最理想的情况是时刻保持树是一棵完全二叉树,然而,为了达到这种要求就会使插入和删除的操作付出很高的代价。对此,人们设计出在高度上相对平衡的二叉查找树,其查找、插入和删除的时间都是O(log2n)。

    AVL树是有Adelson-Velskii和Landis提出的,一种在高度上相对平衡的二叉查找树。由于该树的平衡性,其平均和最坏查找时间都是O(log2n),且插入和删除也只需O(log2n)时间,插入和删除后的树仍是高度上相对平衡的。

    (1)AVL树的定义

    空二叉树是AVL树,如果T是一棵非空二叉查找树,其左子树为TL,右子树为TR,TL的高度为HL,TR的高度为HR,则T是AVL树当且仅当:

    a. TL和TR是AVL树;

    b. |HL-HR|<=1.

    或者说:AVL树是每个结点的左右子树高度最多差1的二叉查找树。

    由斐波那契数可以推出AVL树的高度最多为1.44log(N+2)-1.328,它只比logN多一点。

    (2)AVL树的插入

    当向AVL树中插入新的结点时,需要更新通向根结点路径上那些结点的所有平衡信息,此外,插入可能会破坏AVL树的平衡特性,通常需要在插入后通过修正来保持AVL树的特性,对此常用的方法是旋转。

    假如插入新结点后结点A的两棵子树的高度差为2,那么可以推断插入应是下列四种情况中的一种:

    LL:对A的左儿子的左子树进行一次插入

    LR:对A的左儿子的右子树进行一次插入

    RL:对A的右儿子的左子树进行一次插入

    RR:对A的右儿子的右子树进行一次插入

    上面的情形中LL和RR是对称的,LR和RL是对称的,对于前者,可以通过单旋转恢复AVL树的特性,对于后者可以通过双旋转恢复AVL树的平衡性。

    a. 单旋转

    LL情形下:

    如下图所示:结点k2不满足AVL平衡特性,左子树比右子树的高度高2。通过调整之后,k1成了树根,二叉查找树的性质又使k2成为了k1的右儿子,Y成为了k2的左儿子,二叉查找树的性质没有被破坏,且AVL的特性也恢复了。

    对应的,RR情形的单旋转如下:其中k1成为k2的左儿子,Y成为k1的右儿子

    b. 双旋转

    LR情形:如果插入是在结点的左儿子的右子树中,那么通过单旋转并不能恢复AVL树的平衡特性,如下图:

    此时就需要双旋转,如下图所示,调整的过程中首先找出不平衡点k3,顺着k3依次找出3个点:k3,k1,k2,k2是最后一个点,它将成为旋转后的新的根结点,并根据二叉查找树的性质让k1,k3分别成为k2的左右儿子,B和C分别成为k1和k3的右儿子和左儿子:

    对应的,对于RL情形,旋转如下:

    (3)AVL树插入C++实现

     设计两个类AVLNode和AVLTree,其中AVLTree为AVLNode的友元:

      1 /***********AVLNode.h***********/
      2 #ifndef AVLNODE_H
      3 #define AVLNODE_H
      4 
      5 template<class T> class AVLTree;
      6 template<class T>
      7 class AVLNode
      8 {
      9 friend class AVLTree<T>;
     10 public:
     11     AVLNode()
     12     {
     13         data = 0;
     14         left = NULL;
     15         right = NULL;
     16         height = 0;
     17     }
     18     AVLNode(T val)
     19     {
     20         data = val;
     21         left = NULL;
     22         right = NULL;
     23         height = 0;
     24     }
     25 
     26 public:
     27     T data;
     28     AVLNode* left;
     29     AVLNode* right;
     30     int height;
     31 };
     32 
     33 #endif
     34 
     35 /************AVLTree.h**************/
     36 #ifndef AVLTREE_H
     37 #define AVLTREE_H
     38 
     39 #include "AVLNode.h"
     40 
     41 template<class T>
     42 class AVLTree
     43 {
     44 public:
     45     AVLTree();
     46     AVLNode<T>* Insert(const T data, AVLNode<T>* node);
     47     void LevelOrder(AVLNode<T>* root);
     48 private:
     49     AVLNode<T>* root;
     50 };
     51 
     52 #endif
     53 
     54 /************AVLTree.CPP**************/
     55 #include "AVLNode.h"
     56 #include "AVLTree.h"
     57 #include<queue>
     58 #include<iostream>
     59 using namespace std;
     60 
     61 template<class T>
     62 AVLTree<T>::AVLTree()
     63 {
     64     root = NULL;
     65 }
     66 
     67 template<class T>
     68 int Height(AVLNode<T>* node)
     69 {
     70     if(node != NULL)
     71         return node->height;
     72     return -1;
     73 }
     74 
     75 template<class T>
     76 AVLNode<T>* SingleRotateWithLeft(AVLNode<T>* node)
     77 {
     78     if(node != NULL)
     79     {
     80         AVLNode<T>* k;
     81         k = node->left;
     82         node->left = k->right;
     83         k->right = node;
     84 
     85         node->height = max(Height(node->left),Height(node->right)) + 1;
     86         k->height = max(Height(k->left),Height(k->right)) + 1;
     87 
     88         return k;
     89     }
     90     return NULL;
     91 }
     92 
     93 template<class T>
     94 AVLNode<T>* SingleRotateWithRight(AVLNode<T>* node)
     95 {
     96     if(node != NULL)
     97     {
     98         AVLNode<T>* k;
     99         k = node->right;
    100         node->right = k->left;
    101         k->left = node;
    102 
    103         node->height = max(Height(node->left),Height(node->right)) + 1;
    104         k->height = max(Height(k->left),Height(k->right)) + 1;    
    105 
    106         return k;
    107     }
    108     return NULL;
    109 }
    110 
    111 template<class T>
    112 AVLNode<T>* DoubleRotateWithLeft(AVLNode<T>* node)
    113 {
    114     node->left = SingleRotateWithRight(node->left);
    115     return SingleRotateWithLeft(node);
    116 }
    117 
    118 template<class T>
    119 AVLNode<T>* DoubleRotateWithRight(AVLNode<T>* node)
    120 {
    121     node->right = SingleRotateWithLeft(node->right);
    122     return SingleRotateWithRight(node);
    123 }
    124 
    125 template<class T>
    126 void AVLTree<T>::LevelOrder(AVLNode<T>* root)
    127 {
    128     if(root != NULL)
    129     {    
    130         queue<AVLNode<T>*> q;
    131         AVLNode<T>* curr = root;
    132         AVLNode<T>* temp = root;
    133         while(curr)
    134         {
    135             cout<<curr->data<<"("<<curr->height<<")"<<endl;
    136             if(curr->left)
    137                 q.push(curr->left);
    138             if(curr->right)
    139                 q.push(curr->right);
    140             if(!q.empty())
    141             {
    142                 curr = q.front();
    143                 q.pop();
    144             }
    145             else
    146                 curr = NULL;
    147         }
    148     }
    149 }
    150 
    151 template<class T>
    152 AVLNode<T>* AVLTree<T>::Insert(const T data, AVLNode<T>* root)
    153 {
    154     if(root == NULL)
    155         return root = new AVLNode<T>(data);
    156     else
    157     {
    158         AVLNode<T>* node = root;
    159         if(node->data > data)
    160         {
    161             node->left = Insert(data,node->left);
    162             if(Height(node->left) - Height(node->right) == 2)
    163             {
    164                 if(data < node->left->data)
    165                     node = SingleRotateWithLeft(node);
    166                 else
    167                     node = DoubleRotateWithLeft(node);
    168             }            
    169         }
    170         else if(node->data < data)
    171         {
    172             node->right = Insert(data,node->right);
    173             if(Height(node->right) - Height(node->left) == 2)
    174             {
    175                 if(data > node->right->data)
    176                     node = SingleRotateWithRight(node);
    177                 else
    178                     node = DoubleRotateWithRight(node);
    179             }
    180         }
    181         node->height = max(Height(node->left),Height(node->right))+1;
    182         return node;
    183     }
    184     
    185 }
    186 
    187 // AVL.cpp : 定义控制台应用程序的入口点。
    188 //
    189 
    190 #include "stdafx.h"
    191 #include "AVLNode.h"
    192 #include "AVLTree.h"
    193 #include "AVLTree.cpp"
    194 
    195 #include <iostream>
    196 
    197 using namespace std;
    198 
    199 
    200 int _tmain(int argc, _TCHAR* argv[])
    201 {
    202     AVLTree<int> avl;
    203     AVLNode<int>* root = avl.Insert(3,NULL);
    204     root = avl.Insert(2,root);
    205     root = avl.Insert(1,root);
    206 
    207     avl.LevelOrder(root);
    208 
    209      system("pause");
    210     return 0;
    211 }
    View Code
  • 相关阅读:
    深入理解memcached
    如何查看你的 memcached 的状态
    转: Linux 技巧:让进程在后台可靠运行的几种方法
    centos 如何用 rsyslog 搭建本地日志服务(续1: omprog模块与php deamon的配合使用)
    转: 解决MSYS2下的中文乱码问题
    解决windows下vim方向键变成 ABCD 的问题
    centos 如何用 rsyslog 搭建本地日志服务
    转:理解 Linux 的硬链接与软链接
    php include include_once require require_once 的区别与联系
    让块级元素水平垂直居中
  • 原文地址:https://www.cnblogs.com/sophia-yun/p/3167381.html
Copyright © 2020-2023  润新知