上一篇我們聊過,二叉查找樹不是嚴格的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神器。
