6天通吃樹結構—— 第二天 平衡二叉樹


       

      上一篇我們聊過,二叉查找樹不是嚴格的O(logN),導致了在真實場景中沒有用武之地,誰也不願意有O(N)的情況發生,

作為一名碼農,肯定會希望能把“范圍查找”做到地球人都不能優化的地步。

     當有很多數據灌到我的樹中時,我肯定會希望最好是以“完全二叉樹”的形式展現,這樣我才能做到“查找”是嚴格的O(logN),

比如把這種”樹“調正到如下結構。

     

這里就涉及到了“樹節點”的旋轉,也是我們今天要聊到的內容。

 

一:平衡二叉樹(AVL)

1:定義

       父節點的左子樹和右子樹的高度之差不能大於1,也就是說不能高過1層,否則該樹就失衡了,此時就要旋轉節點,在

編碼時,我們可以記錄當前節點的高度,比如空節點是-1,葉子節點是0,非葉子節點的height往根節點遞增,比如在下圖

中我們認為樹的高度為h=2。

 1 #region 平衡二叉樹節點
 2     /// <summary>
 3     /// 平衡二叉樹節點
 4     /// </summary>
 5     /// <typeparam name="K"></typeparam>
 6     /// <typeparam name="V"></typeparam>
 7     public class AVLNode<K, V>
 8     {
 9         /// <summary>
10         /// 節點元素
11         /// </summary>
12         public K key;
13 
14         /// <summary>
15         /// 增加一個高度信息
16         /// </summary>
17         public int height;
18 
19         /// <summary>
20         /// 節點中的附加值
21         /// </summary>
22         public HashSet<V> attach = new HashSet<V>();
23 
24         /// <summary>
25         /// 左節點
26         /// </summary>
27         public AVLNode<K, V> left;
28 
29         /// <summary>
30         /// 右節點
31         /// </summary>
32         public AVLNode<K, V> right;
33 
34         public AVLNode() { }
35 
36         public AVLNode(K key, V value, AVLNode<K, V> left, AVLNode<K, V> right)
37         {
38             //KV鍵值對
39             this.key = key;
40             this.attach.Add(value);
41 
42             this.left = left;
43             this.right = right;
44         }
45     }
46     #endregion

 

2:旋轉

    節點再怎么失衡都逃不過4種情況,下面我們一一來看一下。

① 左左情況(左子樹的左邊節點)

我們看到,在向樹中追加“節點1”的時候,根據定義我們知道這樣會導致了“節點3"失衡,滿足“左左情況“,可以這樣想,把這

棵樹比作齒輪,我們在“節點5”處把齒輪往下拉一個位置,也就變成了后面這樣“平衡”的形式,如果用動畫解釋就最好理解了。

 1         #region 第一種:左左旋轉(單旋轉)
 2         /// <summary>
 3         /// 第一種:左左旋轉(單旋轉)
 4         /// </summary>
 5         /// <param name="node"></param>
 6         /// <returns></returns>
 7         public AVLNode<K, V> RotateLL(AVLNode<K, V> node)
 8         {
 9             //top:需要作為頂級節點的元素
10             var top = node.left;
11 
12             //先截斷當前節點的左孩子
13             node.left = top.right;
14 
15             //將當前節點作為temp的右孩子
16             top.right = node;
17 
18             //計算當前兩個節點的高度
19             node.height = Math.Max(Height(node.left), Height(node.right)) + 1;
20             top.height = Math.Max(Height(top.left), Height(top.right)) + 1;
21 
22             return top;
23         }
24         #endregion

 

② 右右情況(右子樹的右邊節點)

同樣,”節點5“滿足”右右情況“,其實我們也看到,這兩種情況是一種鏡像,當然操作方式也大同小異,我們在”節點1“的地方

將樹往下拉一位,最后也就形成了我們希望的平衡效果。

 1         #region 第二種:右右旋轉(單旋轉)
 2         /// <summary>
 3         /// 第二種:右右旋轉(單旋轉)
 4         /// </summary>
 5         /// <param name="node"></param>
 6         /// <returns></returns>
 7         public AVLNode<K, V> RotateRR(AVLNode<K, V> node)
 8         {
 9             //top:需要作為頂級節點的元素
10             var top = node.right;
11 
12             //先截斷當前節點的右孩子
13             node.right = top.left;
14 
15             //將當前節點作為temp的右孩子
16             top.left = node;
17 
18             //計算當前兩個節點的高度
19             node.height = Math.Max(Height(node.left), Height(node.right)) + 1;
20             top.height = Math.Max(Height(top.left), Height(top.right)) + 1;
21 
22             return top;
23         }
24         #endregion

 

③左右情況(左子樹的右邊節點)

從圖中我們可以看到,當我們插入”節點3“時,“節點5”處失衡,注意,找到”失衡點“是非常重要的,當面對”左右情況“時,我們將

失衡點的左子樹進行"右右情況旋轉",然后進行”左左情況旋轉“,經過這樣兩次的旋轉就OK了,很有意思,對吧。

 1         #region 第三種:左右旋轉(雙旋轉)
 2         /// <summary>
 3         /// 第三種:左右旋轉(雙旋轉)
 4         /// </summary>
 5         /// <param name="node"></param>
 6         /// <returns></returns>
 7         public AVLNode<K, V> RotateLR(AVLNode<K, V> node)
 8         {
 9             //先進行RR旋轉
10             node.left = RotateRR(node.left);
11 
12             //再進行LL旋轉
13             return RotateLL(node);
14         }
15         #endregion

 

④右左情況(右子樹的左邊節點)

這種情況和“情景3”也是一種鏡像關系,很簡單,我們找到了”節點15“是失衡點,然后我們將”節點15“的右子樹進行”左左情況旋轉“,

然后進行”右右情況旋轉“,最終得到了我們滿意的平衡。

 1         #region 第四種:右左旋轉(雙旋轉)
 2         /// <summary>
 3         /// 第四種:右左旋轉(雙旋轉)
 4         /// </summary>
 5         /// <param name="node"></param>
 6         /// <returns></returns>
 7         public AVLNode<K, V> RotateRL(AVLNode<K, V> node)
 8         {
 9             //執行左左旋轉
10             node.right = RotateLL(node.right);
11 
12             //再執行右右旋轉
13             return RotateRR(node);
14 
15         }
16         #endregion

 

3:添加

    如果我們理解了上面的這幾種旋轉,那么添加方法簡直是輕而易舉,出現了哪一種情況調用哪一種方法而已。

 1  #region 添加操作
 2         /// <summary>
 3         /// 添加操作
 4         /// </summary>
 5         /// <param name="key"></param>
 6         /// <param name="value"></param>
 7         /// <param name="tree"></param>
 8         /// <returns></returns>
 9         public AVLNode<K, V> Add(K key, V value, AVLNode<K, V> tree)
10         {
11             if (tree == null)
12                 tree = new AVLNode<K, V>(key, value, null, null);
13 
14             //左子樹
15             if (key.CompareTo(tree.key) < 0)
16             {
17                 tree.left = Add(key, value, tree.left);
18 
19                 //如果說相差等於2就說明這棵樹需要旋轉了
20                 if (Height(tree.left) - Height(tree.right) == 2)
21                 {
22                     //說明此時是左左旋轉
23                     if (key.CompareTo(tree.left.key) < 0)
24                     {
25                         tree = RotateLL(tree);
26                     }
27                     else
28                     {
29                         //屬於左右旋轉
30                         tree = RotateLR(tree);
31                     }
32                 }
33             }
34 
35             //右子樹
36             if (key.CompareTo(tree.key) > 0)
37             {
38                 tree.right = Add(key, value, tree.right);
39 
40                 if ((Height(tree.right) - Height(tree.left) == 2))
41                 {
42                     //此時是右右旋轉
43                     if (key.CompareTo(tree.right.key) > 0)
44                     {
45                         tree = RotateRR(tree);
46                     }
47                     else
48                     {
49                         //屬於右左旋轉
50                         tree = RotateRL(tree);
51                     }
52                 }
53             }
54 
55             //將value追加到附加值中(也可對應重復元素)
56             if (key.CompareTo(tree.key) == 0)
57                 tree.attach.Add(value);
58 
59             //計算高度
60             tree.height = Math.Max(Height(tree.left), Height(tree.right)) + 1;
61 
62             return tree;
63         }
64         #endregion

4:刪除

刪除方法跟添加方法也類似,當刪除一個結點的時候,可能會引起祖先結點的失衡,所以在每次”結點“回退的時候計算結點高度。

 1 #region 刪除當前樹中的節點
 2         /// <summary>
 3         /// 刪除當前樹中的節點
 4         /// </summary>
 5         /// <param name="key"></param>
 6         /// <param name="tree"></param>
 7         /// <returns></returns>
 8         public AVLNode<K, V> Remove(K key, V value, AVLNode<K, V> tree)
 9         {
10             if (tree == null)
11                 return null;
12 
13             //左子樹
14             if (key.CompareTo(tree.key) < 0)
15             {
16                 tree.left = Remove(key, value, tree.left);
17 
18                 //如果說相差等於2就說明這棵樹需要旋轉了
19                 if (Height(tree.left) - Height(tree.right) == 2)
20                 {
21                     //說明此時是左左旋轉
22                     if (key.CompareTo(tree.left.key) < 0)
23                     {
24                         tree = RotateLL(tree);
25                     }
26                     else
27                     {
28                         //屬於左右旋轉
29                         tree = RotateLR(tree);
30                     }
31                 }
32             }
33             //右子樹
34             if (key.CompareTo(tree.key) > 0)
35             {
36                 tree.right = Remove(key, value, tree.right);
37 
38                 if ((Height(tree.right) - Height(tree.left) == 2))
39                 {
40                     //此時是右右旋轉
41                     if (key.CompareTo(tree.right.key) > 0)
42                     {
43                         tree = RotateRR(tree);
44                     }
45                     else
46                     {
47                         //屬於右左旋轉
48                         tree = RotateRL(tree);
49                     }
50                 }
51             }
52             /*相等的情況*/
53             if (key.CompareTo(tree.key) == 0)
54             {
55                 //判斷里面的HashSet是否有多值
56                 if (tree.attach.Count > 1)
57                 {
58                     //實現惰性刪除
59                     tree.attach.Remove(value);
60                 }
61                 else
62                 {
63                     //有兩個孩子的情況
64                     if (tree.left != null && tree.right != null)
65                     {
66                         //根據平衡二叉樹的中順遍歷,需要找到”有子樹“的最小節點
67                         tree.key = FindMin(tree.right).key;
68 
69                         //刪除右子樹的指定元素
70                         tree.right = Remove(tree.key, value, tree.right);
71                     }
72                     else
73                     {
74                         //自減高度
75                         tree = tree.left == null ? tree.right : tree.left;
76 
77                         //如果刪除的是葉子節點直接返回
78                         if (tree == null)
79                             return null;
80                     }
81                 }
82             }
83 
84             //統計高度
85             tree.height = Math.Max(Height(tree.left), Height(tree.right)) + 1;
86 
87             return tree;
88         }
89         #endregion

5: 測試

不像上一篇不能在二叉樹中灌有序數據,平衡二叉樹就沒關系了,我們的需求是檢索2012-7-30 4:00:00 到 2012-7-30 5:00:00

的登陸用戶的ID,數據量在500w,看看平衡二叉樹是如何秒殺對手。

View Code
  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Threading;
  6 using System.IO;
  7 using System.Diagnostics;
  8 
  9 namespace DataStruct
 10 {
 11     class Program
 12     {
 13         static void Main(string[] args)
 14         {
 15             AVLTree<int, int> avl = new AVLTree<int, int>();
 16 
 17             Dictionary<DateTime, int> dic = new Dictionary<DateTime, int>();
 18 
 19             AVLTree<DateTime, int> tree = new AVLTree<DateTime, int>();
 20 
 21             //500w
 22             for (int i = 1; i < 5000000; i++)
 23             {
 24                 dic.Add(DateTime.Now.AddMinutes(i), i);
 25 
 26                 tree.Add(DateTime.Now.AddMinutes(i), i);
 27             }
 28 
 29             //檢索2012-7-30 4:00:00 到 2012-7-30 5:00:00的登陸人數
 30             var min = Convert.ToDateTime("2012/7/30 4:00:00");
 31 
 32             var max = Convert.ToDateTime("2012/7/30 5:00:00");
 33 
 34             var watch = Stopwatch.StartNew();
 35 
 36             var result1 = dic.Keys.Where(i => i >= min && i <= max).Select(i => dic[i]).ToList();
 37 
 38             watch.Stop();
 39 
 40             Console.WriteLine("字典查找耗費時間:{0}ms", watch.ElapsedMilliseconds);
 41 
 42             watch = Stopwatch.StartNew();
 43 
 44             var result2 = tree.SearchRange(min, max);
 45 
 46             watch.Stop();
 47 
 48             Console.WriteLine("平衡二叉樹查找耗費時間:{0}ms", watch.ElapsedMilliseconds);
 49         }
 50     }
 51 
 52     #region 平衡二叉樹節點
 53     /// <summary>
 54     /// 平衡二叉樹節點
 55     /// </summary>
 56     /// <typeparam name="K"></typeparam>
 57     /// <typeparam name="V"></typeparam>
 58     public class AVLNode<K, V>
 59     {
 60         /// <summary>
 61         /// 節點元素
 62         /// </summary>
 63         public K key;
 64 
 65         /// <summary>
 66         /// 增加一個高度信息
 67         /// </summary>
 68         public int height;
 69 
 70         /// <summary>
 71         /// 節點中的附加值
 72         /// </summary>
 73         public HashSet<V> attach = new HashSet<V>();
 74 
 75         /// <summary>
 76         /// 左節點
 77         /// </summary>
 78         public AVLNode<K, V> left;
 79 
 80         /// <summary>
 81         /// 右節點
 82         /// </summary>
 83         public AVLNode<K, V> right;
 84 
 85         public AVLNode() { }
 86 
 87         public AVLNode(K key, V value, AVLNode<K, V> left, AVLNode<K, V> right)
 88         {
 89             //KV鍵值對
 90             this.key = key;
 91             this.attach.Add(value);
 92 
 93             this.left = left;
 94             this.right = right;
 95         }
 96     }
 97     #endregion
 98 
 99     public class AVLTree<K, V> where K : IComparable
100     {
101         public AVLNode<K, V> node = null;
102 
103         #region 添加操作
104         /// <summary>
105         /// 添加操作
106         /// </summary>
107         /// <param name="key"></param>
108         /// <param name="value"></param>
109         public void Add(K key, V value)
110         {
111             node = Add(key, value, node);
112         }
113         #endregion
114 
115         #region 添加操作
116         /// <summary>
117         /// 添加操作
118         /// </summary>
119         /// <param name="key"></param>
120         /// <param name="value"></param>
121         /// <param name="tree"></param>
122         /// <returns></returns>
123         public AVLNode<K, V> Add(K key, V value, AVLNode<K, V> tree)
124         {
125             if (tree == null)
126                 tree = new AVLNode<K, V>(key, value, null, null);
127 
128             //左子樹
129             if (key.CompareTo(tree.key) < 0)
130             {
131                 tree.left = Add(key, value, tree.left);
132 
133                 //如果說相差等於2就說明這棵樹需要旋轉了
134                 if (Height(tree.left) - Height(tree.right) == 2)
135                 {
136                     //說明此時是左左旋轉
137                     if (key.CompareTo(tree.left.key) < 0)
138                     {
139                         tree = RotateLL(tree);
140                     }
141                     else
142                     {
143                         //屬於左右旋轉
144                         tree = RotateLR(tree);
145                     }
146                 }
147             }
148 
149             //右子樹
150             if (key.CompareTo(tree.key) > 0)
151             {
152                 tree.right = Add(key, value, tree.right);
153 
154                 if ((Height(tree.right) - Height(tree.left) == 2))
155                 {
156                     //此時是右右旋轉
157                     if (key.CompareTo(tree.right.key) > 0)
158                     {
159                         tree = RotateRR(tree);
160                     }
161                     else
162                     {
163                         //屬於右左旋轉
164                         tree = RotateRL(tree);
165                     }
166                 }
167             }
168 
169             //將value追加到附加值中(也可對應重復元素)
170             if (key.CompareTo(tree.key) == 0)
171                 tree.attach.Add(value);
172 
173             //計算高度
174             tree.height = Math.Max(Height(tree.left), Height(tree.right)) + 1;
175 
176             return tree;
177         }
178         #endregion
179 
180         #region 計算當前節點的高度
181         /// <summary>
182         /// 計算當前節點的高度
183         /// </summary>
184         /// <param name="node"></param>
185         /// <returns></returns>
186         public int Height(AVLNode<K, V> node)
187         {
188             return node == null ? -1 : node.height;
189         }
190         #endregion
191 
192         #region 第一種:左左旋轉(單旋轉)
193         /// <summary>
194         /// 第一種:左左旋轉(單旋轉)
195         /// </summary>
196         /// <param name="node"></param>
197         /// <returns></returns>
198         public AVLNode<K, V> RotateLL(AVLNode<K, V> node)
199         {
200             //top:需要作為頂級節點的元素
201             var top = node.left;
202 
203             //先截斷當前節點的左孩子
204             node.left = top.right;
205 
206             //將當前節點作為temp的右孩子
207             top.right = node;
208 
209             //計算當前兩個節點的高度
210             node.height = Math.Max(Height(node.left), Height(node.right)) + 1;
211             top.height = Math.Max(Height(top.left), Height(top.right)) + 1;
212 
213             return top;
214         }
215         #endregion
216 
217         #region 第二種:右右旋轉(單旋轉)
218         /// <summary>
219         /// 第二種:右右旋轉(單旋轉)
220         /// </summary>
221         /// <param name="node"></param>
222         /// <returns></returns>
223         public AVLNode<K, V> RotateRR(AVLNode<K, V> node)
224         {
225             //top:需要作為頂級節點的元素
226             var top = node.right;
227 
228             //先截斷當前節點的右孩子
229             node.right = top.left;
230 
231             //將當前節點作為temp的右孩子
232             top.left = node;
233 
234             //計算當前兩個節點的高度
235             node.height = Math.Max(Height(node.left), Height(node.right)) + 1;
236             top.height = Math.Max(Height(top.left), Height(top.right)) + 1;
237 
238             return top;
239         }
240         #endregion
241 
242         #region 第三種:左右旋轉(雙旋轉)
243         /// <summary>
244         /// 第三種:左右旋轉(雙旋轉)
245         /// </summary>
246         /// <param name="node"></param>
247         /// <returns></returns>
248         public AVLNode<K, V> RotateLR(AVLNode<K, V> node)
249         {
250             //先進行RR旋轉
251             node.left = RotateRR(node.left);
252 
253             //再進行LL旋轉
254             return RotateLL(node);
255         }
256         #endregion
257 
258         #region 第四種:右左旋轉(雙旋轉)
259         /// <summary>
260         /// 第四種:右左旋轉(雙旋轉)
261         /// </summary>
262         /// <param name="node"></param>
263         /// <returns></returns>
264         public AVLNode<K, V> RotateRL(AVLNode<K, V> node)
265         {
266             //執行左左旋轉
267             node.right = RotateLL(node.right);
268 
269             //再執行右右旋轉
270             return RotateRR(node);
271 
272         }
273         #endregion
274 
275         #region 是否包含指定元素
276         /// <summary>
277         /// 是否包含指定元素
278         /// </summary>
279         /// <param name="key"></param>
280         /// <returns></returns>
281         public bool Contain(K key)
282         {
283             return Contain(key, node);
284         }
285         #endregion
286 
287         #region 是否包含指定元素
288         /// <summary>
289         /// 是否包含指定元素
290         /// </summary>
291         /// <param name="key"></param>
292         /// <param name="tree"></param>
293         /// <returns></returns>
294         public bool Contain(K key, AVLNode<K, V> tree)
295         {
296             if (tree == null)
297                 return false;
298             //左子樹
299             if (key.CompareTo(tree.key) < 0)
300                 return Contain(key, tree.left);
301 
302             //右子樹
303             if (key.CompareTo(tree.key) > 0)
304                 return Contain(key, tree.right);
305 
306             return true;
307         }
308         #endregion
309 
310         #region 樹的指定范圍查找
311         /// <summary>
312         /// 樹的指定范圍查找
313         /// </summary>
314         /// <param name="min"></param>
315         /// <param name="max"></param>
316         /// <returns></returns>
317         public HashSet<V> SearchRange(K min, K max)
318         {
319             HashSet<V> hashSet = new HashSet<V>();
320 
321             hashSet = SearchRange(min, max, hashSet, node);
322 
323             return hashSet;
324         }
325         #endregion
326 
327         #region 樹的指定范圍查找
328         /// <summary>
329         /// 樹的指定范圍查找
330         /// </summary>
331         /// <param name="range1"></param>
332         /// <param name="range2"></param>
333         /// <param name="tree"></param>
334         /// <returns></returns>
335         public HashSet<V> SearchRange(K min, K max, HashSet<V> hashSet, AVLNode<K, V> tree)
336         {
337             if (tree == null)
338                 return hashSet;
339 
340             //遍歷左子樹(尋找下界)
341             if (min.CompareTo(tree.key) < 0)
342                 SearchRange(min, max, hashSet, tree.left);
343 
344             //當前節點是否在選定范圍內
345             if (min.CompareTo(tree.key) <= 0 && max.CompareTo(tree.key) >= 0)
346             {
347                 //等於這種情況
348                 foreach (var item in tree.attach)
349                     hashSet.Add(item);
350             }
351 
352             //遍歷右子樹(兩種情況:①:找min的下限 ②:必須在Max范圍之內)
353             if (min.CompareTo(tree.key) > 0 || max.CompareTo(tree.key) > 0)
354                 SearchRange(min, max, hashSet, tree.right);
355 
356             return hashSet;
357         }
358         #endregion
359 
360         #region 找到當前樹的最小節點
361         /// <summary>
362         /// 找到當前樹的最小節點
363         /// </summary>
364         /// <returns></returns>
365         public AVLNode<K, V> FindMin()
366         {
367             return FindMin(node);
368         }
369         #endregion
370 
371         #region 找到當前樹的最小節點
372         /// <summary>
373         /// 找到當前樹的最小節點
374         /// </summary>
375         /// <param name="tree"></param>
376         /// <returns></returns>
377         public AVLNode<K, V> FindMin(AVLNode<K, V> tree)
378         {
379             if (tree == null)
380                 return null;
381 
382             if (tree.left == null)
383                 return tree;
384 
385             return FindMin(tree.left);
386         }
387         #endregion
388 
389         #region 找到當前樹的最大節點
390         /// <summary>
391         /// 找到當前樹的最大節點
392         /// </summary>
393         /// <returns></returns>
394         public AVLNode<K, V> FindMax()
395         {
396             return FindMin(node);
397         }
398         #endregion
399 
400         #region 找到當前樹的最大節點
401         /// <summary>
402         /// 找到當前樹的最大節點
403         /// </summary>
404         /// <param name="tree"></param>
405         /// <returns></returns>
406         public AVLNode<K, V> FindMax(AVLNode<K, V> tree)
407         {
408             if (tree == null)
409                 return null;
410 
411             if (tree.right == null)
412                 return tree;
413 
414             return FindMax(tree.right);
415         }
416         #endregion
417 
418         #region 刪除當前樹中的節點
419         /// <summary>
420         /// 刪除當前樹中的節點
421         /// </summary>
422         /// <param name="key"></param>
423         /// <returns></returns>
424         public void Remove(K key, V value)
425         {
426             node = Remove(key, value, node);
427         }
428         #endregion
429 
430         #region 刪除當前樹中的節點
431         /// <summary>
432         /// 刪除當前樹中的節點
433         /// </summary>
434         /// <param name="key"></param>
435         /// <param name="tree"></param>
436         /// <returns></returns>
437         public AVLNode<K, V> Remove(K key, V value, AVLNode<K, V> tree)
438         {
439             if (tree == null)
440                 return null;
441 
442             //左子樹
443             if (key.CompareTo(tree.key) < 0)
444             {
445                 tree.left = Remove(key, value, tree.left);
446 
447                 //如果說相差等於2就說明這棵樹需要旋轉了
448                 if (Height(tree.left) - Height(tree.right) == 2)
449                 {
450                     //說明此時是左左旋轉
451                     if (key.CompareTo(tree.left.key) < 0)
452                     {
453                         tree = RotateLL(tree);
454                     }
455                     else
456                     {
457                         //屬於左右旋轉
458                         tree = RotateLR(tree);
459                     }
460                 }
461             }
462             //右子樹
463             if (key.CompareTo(tree.key) > 0)
464             {
465                 tree.right = Remove(key, value, tree.right);
466 
467                 if ((Height(tree.right) - Height(tree.left) == 2))
468                 {
469                     //此時是右右旋轉
470                     if (key.CompareTo(tree.right.key) > 0)
471                     {
472                         tree = RotateRR(tree);
473                     }
474                     else
475                     {
476                         //屬於右左旋轉
477                         tree = RotateRL(tree);
478                     }
479                 }
480             }
481             /*相等的情況*/
482             if (key.CompareTo(tree.key) == 0)
483             {
484                 //判斷里面的HashSet是否有多值
485                 if (tree.attach.Count > 1)
486                 {
487                     //實現惰性刪除
488                     tree.attach.Remove(value);
489                 }
490                 else
491                 {
492                     //有兩個孩子的情況
493                     if (tree.left != null && tree.right != null)
494                     {
495                         //根據平衡二叉樹的中順遍歷,需要找到”有子樹“的最小節點
496                         tree.key = FindMin(tree.right).key;
497 
498                         //刪除右子樹的指定元素
499                         tree.right = Remove(tree.key, value, tree.right);
500                     }
501                     else
502                     {
503                         //自減高度
504                         tree = tree.left == null ? tree.right : tree.left;
505 
506                         //如果刪除的是葉子節點直接返回
507                         if (tree == null)
508                             return null;
509                     }
510                 }
511             }
512 
513             //統計高度
514             tree.height = Math.Max(Height(tree.left), Height(tree.right)) + 1;
515 
516             return tree;
517         }
518         #endregion
519     }
520 }

wow,相差98倍,這個可不是一個級別啊...AVL神器。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM