AVL树探秘

一、AVL树

  AVL树是一种平衡查找树,在前面的两篇文章:二叉搜索树 和 红黑树 中都提到过。由于二叉搜索树在某些特殊情况下是不平衡的(任意一个结点深度过大),因此其一些动态集合操作在最坏情况下的时间复杂度为O(n)。因此提出一些对二叉搜索树效率改进的树结构使最坏时间复杂度降为O(lgn),AVL树和红黑树就是其中的代表,除此之外,还有一些如AA-tree、B-tree、2-3-tree等。使不平衡树变平衡最关键的是找到“平衡条件”,我们已经在前面一篇文章中详述了红黑树的平衡条件是:对节点进行着色,并约束从根节点到任何叶子节点的长度,其中,约定了5条规定,稍显复杂。而AVL树的平衡条件则显得格外简单:只用保证左右子树的高度不超过1即可。

二、AVL树的实现

1、数据结构

节点类:因为需要控制节点的高度,所以高度是一个属性。指针域包括left、right,parent可以包括也可以不要,本文的实现中,我们包括parent。

struct AVLNode {
        AVLNode        *Parent;
        AVLNode        *Left;
        AVLNode        *Right;
        int            m_nHeight;
        int            m_nValue;
    };

2、节点的平衡

当插入新的节点或者删除节点时,会导致树的不平衡,即其中有节点的左右子树的高度相差>1,这个时候就需要调节树使之平衡。可能出现不平衡的情况总共有以下几种:

////////////////////////////////////////

a   a   a   a
      /    /       \     \
    b     b         b    b
   /       \       /       \
 c         c     c         c
LL         LR    RL        RR

//////////////////////////////////////

  总共就只会出现这四种情况,对这四种情况的分类很多书上有各自的说法。其中1、4和2、3是对称的,我们用LL、LR、RL、RR来分别表示,要使这几种情况平衡,我们只用做简单的旋转操作就OK了,针对1、4,有的说法是做单旋,有的说法是外旋,而2、3,则做双旋或内旋,不管是哪种说法,其本质是不变的。在我们的实现中,采用单旋和双旋,双旋就是做两次单旋:

//单旋
void _LeftRotation( AVLNode *node );
void _RightRotation( AVLNode *node );

//双旋
void _LeftRightRotation( AVLNode *node );
void _RightLeftRotation( AVLNode *node );

3、平衡的修复

  在插入节点和删除节点的时候,会破坏树的平衡条件,这个时候就需要修复。我们采用尽可能少地改动原有代码的原则来修复,这个原则和红黑树的修复操作是一致的,即插入和删除操作我们依然沿用二叉搜索树的实现,只在后面添加修复的代码即可。

  如何修复?首先,插入和删除会破坏节点的高度,所以,应更新结点的高度;其次,插入和删除破坏了树中某些节点的平衡,所以,应针对上面四种情况分别平衡节点。所以,这里就需要两个函数:一个更新结点高度的函数UpdateHeight( AVLNode *node );一个平衡节点的函数: BalanceNode( AVLNode *node )。

void AVLTree::_UpdateHeight( AVLNode *node )
{
    AVLNode *l = node->Left, *r = node->Right;

    if ( l && r )
        node->m_nHeight = max( l->m_nHeight, r->m_nHeight ) + 1;
    else if ( l )
        node->m_nHeight = l->m_nHeight + 1;
    else if ( r )
        node->m_nHeight = r->m_nHeight + 1;
    else node->m_nHeight = 0;
}
 1 //////////////////////////////////////////////////////////////////////////
 2 //        a    a    a    a
 3 //       /   /     \    4 //    b   b       b   b
 5 //   /     \     /      6 //  c       c   c       c
 7 // LL       LR  RL      RR
 8 //////////////////////////////////////////////////////////////////////////
 9 void AVLTree::_BalanceNode( AVLNode *node )
10 {
11     int nBlance = _GetBalanceFactor( node );
12     if ( nBlance > 1 ) { //L
13         //(1)
14         //if ( _GetBalanceFactor( node->Left ) < 0 ) //LR
15         //    _LeftRightRotation( node ); //双旋
16         //else _RightRotation( node ); //LL //单旋
17
18         //(2)
19         if ( _GetBalanceFactor( node->Left ) < 0 )
20             _LeftRotation( node->Left );
21         _RightRotation( node );
22     }
23     if ( nBlance < -1 ) { //R
24         if ( _GetBalanceFactor( node ) > 0 ) { //RL
25             _RightRotation( node->Right );
26         }
27         _LeftRotation( node );
28     }
29 }
30
31 //平衡因子(左右子树的高度差)
32 int AVLTree::_GetBalanceFactor( AVLNode *node )
33 {
34     AVLNode *l = node->Left, *r = node->Right;
35
36     if ( l && r )
37         return l->m_nHeight - r->m_nHeight;
38     else if ( l )
39         return l->m_nHeight + 1;
40     else if ( r )
41         return -r->m_nHeight - 1;
42     else return 0;
43 }

基本上该注意的点都提到了,下面附上详细代码实现:

 1 #ifndef __AVL_TREE_H_
 2 #define __AVL_TREE_H_
 3
 4 class AVLTree
 5 {
 6 private:
 7     struct AVLNode {
 8         AVLNode        *Parent;
 9         AVLNode        *Left;
10         AVLNode        *Right;
11         int            m_nHeight;
12         int            m_nValue;
13     };
14 public:
15     AVLTree(AVLNode *root = NULL):m_pRoot(root) {}
16     ~AVLTree() {
17         _RecursiveDeleteNode(m_pRoot);
18     }
19
20     bool Search( const int search_value ) const;
21     bool Insert( const int value );
22     bool Delete( const int delete_value );
23
24     void Print() const;
25
26 private:
27     void _RecursiveDeleteNode(AVLNode *node) {
28         if ( node ) {
29             _RecursiveDeleteNode( node->Left );
30             _RecursiveDeleteNode( node->Right );
31             delete node;
32         }
33         node = NULL;
34     }
35
36     void _DeleteNode( AVLNode *delete_node );
37     void _Delete_Transplant( AVLNode *unode, AVLNode *vnode );
38     void _InsertNode( const int insert_value );
39     AVLNode * _SearchNode( AVLNode *node, const int search_value ) const;
40
41     //单旋
42     void _LeftRotation( AVLNode *node );
43     void _RightRotation( AVLNode *node );
44
45     //双旋
46     void _LeftRightRotation( AVLNode *node );
47     void _RightLeftRotation( AVLNode *node );
48
49     AVLNode* Minimum( AVLNode *node );
50
51     //树高
52     int _Height ( AVLNode *node );
53     void _UpdateHeight( AVLNode *node );
54     //平衡因子
55     int _GetBalanceFactor( AVLNode *node );
56     //平衡失去平衡的节点
57     void _BalanceNode( AVLNode *node );
58
59     void _Print ( AVLNode *node ) const;
60
61 private:
62     AVLNode *m_pRoot;
63
64 };
65 #endif//__AVL_TREE_H_

  1 #include <iostream>
  2 #include <algorithm>
  3 using namespace std;
  4
  5 #include "AVL_Tree.h"
  6
  7 bool AVLTree::Search( const int search_value ) const
  8 {
  9     return _SearchNode( m_pRoot, search_value ) != NULL;
 10 }
 11
 12 AVLTree::AVLNode * AVLTree::_SearchNode( AVLNode *node, const int search_value ) const
 13 {
 14     while ( node && search_value != node->m_nValue ) {
 15         if ( search_value < node->m_nValue )
 16             node = node->Left;
 17         else
 18             node = node->Right;
 19     }
 20     return node;
 21 }
 22
 23 bool AVLTree::Insert( const int value )
 24 {
 25     //该值已存在
 26     if ( Search( value ) )
 27         return false;
 28     else {
 29         _InsertNode( value );
 30         return true;
 31     }
 32 }
 33
 34 void AVLTree::_InsertNode( const int insert_value )
 35 {
 36     AVLNode *node = m_pRoot;
 37     AVLNode *temp_node = NULL;
 38
 39     //先找到待插入节点的位置
 40     while ( node ) {
 41         temp_node = node;
 42         node = ( insert_value < node->m_nValue )?node->Left:node->Right;
 43     }
 44
 45     AVLNode *insert_node = new AVLNode();
 46     insert_node->m_nValue = insert_value;
 47
 48     insert_node->Parent = temp_node;
 49
 50     //空树
 51     if ( temp_node == NULL )
 52         m_pRoot = insert_node;
 53     else {
 54         if ( insert_value < temp_node->m_nValue )//左子树
 55             temp_node->Left = insert_node;
 56         else
 57             temp_node->Right = insert_node; //右子树
 58     }
 59
 60     //更新插入节点的高度和平衡节点
 61     while ( insert_node ) {
 62         _UpdateHeight( insert_node );
 63         _BalanceNode( insert_node );
 64         insert_node = insert_node->Parent;
 65     }
 66 }
 67
 68 bool AVLTree::Delete( const int delete_value )
 69 {
 70     AVLNode *delete_node = _SearchNode( m_pRoot, delete_value );
 71
 72     //节点不存在
 73     if ( delete_node == NULL )
 74         return false;
 75     else {
 76         _DeleteNode( delete_node );
 77         return true;
 78     }
 79 }
 80
 81 void AVLTree::_DeleteNode( AVLNode *delete_node )
 82 {
 83     if ( delete_node->Left == NULL )
 84         _Delete_Transplant( delete_node, delete_node->Right );
 85     else if ( delete_node->Right == NULL )
 86         _Delete_Transplant( delete_node, delete_node->Left );
 87     else {
 88         AVLNode *min_node = Minimum( delete_node->Right );
 89         if ( min_node->Parent != delete_node ) {
 90             _Delete_Transplant( min_node, min_node->Right );
 91             min_node->Right = delete_node->Right;
 92             min_node->Right->Parent = min_node;
 93         }
 94         _Delete_Transplant( delete_node, min_node );
 95         min_node->Left = delete_node->Left;
 96         min_node->Left->Parent = min_node;
 97     }
 98
 99     //更新结点的高度和平衡节点
100     while ( delete_node ) {
101         _UpdateHeight( delete_node );
102         _BalanceNode( delete_node );
103         delete_node = delete_node->Parent;
104     }
105 }
106
107 void AVLTree::_Delete_Transplant( AVLNode *unode, AVLNode *vnode )
108 {
109     if ( unode->Parent == NULL )
110         m_pRoot = vnode;
111     else if ( unode == unode->Parent->Left )
112         unode->Parent->Left = vnode;
113     else
114         unode->Parent->Right = vnode;
115     if ( vnode )
116         vnode->Parent = unode->Parent;
117 }
118
119 AVLTree::AVLNode* AVLTree::Minimum( AVLNode *node )
120 {
121     while ( node->Left )
122         node = node->Left;
123     return node;
124 }
125
126 //树高
127 int AVLTree::_Height( AVLNode *node )
128 {
129     return node->m_nHeight;
130 }
131
132 //平衡因子(左右子树的高度差)
133 int AVLTree::_GetBalanceFactor( AVLNode *node )
134 {
135     AVLNode *l = node->Left, *r = node->Right;
136
137     if ( l && r )
138         return l->m_nHeight - r->m_nHeight;
139     else if ( l )
140         return l->m_nHeight + 1;
141     else if ( r )
142         return -r->m_nHeight - 1;
143     else return 0;
144 }
145
146 void AVLTree::_UpdateHeight( AVLNode *node )
147 {
148     AVLNode *l = node->Left, *r = node->Right;
149
150     if ( l && r )
151         node->m_nHeight = max( l->m_nHeight, r->m_nHeight ) + 1;
152     else if ( l )
153         node->m_nHeight = l->m_nHeight + 1;
154     else if ( r )
155         node->m_nHeight = r->m_nHeight + 1;
156     else node->m_nHeight = 0;
157 }
158
159 //////////////////////////////////////////////////////////////////////////
160 //        a    a    a    a
161 //       /   /     \   162 //    b   b       b   b
163 //   /     \     /     164 //  c       c   c       c
165 // LL       LR  RL      RR
166 //////////////////////////////////////////////////////////////////////////
167 void AVLTree::_BalanceNode( AVLNode *node )
168 {
169     int nBlance = _GetBalanceFactor( node );
170     if ( nBlance > 1 ) { //L
171         //(1)
172         //if ( _GetBalanceFactor( node->Left ) < 0 ) //LR
173         //    _LeftRightRotation( node ); //双旋
174         //else _RightRotation( node ); //LL //单旋
175
176         //(2)
177         if ( _GetBalanceFactor( node->Left ) < 0 )
178             _LeftRotation( node->Left );
179         _RightRotation( node );
180     }
181     if ( nBlance < -1 ) { //R
182         if ( _GetBalanceFactor( node ) > 0 ) { //RL
183             _RightRotation( node->Right );
184         }
185         _LeftRotation( node );
186     }
187 }
188
189 //单旋
190 //左旋
191 void AVLTree::_LeftRotation( AVLNode *node )
192 {
193     if ( node->Right == NULL )
194         return;
195
196     AVLNode *temp_node = node->Right;
197
198     //补
199     node->Right = temp_node->Left;
200     if ( temp_node->Left )
201         temp_node->Left->Parent = node;
202
203     //提
204     temp_node->Parent = node->Parent;
205     if ( node->Parent == NULL )
206         m_pRoot = temp_node;
207     else if ( node == node->Parent->Left )
208         node->Parent->Left = temp_node;
209     else node->Parent->Right = temp_node;
210
211     //降
212     temp_node->Left = node;
213     node->Parent = temp_node;
214
215     _UpdateHeight( node );
216     _UpdateHeight( temp_node );
217 }
218
219 //右旋
220 void AVLTree::_RightRotation( AVLNode *node )
221 {
222     if ( node->Left == NULL )
223         return;
224
225     AVLNode *temp_node = node->Left;
226
227     //补
228     node->Left = temp_node->Right;
229     if ( temp_node->Right )
230         temp_node->Right->Parent = node;
231
232     //提
233     temp_node->Parent = node->Parent;
234     if ( node->Parent == NULL )
235         m_pRoot = temp_node;
236     else if ( node == node->Parent->Left )
237         node->Parent->Left = temp_node;
238     else node->Parent->Right = temp_node;
239
240     //降
241     temp_node->Right = node;
242     node->Parent = temp_node;
243
244     _UpdateHeight( node );
245     _UpdateHeight( temp_node );
246 }
247
248 //双旋
249 //LR
250 void AVLTree::_LeftRightRotation( AVLNode *node )
251 {
252     _LeftRotation( node->Left );
253     _RightRotation( node );
254 }
255
256 //RL
257 void AVLTree::_RightLeftRotation( AVLNode *node )
258 {
259     _RightRotation( node->Right );
260     _RightRotation( node );
261 }
262
263 void AVLTree::Print() const
264 {
265     _Print(m_pRoot);
266 }
267 //打印
268 void AVLTree::_Print ( AVLNode *node ) const
269 {
270     if ( node->Parent == NULL )
271         cout << "root: " << node->m_nValue << endl;
272     else if ( node == node->Parent->Left )
273         cout << "left: " << node->m_nValue << ", parent: " << node->Parent->m_nValue << endl;
274     else cout << "right: " << node->m_nValue << ", parent: " << node->Parent->m_nValue << endl;
275     if ( node->Left )
276         _Print( node->Left );
277     if ( node->Right )
278         _Print( node->Right );
279 }
280
281 int main()
282 {
283     AVLTree al;
284     for (int i = 1; i < 10; i ++) {
285         al.Insert(i);
286
287     }
288     al.Print();
289     for (int i = 1; i < 10; i += 2) {
290         al.Delete(i);
291         al.Print();
292     }
293     return 0;
294 }

时间: 2024-08-24 08:27:34

AVL树探秘的相关文章

AVL树

定义:AVL树是每个节点左子树和右子树的高度差最大为1的二叉查找树 不平衡节点:假设在懒惰删除(删除操作时,并不删除节点,只是对节点进行特定标记)的条件下,插入操作有可能破坏AVL树的平衡特性. 如果插入节点导致平衡性被破坏,那么平衡性遭到破坏的节点只可能出现在插入节点到根节点的路径上.因为插入操作只会改变 插入节点的父节点的高度,而这些父节点就再这条路径上. 调整:对于平衡性遭到破坏的节点,需要对其进行调整以恢复平衡性.调整的方法称为旋转,针对不同的插入情况,调整操作稍有不同. 下面先对插入情

数据结构--AVL树

AVL树是高度平衡的二叉搜索树,较搜索树而言降低了树的高度:时间复杂度减少了使其搜索起来更方便: 1.性质: (1)左子树和右子树高度之差绝对值不超过1: (2)树中每个左子树和右子树都必须为AVL树: (3)每一个节点都有一个平衡因子(-1,0,1:右子树-左子树) (4)遍历一个二叉搜索树可以得到一个递增的有序序列 2.结构: 平衡二叉树是对二叉搜索树(又称为二叉排序树)的一种改进.二叉搜索树有一个缺点就是,树的结构是无法预料的.任意性非常大.它仅仅与节点的值和插入的顺序有关系.往往得到的是

AVL树原理及实现(C语言实现以及Java语言实现)

欢迎探讨,如有错误敬请指正 如需转载,请注明出处http://www.cnblogs.com/nullzx/ 1. AVL定义 AVL树是一种改进版的搜索二叉树.对于一般的搜索二叉树而言,如果数据恰好是按照从小到大的顺序或者从大到小的顺序插入的,那么搜索二叉树就对退化成链表,这个时候查找,插入和删除的时间都会上升到O(n),而这对于海量数据而言,是我们无法忍受的.即使是一颗由完全随机的数据构造成的搜索二叉树,从统计角度去分析,在进行若甘次的插入和删除操作,这个搜索二叉树的高度也不能令人满意.这个

数据结构与算法系列----平衡二叉树(AVL树)

一:背景 平衡二叉树(又称AVL树)是二叉查找树的一个进化体,由于二叉查找树不是严格的O(logN),所以引入一个具有平衡概念的二叉树,它的查找速度是O(logN).所以在学习平衡二叉树之前,读者需要了解二叉查找树的实现,具体链接:二叉查找树 那么平衡是什么意思?我们要求对于一棵二叉查找树 ,它的每一个节点的左右子树高度之差不超过1.(对于树的高度的约定:空节点高度是0:叶子节点高度是1.)例如下图: 如果我们的二叉查找树是不平衡该怎么办?进行旋转.经过分析发现,出现不平衡无外乎四种情况,下面我

AVL树 冲突链表

;红黑树只不过是AVL树的变种而已 ,平衡方式耕地,意味着比AVL旋转的次数少,长应用于关联数组 红黑树和AVL树在实际开发中比较常用 ;AVL树二叉平衡树 适合在内存中使用速度会达到最优化,要是在文件中那么速度大大降低 ;文件中适合用b+树,B+树读文件一次读的孩子结点比较多,一次read读取尽量多的结点到内存中缓存起来,下次直接从内存中返回. ;百万级别的数据存文件用c库函数利用缓冲区一次不要读两个缓冲区的内容(<4096)设计树的结构,超过就自己设计fopen喽自己做大的缓冲区,降低文件访

AVL树,红黑树,B-B+树,Trie树原理和应用

前言:本文章来源于我在知乎上回答的一个问题 AVL树,红黑树,B树,B+树,Trie树都分别应用在哪些现实场景中? 看完后您可能会了解到这些数据结构大致的原理及为什么用在这些场景,文章并不涉及具体操作(如插入删除等等) 目录 AVL树 AVL树原理与应用 红黑树 红黑树原理与应用 B/B+树 B/B+树原理与应用 Trie树 Trie树原理与应用 AVL树 简介: AVL树是最早的自平衡二叉树,在早期应用还相对来说比较广,后期由于旋转次数过多而被红黑树等结构取代(二者都是用来搜索的),AVL树内

AVL树的初步生成与插入操作

平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树.构造与调整方法 平衡二叉树的常用算法有红黑树.AVL.Treap等. 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量. AVL是最先发明的

图解平衡二叉树,AVL树(一)

图解平衡二叉树,AVL树(一) 学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建立的树如图2,才能够最大地体现二叉树的优点. 在上述的例子中,图2就是一棵平衡二叉树.科学家们提出平衡二叉树,就是为了让树的查找性能得到最大的体现(至少我是这样理解的,欢迎批评改正).下面进入今天的正题,平衡二叉树. AVL的定义 平衡二叉查找树:简称平衡二叉树.由前

平衡二叉搜索树(AVL树)的原理及实现源代码(有图文详解和C++、Java实现代码)

一.AVL树(平衡二叉搜索树)是什么? AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的.AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树. 2.带有平衡条件:每个非叶子结点的左右子树的高度之差的绝对值(平衡因子)最多为1. 例如: 5             5 / \            /  \ 2   6         2   6 / \    \         / \ 1  4   7       1  4