接上一篇,繼續講二叉查找樹的操作,之前的博客都講得差不多了,本篇就講一下刪除操作,以及求最矮公共父結點(LCA:lowest common ancestor)的操作吧。
- 刪除
將一個結點從二叉查找樹中刪除之后,剩下的結點可能會不滿足二叉查找樹的性質,因此,在刪除結點之后要對樹進行調整,使其滿足二叉查找樹的性質。根據結點的孩子的數量,將刪除操作分為三種情況,我們記要刪除的結點為z,實際上刪除的結點為y。
1. z結點沒有孩子。
如下圖a所示,我們要刪除值為13的結點,因為結點沒有孩子,所以刪除之后不會影響到二叉樹的整體性質,也就是說,直接將13這個結點刪除即可,如圖a所示,從左邊的二叉樹刪除13這個點之后變到右邊的二叉樹。
2. z結點有一個孩子。
如下圖b所示,要刪除的值為16的結點有一個孩子,而且是右孩子,那么從圖上來看,如果,我們將16去掉,然后把以20為結點的子樹作為15的右子樹,那么整棵樹還是符合二叉查找樹的性質的,因此,有一個孩子的結點的刪除操作,就是要將其孩子作為其父結點的孩子即可。如圖b所示。
3. z結點有兩個孩子。
如下圖c所示,要刪除的值為5的結點,有兩個孩子,刪除之后肯定整棵樹就不符合二叉查找樹的性質了,因此要進行調整,我們發現,將5的后繼,值為6的結點來放到5的位置,然后將6的孩子7作為6的父結點10的孩子,如下圖c所示,我們要刪除的是z結點,而我們實際要刪除y結點,並替換z結點。這里需要注意的一點是,如果一個結點有右孩子,則該結點的后繼,至多有一個子女,而且是右孩子。因為假如該結點的后繼有左孩子和右孩子,那么其左孩子的值肯定是介於該結點和其后繼之間的,那么按照二叉查找樹的性質,這個左孩子就應該是該結點的后繼,所以,這與原先的后繼相互矛盾,因此,結論成立。
好了,分析完了刪除的三種情況,我們來完成我們的程序吧。
1 /** 2 * 刪除二叉查找樹中的結點z 3 * @author Alfred 4 * @param z 要刪除的結點 5 * @return 刪除或者替換的結點 6 */ 7 public TreeNode treeDelete(TreeNode z){ 8 TreeNode x = null, y = null; 9 if(z.getLeft() == null || z.getRight() == null){ 10 //對應第1和第2種情況 11 y = z; 12 }else{ 13 //對應第3種情況 14 y = treeSuccessor(z); 15 } 16 //將x置為y的非null子女,或者當y無子女時置為null 17 if(y.getLeft() != null){ 18 x = y.getLeft(); 19 }else{ 20 x = y.getRight(); 21 } 22 //通過修改x和y的父結點的引用,將y刪除 23 if(x != null){ 24 x.setParent(y.getParent()); 25 } 26 if(y.getParent() == null){ 27 //x成為樹根 28 rootNode = x; 29 }else if(y == y.getParent().getLeft()){ 30 //y是其父結點的左孩子 31 y.getParent().setLeft(x); 32 }else{ 33 //y是其父結點的右孩子 34 y.getParent().setRight(x); 35 } 36 //如果y和z不是同一個結點,說明是第3種情況 37 if(y != z){ 38 //內容替換 39 z.setKey(y.getKey()); 40 z.setDataNum(y.getDataNum()); 41 } 42 return y; 43 }
上面的程序完整的搞定了上面分析的三種情況。
- LCA
LCA問題對於二叉查找樹來說是非常簡單的。因為二叉查找樹滿足其特有的性質。給定樹中的兩個結點x和y,求其最低公共父結點。我們把這個算法分為三種情況。對於一棵二叉查找樹來說:
1. 如果x和y分別位於某結點z的左右子樹上,那么結點z就是x和y的lca。
2. 如果x和y位於某結點z的左子樹或者右子樹上,那么x和y的lca也必然位於其所處的左子樹或者右子樹上。
3. 如果x或者y中,有一個結點是另外一個結點的父結點,那么lca就是它們中的父結點。即如果有一個點和某結點重合,則重合的點就是lca。
那么,我們就從根結點開始,按照從上往下的順序查找lca吧,比較根結點與兩結點的關系,然后再進行下一步的操作。代碼如下:
1 /** 2 * 求兩個結點的最低公共父結點 3 * @author Alfred 4 * @param x 結點 5 * @param y 結點 6 * @return 最低公共父結點 7 */ 8 public TreeNode lca(TreeNode x, TreeNode y){ 9 TreeNode tmpNode = rootNode; 10 //獲取兩個key值 11 int xKey = x.getKey(); 12 int yKey = y.getKey(); 13 //給兩個元素按從小到大排下序,使得x<y 14 if(xKey > yKey){ 15 int tmpKey = xKey; 16 xKey = yKey; 17 yKey = tmpKey; 18 } 19 while(true){ 20 if(tmpNode.getKey() < xKey){ 21 //這種情況下,lca在其右子樹上 22 tmpNode = tmpNode.getRight(); 23 }else if(tmpNode.getKey() > yKey){ 24 //這種情況下,lca在其左子樹上 25 tmpNode = tmpNode.getLeft(); 26 }else{ 27 return tmpNode; 28 } 29 } 30 }
代碼比較簡單,就是按照上面的三種情況按照從上到下的順序來分類處理的。其他還有一些lca算法,如離線算法(Tarjan)和在線算法(RMQ)等,暫時先不討論了,以后有時間了再補上吧。為了方便想學習的童鞋來測試,我把整個代碼就貼到下面了(木有找到更好地方法來分享。。)。

1 package com.alfred.bstree; 2 3 /** 4 * 二叉查找樹結點 5 * @author Alfred 6 */ 7 public class TreeNode { 8 //key值 9 private int key; 10 //記錄相同的key值的結點個數 11 private int dataNum; 12 //下面三個大家都懂得! 13 private TreeNode parent; 14 private TreeNode left; 15 private TreeNode right; 16 public TreeNode(int key){ 17 this.key = key; 18 this.dataNum = 1; 19 } 20 public String toString(){ 21 return ""+key+"*"+dataNum+" "; 22 } 23 /** 24 * 偷個懶...自加方法 25 * @author Alfred 26 */ 27 public void incNumByOne(){ 28 this.dataNum++; 29 } 30 31 /** 32 * @return the key 33 */ 34 public int getKey() { 35 return key; 36 } 37 /** 38 * @param key the key to set 39 */ 40 public void setKey(int key) { 41 this.key = key; 42 } 43 /** 44 * @return the dataNum 45 */ 46 public int getDataNum() { 47 return dataNum; 48 } 49 /** 50 * @param dataNum the dataNum to set 51 */ 52 public void setDataNum(int dataNum) { 53 this.dataNum = dataNum; 54 } 55 /** 56 * @return the parent 57 */ 58 public TreeNode getParent() { 59 return parent; 60 } 61 /** 62 * @param parent the parent to set 63 */ 64 public void setParent(TreeNode parent) { 65 this.parent = parent; 66 } 67 /** 68 * @return the left 69 */ 70 public TreeNode getLeft() { 71 return left; 72 } 73 /** 74 * @param left the left to set 75 */ 76 public void setLeft(TreeNode left) { 77 this.left = left; 78 } 79 /** 80 * @return the right 81 */ 82 public TreeNode getRight() { 83 return right; 84 } 85 /** 86 * @param right the right to set 87 */ 88 public void setRight(TreeNode right) { 89 this.right = right; 90 } 91 }

1 package com.alfred.bstree; 2 3 import java.util.LinkedList; 4 import java.util.List; 5 import java.util.Queue; 6 import java.util.Random; 7 import java.util.Stack; 8 9 /** 10 * 二叉查找樹 11 * @author Alfred 12 */ 13 public class BSTree { 14 //隨機化的構造二叉查找樹 15 private Random rand = null; 16 //根結點 17 private TreeNode rootNode = null; 18 19 /** 20 * 以int數組A來創建二叉查找樹 21 * @param A int數組 22 */ 23 public BSTree(int[] A){ 24 rand = new Random(); 25 createBSTree(A); 26 } 27 28 /** 29 * 創建二叉查找樹 30 * @param A int數組 31 */ 32 private void createBSTree(int[] A){ 33 //先構建一個存儲數組下標的List 34 List<Integer> index = new LinkedList<Integer>(); 35 int i = 0; 36 for(i = 0; i < A.length; i++){ 37 index.add(i); 38 } 39 //隨機構造二叉樹 40 for(i = 0; i < A.length; i++){ 41 int j = 0; 42 if(index.size() > 1){ 43 //隨機產生一個數組下標值 44 j = rand.nextInt(index.size() - 1); 45 } 46 //插入二叉樹 47 TreeInsert(A[index.get(j)]); 48 //移除下標 49 index.remove(j); 50 } 51 } 52 53 /** 54 * 插入一個整數 55 * @param z 整數 56 */ 57 public void TreeInsert(int z){ 58 TreeNode parentNode = null; 59 TreeNode searchNode = rootNode; 60 TreeNode insertNode = new TreeNode(z); 61 //while循環找到要插入的點的父結點 62 while(searchNode != null){ 63 parentNode = searchNode; 64 if(insertNode.getKey() < searchNode.getKey()){ 65 searchNode = searchNode.getLeft(); 66 }else if(insertNode.getKey() == searchNode.getKey()){ 67 //如果是key值相同的話,直接插入,偷懶在這里... 68 searchNode.incNumByOne(); 69 return; 70 }else{ 71 searchNode = searchNode.getRight(); 72 } 73 } 74 75 insertNode.setParent(parentNode); 76 if(parentNode == null){ 77 rootNode = insertNode; 78 }else if(insertNode.getKey() < parentNode.getKey()){ 79 //插入左結點 80 parentNode.setLeft(insertNode); 81 }else if(insertNode.getKey() == parentNode.getKey()){ 82 //因為上面插入了,所以這里就不會執行了。 83 parentNode.incNumByOne(); 84 System.out.println("this is not supposed to be executed."); 85 }else{ 86 //插入右結點 87 parentNode.setRight(insertNode); 88 } 89 } 90 91 /** 92 * 遞歸前序遍歷以x為根的二叉樹 93 * @author Alfred 94 * @param x 根結點 95 */ 96 public void preOrderTreeWalk(TreeNode x){ 97 if(x != null){ 98 System.out.print(x);//訪問形式為打印輸出一下 99 preOrderTreeWalk(x.getLeft()); 100 preOrderTreeWalk(x.getRight()); 101 } 102 } 103 104 public void preOrderTreeWalk(){ 105 preOrderTreeWalk(rootNode); 106 } 107 108 /** 109 * 非遞歸前序遍歷以x為根結點的二叉樹 110 * @author Alfred 111 * @param x 根結點 112 */ 113 public void preOrderTreeWalkNonrecursive1(TreeNode x){ 114 //借助棧來實現。 115 Stack<TreeNode> stack = new Stack<TreeNode>(); 116 while(x != null || !stack.empty()){ 117 if(x != null){ 118 System.out.print(x);//遍歷輸出 119 stack.push(x);//壓棧 120 x = x.getLeft(); 121 }else{ 122 x = stack.pop();//出棧 123 x = x.getRight(); 124 } 125 } 126 } 127 128 /** 129 * 非遞歸前序遍歷以x為根結點的二叉樹 130 * @author Alfred 131 * @param x 根結點 132 */ 133 public void preOrderTreeWalkNonrecursive2(TreeNode x){ 134 Stack<TreeNode> stack = new Stack<TreeNode>(); 135 if(x != null){ 136 stack.push(x); 137 while(!stack.empty()){ 138 TreeNode tmpNode = stack.pop(); 139 System.out.print(tmpNode);//遍歷輸出 140 if(tmpNode.getRight() != null){ 141 stack.push(tmpNode.getRight()); 142 } 143 if(tmpNode.getLeft() != null){ 144 stack.push(tmpNode.getLeft()); 145 } 146 } 147 } 148 } 149 150 public void preOrderTreeWalkNonrecursive(){ 151 System.out.println("方法1:"); 152 preOrderTreeWalkNonrecursive1(rootNode); 153 System.out.println("\n方法2:"); 154 preOrderTreeWalkNonrecursive2(rootNode); 155 } 156 157 /** 158 * 遞歸中序遍歷以x為根的二叉樹 159 * @author Alfred 160 * @param x 根結點 161 */ 162 public void inOrderTreeWalk(TreeNode x){ 163 if(x != null){ 164 inOrderTreeWalk(x.getLeft()); 165 System.out.print(x); 166 inOrderTreeWalk(x.getRight()); 167 } 168 } 169 170 public void inOrderTreeWalk(){ 171 inOrderTreeWalk(rootNode); 172 } 173 174 /** 175 * 非遞歸中序遍歷以x為根結點的二叉樹 176 * @author Alfred 177 * @param x 根結點 178 */ 179 public void inOrderTreeWalkNonrecursive(TreeNode x){ 180 Stack<TreeNode> stack = new Stack<TreeNode>(); 181 while(x != null || !stack.empty()){ 182 if(x != null){ 183 stack.push(x); 184 x = x.getLeft(); 185 }else{ 186 x = stack.pop(); 187 System.out.print(x);//遍歷輸出 188 x = x.getRight(); 189 } 190 } 191 } 192 193 public void inOrderTreeWalkNonrecursive(){ 194 inOrderTreeWalkNonrecursive(rootNode); 195 } 196 197 /** 198 * 遞歸后序遍歷以x為根的二叉樹 199 * @author Alfred 200 * @param x 根結點 201 */ 202 public void postOrderTreeWalk(TreeNode x){ 203 if(x != null){ 204 postOrderTreeWalk(x.getLeft()); 205 postOrderTreeWalk(x.getRight()); 206 System.out.print(x); 207 } 208 } 209 210 public void postOrderTreeWalk(){ 211 postOrderTreeWalk(rootNode); 212 } 213 /** 214 * 非遞歸后序遍歷以x為根結點的二叉樹 215 * @author Alfred 216 * @param x 根結點 217 */ 218 public void postOrderTreeWalkNonrecursive1(TreeNode x){ 219 Stack<TreeNode> stack = new Stack<TreeNode>(); 220 TreeNode prev = null; 221 TreeNode curr = null; 222 if(x != null){ 223 stack.push(x); 224 } 225 while(!stack.empty()){ 226 curr = stack.peek(); 227 if(prev == null || prev.getLeft() == curr || prev.getRight() == curr){ 228 if(curr.getLeft() != null){ 229 stack.push(curr.getLeft());//壓左孩子 230 }else if(curr.getRight() != null){ 231 stack.push(curr.getRight());//壓右孩子 232 } 233 }else if(curr.getLeft() == prev){ 234 if(curr.getRight() != null){ 235 stack.push(curr.getRight());//壓右孩子 236 } 237 }else{ 238 System.out.print(curr);//遍歷輸出 239 stack.pop(); 240 } 241 prev = curr; 242 } 243 } 244 245 /** 246 * 非遞歸后序遍歷以x為根結點的二叉樹 247 * @author Alfred 248 * @param x 根結點 249 */ 250 public void postOrderTreeWalkNonrecursive2(TreeNode x){ 251 Stack<TreeNode> stack = new Stack<TreeNode>(); 252 Stack<TreeNode> output = new Stack<TreeNode>(); 253 TreeNode curr = null; 254 if(x != null){ 255 stack.push(x); 256 } 257 while(!stack.empty()){ 258 curr = stack.pop(); 259 output.push(curr);//存放到輸出地棧里面 260 if(curr.getLeft() != null){ 261 stack.push(curr.getLeft());//壓左孩子 262 } 263 if(curr.getRight() != null){ 264 stack.push(curr.getRight());//壓右孩子 265 } 266 } 267 while(!output.empty()){ 268 TreeNode tmpNode = output.pop(); 269 System.out.print(tmpNode);//打印輸出 270 } 271 } 272 273 public void postOrderTreeWalkNonrecursive(){ 274 System.out.println("方法1:"); 275 postOrderTreeWalkNonrecursive1(rootNode); 276 System.out.println("\n方法2:"); 277 postOrderTreeWalkNonrecursive2(rootNode); 278 } 279 /** 280 * 層序遍歷二叉樹 281 * @author Alfred 282 * @param x 根結點 283 */ 284 public void levelOrderTreeWalk(TreeNode x){ 285 Queue<TreeNode> queue = new LinkedList<TreeNode>(); 286 TreeNode tmpNode = null; 287 if(x != null){ 288 queue.offer(x); 289 } 290 while(!queue.isEmpty()){ 291 tmpNode = queue.poll(); 292 System.out.print(tmpNode);//打印輸出 293 if(tmpNode.getLeft() != null){ 294 queue.offer(tmpNode.getLeft());//左孩子入隊 295 } 296 if(tmpNode.getRight() != null){ 297 queue.offer(tmpNode.getRight());//右孩子入隊 298 } 299 } 300 } 301 public void levelOrderTreeWalk(){ 302 levelOrderTreeWalk(rootNode); 303 } 304 305 306 /** 307 * 查找以x為根結點的樹中key的值為k的結點,返回找到的結點或者null 308 * @author Alfred 309 * @param x 根結點 310 * @param k 要查找的整數 311 * @return 找到的結點或者null 312 */ 313 private TreeNode treeSearch(TreeNode x, int k){ 314 // System.out.println("treeSearch:"+x); 315 if(x == null || k == x.getKey()){ 316 return x; 317 } 318 if(k < x.getKey()){ 319 return treeSearch(x.getLeft(), k);//查左子樹 320 }else{ 321 return treeSearch(x.getRight(), k);//查右子樹 322 } 323 } 324 /** 325 * 非遞歸地查找以x為根結點的樹中key的值為k的結點,返回找到的結點或者null 326 * @author Alfred 327 * @param x 根結點 328 * @param k 要查找的整數 329 * @return 找到的結點或者null 330 */ 331 private TreeNode treeSearchNonrecursive(TreeNode x, int k){ 332 while(x != null && k != x.getKey()){ 333 if(k < x.getKey()){ 334 x = x.getLeft(); 335 }else{ 336 x = x.getRight(); 337 } 338 } 339 return x; 340 } 341 342 public TreeNode treeSearch(int k){ 343 return treeSearch(rootNode, k); 344 } 345 public TreeNode treeSearchNonrecursive(int k){ 346 return treeSearchNonrecursive(rootNode, k); 347 } 348 /** 349 * 找以x為根結點的二叉查找樹中的最小值 350 * @author Alfred 351 * @param x 根結點 352 * @return 最小值結點或者null 353 */ 354 public TreeNode treeMin(TreeNode x){ 355 while(x.getLeft() != null){ 356 x = x.getLeft(); 357 } 358 return x; 359 } 360 361 public TreeNode treeMin(){ 362 return treeMin(rootNode); 363 } 364 /** 365 * 找以x為根結點的二叉查找樹中的最大值 366 * @author Alfred 367 * @param x 根結點 368 * @return 最大值結點或者null 369 */ 370 public TreeNode treeMax(TreeNode x){ 371 while(x.getRight() != null){ 372 x = x.getRight(); 373 } 374 return x; 375 } 376 377 public TreeNode treeMax(){ 378 return treeMax(rootNode); 379 } 380 /** 381 * 找結點x的后繼結點 382 * @author Alfred 383 * @param x 結點 384 * @return x的后繼結點或者null 385 */ 386 public TreeNode treeSuccessor(TreeNode x){ 387 //第一種情況 388 if(x.getRight() != null){ 389 return treeMin(x.getRight()); 390 } 391 //第二種情況 392 TreeNode tmpNode = x.getParent(); 393 while(tmpNode != null && x == tmpNode.getRight()){ 394 x = tmpNode; 395 tmpNode = tmpNode.getParent(); 396 } 397 return tmpNode; 398 } 399 400 /** 401 * 找結點x的前趨結點 402 * @author Alfred 403 * @param x 結點 404 * @return x的前趨結點或者null 405 */ 406 public TreeNode treePredecessor(TreeNode x){ 407 //第一種情況 408 if(x.getLeft() != null){ 409 return treeMax(x.getLeft()); 410 } 411 //第二種情況 412 TreeNode tmpNode = x.getParent(); 413 while(tmpNode != null && x == tmpNode.getLeft()){ 414 x = tmpNode; 415 tmpNode = tmpNode.getParent(); 416 } 417 return tmpNode; 418 } 419 420 /** 421 * 刪除二叉查找樹中的結點z 422 * @author Alfred 423 * @param z 要刪除的結點 424 * @return 刪除或者替換的結點 425 */ 426 public TreeNode treeDelete(TreeNode z){ 427 TreeNode x = null, y = null; 428 if(z.getLeft() == null || z.getRight() == null){ 429 //對應第1和第2種情況 430 y = z; 431 }else{ 432 //對應第3種情況 433 y = treeSuccessor(z); 434 } 435 //將x置為y的非null子女,或者當y無子女時置為null 436 if(y.getLeft() != null){ 437 x = y.getLeft(); 438 }else{ 439 x = y.getRight(); 440 } 441 //通過修改x和y的父結點的引用,將y刪除 442 if(x != null){ 443 x.setParent(y.getParent()); 444 } 445 if(y.getParent() == null){ 446 //x成為樹根 447 rootNode = x; 448 }else if(y == y.getParent().getLeft()){ 449 //y是其父結點的左孩子 450 y.getParent().setLeft(x); 451 }else{ 452 //y是其父結點的右孩子 453 y.getParent().setRight(x); 454 } 455 //如果y和z不是同一個結點,說明是第3種情況 456 if(y != z){ 457 //內容替換 458 z.setKey(y.getKey()); 459 z.setDataNum(y.getDataNum()); 460 } 461 return y; 462 } 463 464 /** 465 * 求兩個結點的最低公共父結點 466 * @author Alfred 467 * @param x 結點 468 * @param y 結點 469 * @return 最低公共父結點 470 */ 471 public TreeNode lca(TreeNode x, TreeNode y){ 472 TreeNode tmpNode = rootNode; 473 //獲取兩個key值 474 int xKey = x.getKey(); 475 int yKey = y.getKey(); 476 //給兩個元素按從小到大排下序,使得x<y 477 if(xKey > yKey){ 478 int tmpKey = xKey; 479 xKey = yKey; 480 yKey = tmpKey; 481 } 482 while(true){ 483 if(tmpNode.getKey() < xKey){ 484 //這種情況下,lca在其右子樹上 485 tmpNode = tmpNode.getRight(); 486 }else if(tmpNode.getKey() > yKey){ 487 //這種情況下,lca在其左子樹上 488 tmpNode = tmpNode.getLeft(); 489 }else{ 490 return tmpNode; 491 } 492 } 493 } 494 }

1 package com.alfred.bstree; 2 3 public class testMain { 4 5 public static void main(String[] args) { 6 int[] A = new int[]{15,6,18,3,7,17,20,2,4,13,9,3,18,8,8,8,8,8}; 7 BSTree bsTree = new BSTree(A); 8 System.out.println("前序遍歷遞歸方法:"); 9 bsTree.preOrderTreeWalk(); 10 System.out.println("\n前序遍歷非遞歸方法:"); 11 bsTree.preOrderTreeWalkNonrecursive(); 12 System.out.println("\n中序遍歷遞歸方法:"); 13 bsTree.inOrderTreeWalk(); 14 System.out.println("\n中序遍歷非遞歸方法:"); 15 bsTree.inOrderTreeWalkNonrecursive(); 16 System.out.println("\n后序遍歷遞歸方法:"); 17 bsTree.postOrderTreeWalk(); 18 System.out.println("\n后序遍歷非遞歸方法:"); 19 bsTree.postOrderTreeWalkNonrecursive(); 20 System.out.println("\n層序遍歷方法:"); 21 bsTree.levelOrderTreeWalk(); 22 23 System.out.println("\n遞歸查找:"); 24 System.out.println(bsTree.treeSearch(8)); 25 System.out.println("非遞歸查找:"); 26 System.out.println(bsTree.treeSearchNonrecursive(8)); 27 28 System.out.println("\n最大值:"); 29 System.out.println(bsTree.treeMax()); 30 System.out.println("最小值:"); 31 System.out.println(bsTree.treeMin()); 32 System.out.println("8的后繼:"); 33 System.out.println(bsTree.treeSuccessor(bsTree.treeSearch(8))); 34 System.out.println("8的前驅:"); 35 System.out.println(bsTree.treePredecessor(bsTree.treeSearch(8))); 36 System.out.println("\n最大最小值的LCA:"); 37 System.out.println(bsTree.lca(bsTree.treeMin(), bsTree.treeMax())); 38 39 System.out.println("刪除8之后:"); 40 TreeNode eight = bsTree.treeSearch(8); 41 bsTree.inOrderTreeWalk(); 42 System.out.println(); 43 bsTree.treeDelete(eight); 44 bsTree.inOrderTreeWalk(); 45 } 46 }
ps:關於二叉查找樹的一些操作先寫到這里吧,有不對的地方,請廣大博友指正啊。
pss:畫圖好累啊。。轉載請注明。。。