日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

一步一图一代码之排序二叉树

發(fā)布時(shí)間:2025/7/14 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一步一图一代码之排序二叉树 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

作者:禪樓望月(http://www.cnblogs.com/yaoyinglong/)

屬性:

①若它的左子樹不為空,則左子樹上所有節(jié)點(diǎn)的值均小于它的根節(jié)點(diǎn)的值。

②若它的右子樹不為空,則右子樹上所有節(jié)點(diǎn)的值均大于它的根節(jié)點(diǎn)的值。

③它的左、右子樹也都是排序二叉樹。

添加操作:

當(dāng)根節(jié)點(diǎn)為空時(shí),添加進(jìn)的節(jié)點(diǎn)作為根節(jié)點(diǎn)。然后每次添加節(jié)點(diǎn)時(shí),都從根節(jié)點(diǎn)過(guò)濾,以根節(jié)點(diǎn)作為當(dāng)前節(jié)點(diǎn),如果新節(jié)點(diǎn)大于當(dāng)前節(jié)點(diǎn),則走當(dāng)前節(jié)點(diǎn)的右子節(jié)點(diǎn)分支,如果新節(jié)點(diǎn)小于當(dāng)前節(jié)點(diǎn),則走當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)分支。然后再用右子節(jié)點(diǎn)或左子節(jié)點(diǎn)作為當(dāng)前節(jié)點(diǎn)與新加節(jié)點(diǎn)比較,如果新加節(jié)點(diǎn)大,則當(dāng)前節(jié)點(diǎn)的右子節(jié)點(diǎn),如果新加節(jié)點(diǎn)小,則當(dāng)前節(jié)點(diǎn)的左子節(jié)點(diǎn)。依次類推直到左子樹或右子樹為null時(shí),將該新節(jié)點(diǎn)添加在這里。

圖解:

代碼解析:

1 public void add(T data){ 2 Node newNode=new Node(data); 3 if(root==null){ 4 root=newNode; 5 }else { 6 add(newNode, root); 7 } 8 } 9 public void add(Node addNode,Node parentNode) { 10 T data=addNode.data; 11 Node currentNode=parentNode; 12 Node parent=null; 13 int flag=0; 14 while(currentNode!=null){ 15 parent=currentNode; 16 flag=data.compareTo(currentNode.data); 17 if(flag>0){ 18 currentNode=currentNode.rightChild; 19 }else { 20 currentNode=currentNode.leftChild; 21 } 22 } 23 if(flag>0){ 24 parent.rightChild=addNode; 25 }else { 26 parent.leftChild=addNode; 27 } 28 addNode.parent=parent; 29 } View Code

添加操作相對(duì)簡(jiǎn)單,麻煩的是刪除操作。

刪除操作

該操作有很多的情況:

????? 第一:待刪除的節(jié)點(diǎn)是葉子節(jié)點(diǎn)

????? 第二:待刪除的節(jié)點(diǎn)有左子樹沒有右子樹

????? 第三:待刪除的節(jié)點(diǎn)沒有左子樹有右子樹

????? 第四:待刪除的節(jié)點(diǎn)既沒有左子樹也沒有右子樹。

圖解

在第一大類中我們還可分:

1、該葉子節(jié)點(diǎn)就是根節(jié)點(diǎn),即樹中只有一個(gè)根節(jié)點(diǎn)。

這是最簡(jiǎn)單的情況,直接樹的根root指向null即可。

2、否則便要判斷該葉子節(jié)點(diǎn)是其父節(jié)點(diǎn)的左子節(jié)點(diǎn)呢還是其父節(jié)點(diǎn)的右子節(jié)點(diǎn)

下圖為葉子節(jié)點(diǎn)是其父節(jié)點(diǎn)的左子節(jié)點(diǎn),右子節(jié)點(diǎn)一樣。

在第二大類中我們還可以細(xì)分:

1、待刪除的節(jié)點(diǎn)就是根節(jié)點(diǎn)。

只需將根節(jié)點(diǎn)的左子節(jié)點(diǎn)(因?yàn)檫@是根節(jié)點(diǎn)只有左子節(jié)點(diǎn))指向父節(jié)點(diǎn)的指針打斷,并將該左子節(jié)點(diǎn)設(shè)為根節(jié)點(diǎn)即可。

2、如果待刪除的節(jié)點(diǎn)不是根節(jié)點(diǎn),那就必須討論待刪除的節(jié)點(diǎn)是其父節(jié)點(diǎn)的左子節(jié)點(diǎn)還是右子節(jié)點(diǎn)。

以是其父節(jié)點(diǎn)的左子節(jié)點(diǎn)為例(右子節(jié)點(diǎn)的情況一樣),我們需要讓待刪除節(jié)點(diǎn)的父節(jié)點(diǎn)的指向其左孩子的指針重新指向待刪除節(jié)點(diǎn)的左孩子,讓待刪除節(jié)點(diǎn)的左孩子的指向父節(jié)點(diǎn)的指針重新指向待刪除節(jié)點(diǎn)的父節(jié)點(diǎn)。

這期間,我們并沒有打斷圖中節(jié)點(diǎn)5指向其左孩子節(jié)點(diǎn)3的指針,也沒有打斷節(jié)點(diǎn)5指向其父節(jié)點(diǎn)6的指針。這是因?yàn)?#xff0c;沒這個(gè)必要。我們不打斷這些節(jié)點(diǎn)5永遠(yuǎn)也不會(huì)被訪問(wèn)到,而且會(huì)被垃圾回收。

第三大類和第二大類一樣。

第四大類

總的思想就是:找到待刪除節(jié)點(diǎn)左子樹中的最大節(jié)點(diǎn)(leftMaxNode),然后用leftMaxNode替代待刪除的節(jié)點(diǎn)即可。這句話看似簡(jiǎn)單,但是實(shí)現(xiàn)起來(lái)可不是那么的容易!!!

我們也可以細(xì)分:

1、待刪除節(jié)點(diǎn)就是根節(jié)點(diǎn)

???? 1.1 leftMaxNode就是待刪除節(jié)點(diǎn)的左孩子。即待刪除節(jié)點(diǎn)左子樹中沒有右節(jié)點(diǎn)。

???? 1.2 如果待刪除的節(jié)點(diǎn)不是根節(jié)點(diǎn)

對(duì)于這種情況,我們需要顯示顯示打斷的“指針”只有兩個(gè):如下圖中,節(jié)點(diǎn)3指向其右子節(jié)點(diǎn)4(leftMaxNode)的指針,即節(jié)點(diǎn)4(leftMaxNode)指向其父節(jié)點(diǎn)3的指針。然后用節(jié)點(diǎn)4(leftMaxNode)替換節(jié)點(diǎn)5(根節(jié)點(diǎn))即可。

2、待刪除的節(jié)點(diǎn)不是根節(jié)點(diǎn)

???? 2.1 被刪除節(jié)點(diǎn)的左子樹中最大節(jié)點(diǎn)不是其左子節(jié)點(diǎn)

如下圖所示:

在這種情況下使用節(jié)點(diǎn)節(jié)點(diǎn)4替換節(jié)點(diǎn)5的時(shí)候,對(duì)于節(jié)點(diǎn)4和節(jié)點(diǎn)8、節(jié)點(diǎn)9的之間的“指針”創(chuàng)建比較容易,但是節(jié)點(diǎn)3與節(jié)點(diǎn)4之間的“指針”卻不好創(chuàng)建,因?yàn)楣?jié)點(diǎn)4的左子樹可能很復(fù)雜,我們不知道將節(jié)點(diǎn)3插入哪里合適,所以,解決辦法為,將節(jié)點(diǎn)3利用排序二叉樹添加新節(jié)點(diǎn)的功能以新節(jié)點(diǎn)的形式加入節(jié)點(diǎn)4 中。

???? 2.2 被刪除節(jié)點(diǎn)的左子樹中最大節(jié)點(diǎn)就是是其左子節(jié)點(diǎn)

即,如下情況,

這種情況很簡(jiǎn)單了,就不詳細(xì)說(shuō)明了。

完整代碼

1 package com.yyl.tree; 2 3 import java.util.ArrayDeque; 4 import java.util.ArrayList; 5 import java.util.List; 6 import java.util.Queue; 7 8 public class SortedBinaryTree<T extends Comparable<T>> { 9 public class Node{ 10 T data=null; 11 Node parent=null; 12 public Node getParent() { 13 return parent; 14 } 15 public void setParent(Node parent) { 16 this.parent = parent; 17 } 18 19 Node leftChild=null; 20 Node rightChild=null; 21 //region【訪問(wèn)器】 22 public T getData() { 23 return data; 24 } 25 public void setData(T data) { 26 this.data = data; 27 } 28 public Node getLeftChild() { 29 return leftChild; 30 } 31 public void setLeftChild(Node leftChild) { 32 this.leftChild = leftChild; 33 } 34 public Node getRightChild() { 35 return rightChild; 36 } 37 public void setRightChild(Node rightChild) { 38 this.rightChild = rightChild; 39 } 40 //endregion 41 42 // region 【構(gòu)造器】 43 public Node(){} 44 public Node(T data){ 45 this.data=data; 46 } 47 public Node(T data, Node leftChild, Node rightChild){ 48 this.data=data; 49 this.leftChild=leftChild; 50 this.rightChild=rightChild; 51 } 52 //endregion 53 @Override 54 public boolean equals(Object obj) { 55 if(this.data==obj){ 56 return true; 57 }else if(this.getClass()==obj.getClass()){ 58 Node nodeObj=(Node)obj; 59 return this.data.compareTo(nodeObj.data) ==0 && this.leftChild.equals(nodeObj.leftChild) 60 && this.rightChild.equals(nodeObj); 61 } 62 return false; 63 } 64 65 public String toString(){ 66 return "[data:"+this.data+"]"; 67 } 68 } 69 70 Node root=null; 71 public SortedBinaryTree() {} 72 public SortedBinaryTree(Node root){ 73 this.root=root; 74 } 75 76 //添加節(jié)點(diǎn) 77 public void add(T data){ 78 Node newNode=new Node(data); 79 if(root==null){ 80 root=newNode; 81 }else { 82 add(newNode, root); 83 } 84 } 85 public void add(Node addNode,Node parentNode) { 86 T data=addNode.data; 87 Node currentNode=parentNode; 88 Node parent=null; 89 int flag=0; 90 while(currentNode!=null){ 91 parent=currentNode; 92 flag=data.compareTo(currentNode.data); 93 if(flag>0){ 94 currentNode=currentNode.rightChild; 95 }else { 96 currentNode=currentNode.leftChild; 97 } 98 } 99 if(flag>0){ 100 parent.rightChild=addNode; 101 }else { 102 parent.leftChild=addNode; 103 } 104 addNode.parent=parent; 105 } 106 // 刪除節(jié)點(diǎn) 107 public void remove(T data){ 108 if(root==null){ 109 return; 110 }else { 111 Node removeNode=null;//待刪除的節(jié)點(diǎn) 112 removeNode = getNode(data); 113 //endregion 114 115 //如果沒有找見拋出異常 116 if(removeNode==null){ 117 throw new RuntimeException("未找見要?jiǎng)h除的節(jié)點(diǎn)"); 118 } 119 System.out.println("待刪除的節(jié)點(diǎn)為:"+removeNode.toString()); 120 //如果待刪除的節(jié)點(diǎn)既沒有左孩子也沒有右孩子 121 if(removeNode.leftChild==null && removeNode.rightChild==null){ 122 if(removeNode==root){//如果待刪除的節(jié)點(diǎn)就是根節(jié)點(diǎn),即樹中只有一個(gè)根節(jié)點(diǎn) 123 root=null; 124 }else {//如果待刪除的節(jié)點(diǎn)不是根節(jié)點(diǎn),這就要考慮這個(gè)節(jié)點(diǎn)是其父節(jié)點(diǎn)的左孩子還是右孩子 125 if(isLeftNodeOfParent(removeNode)){//如果待刪除是其父節(jié)點(diǎn)的左孩子,則斷開其父節(jié)點(diǎn)指向左孩子的“指針” 126 removeNode.parent.leftChild=null; 127 }else {//如果待刪除是其父節(jié)點(diǎn)的有孩子,則斷開其父節(jié)點(diǎn)指向右孩子的“指針” 128 removeNode.parent.rightChild=null; 129 } 130 //【注】斷開他的指向父節(jié)點(diǎn)的“指針” 131 //removeNode.parent=null; 132 } 133 }else if (removeNode.leftChild!=null && removeNode.rightChild==null) {//如果待刪除的節(jié)點(diǎn)有左孩子但是沒有右孩子 134 if(removeNode==root){//如果待刪除的節(jié)點(diǎn)就是根節(jié)點(diǎn) 135 136 //這條語(yǔ)句并不是必須的,因?yàn)閷?duì)于數(shù)而言,不管怎么都是以root為起點(diǎn)開始所有操作,所以遍歷等操作不會(huì)涉及 137 //到root.leftChild.parent.不將它設(shè)為null,同樣不影響樹的正常運(yùn)行。但是root.leftChild.parent所引 138 //用的對(duì)象并不會(huì)被當(dāng)成垃圾而被回收,因?yàn)閺膔oot.leftChild.parent依然可以訪問(wèn)到該Java對(duì)象 139 root.leftChild.parent=null; 140 141 root=root.leftChild; 142 }else {//如果待刪除的節(jié)點(diǎn)不是根節(jié)點(diǎn),那就必須討論待刪除的節(jié)點(diǎn)是其父節(jié)點(diǎn)的左子節(jié)點(diǎn)還是右子節(jié)點(diǎn) 143 if(isLeftNodeOfParent(removeNode)){ 144 removeNode.parent.leftChild=removeNode.leftChild; 145 }else { 146 removeNode.parent.rightChild=removeNode.leftChild; 147 } 148 //這條語(yǔ)句不要更精煉,加上會(huì)讓程序更清晰 149 //removeNode.parent=null; 150 151 152 removeNode.leftChild.parent=removeNode.parent; 153 } 154 //這條語(yǔ)句不要更精煉,加上會(huì)讓程序更清晰 155 //removeNode.leftChild=null; 156 } 157 else if (removeNode.leftChild==null && removeNode.rightChild!=null) {//如果待刪除的節(jié)點(diǎn)沒有左孩子但是有右孩子 158 if(root==removeNode){//如果待刪除的節(jié)點(diǎn)就是根節(jié)點(diǎn) 159 root=root.rightChild; 160 //釋放內(nèi)存,讓垃圾回收removeNode 161 removeNode.rightChild.parent=null; 162 }else {//如果待刪除的節(jié)點(diǎn)不是根節(jié)點(diǎn) 163 if(isLeftNodeOfParent(removeNode)){ 164 removeNode.parent.leftChild=removeNode.rightChild; 165 }else { 166 removeNode.parent.rightChild=removeNode.rightChild; 167 } 168 removeNode.rightChild.parent=removeNode.parent; 169 170 //這條語(yǔ)句不要更精煉,加上會(huì)讓程序更清晰 171 //removeNode.parent=null; 172 } 173 //這條語(yǔ)句不要更精煉,加上會(huì)讓程序更清晰 174 //removeNode.rightChild=null; 175 }else {//如果待刪除的節(jié)點(diǎn)既有左孩子也有右孩子 176 Node leftMaxNode=null; 177 //region【尋找被刪除節(jié)點(diǎn)左子樹中最大節(jié)點(diǎn)】 178 Node tmp=removeNode.leftChild; 179 while(tmp.rightChild!=null){ 180 tmp=tmp.rightChild; 181 } 182 leftMaxNode=tmp; 183 //endregion 184 185 System.out.println("leftmaxnode:"+leftMaxNode.toString()); 186 if(removeNode==root){//如果待刪除的節(jié)點(diǎn)就是根節(jié)點(diǎn) 187 if(leftMaxNode==removeNode.leftChild){//如果被刪除節(jié)點(diǎn)的左子樹中最大節(jié)點(diǎn)就是其左子節(jié)點(diǎn) 188 leftMaxNode.rightChild=root.rightChild; 189 root.rightChild.parent=leftMaxNode; 190 root=leftMaxNode; 191 leftMaxNode.parent=null; 192 193 //這條語(yǔ)句不要更精煉,加上會(huì)讓程序更清晰 194 //root.leftChild=null; 195 }else { 196 leftMaxNode.rightChild=root.rightChild; 197 leftMaxNode.leftChild=root.leftChild; 198 199 root.rightChild.parent=leftMaxNode; 200 root.leftChild.parent=leftMaxNode; 201 202 leftMaxNode.parent.rightChild=null; 203 leftMaxNode.parent=null; 204 root=leftMaxNode; 205 } 206 }else {//如果待刪除的節(jié)點(diǎn)不是根節(jié)點(diǎn) 207 if(leftMaxNode!=removeNode.leftChild){//如果被刪除節(jié)點(diǎn)的左子樹中最大節(jié)點(diǎn)不是其左子節(jié)點(diǎn) 208 Node addNode=removeNode.leftChild; 209 removeNode.leftChild=null; 210 addNode.parent=null; 211 add(addNode,leftMaxNode); 212 leftMaxNode.parent.rightChild=null; 213 } 214 leftMaxNode.rightChild=removeNode.rightChild; 215 removeNode.rightChild.parent=leftMaxNode; 216 217 leftMaxNode.parent=removeNode.parent; 218 219 220 if(isLeftNodeOfParent(removeNode)){ 221 removeNode.parent.leftChild=leftMaxNode; 222 }else { 223 removeNode.parent.rightChild=leftMaxNode; 224 } 225 } 226 } 227 } 228 } 229 230 public Node getNode(T data) { 231 Node removeNode=null; 232 Node current=root;//臨時(shí)變量,用于輔助查找待刪除的節(jié)點(diǎn) 233 //region 【尋找要待刪除的節(jié)點(diǎn)】 234 while(current!=null){ 235 if(data.compareTo(current.data)>0){ 236 current=current.rightChild; 237 }else if (data.compareTo(current.data)<0) { 238 current=current.leftChild; 239 }else { 240 removeNode=current; 241 break; 242 } 243 } 244 return removeNode; 245 } 246 247 private boolean isLeftNodeOfParent(Node node) { 248 return node.data.compareTo(node.parent.data)<=0; 249 } 250 //中序遍歷 251 public List<Node> midIterator(){ 252 return midIterator(root); 253 } 254 private List<Node> midIterator(Node node) { 255 List<Node> list=new ArrayList<Node>(); 256 if(node==null){ 257 return null; 258 } 259 if(node.leftChild!=null){ 260 list.addAll(midIterator(node.leftChild)); 261 } 262 list.add(node); 263 if(node.rightChild!=null){ 264 list.addAll(midIterator(node.rightChild)); 265 } 266 return list; 267 } 268 269 //先序遍歷 270 public List<Node> preIterator(){ 271 return preIterator(root); 272 } 273 private List<Node> preIterator(Node root) { 274 List<Node> list=new ArrayList<Node>(); 275 if(root==null) 276 return null; 277 list.add(root); 278 if(root.leftChild!=null){ 279 list.addAll(preIterator(root.leftChild)); 280 } 281 if(root.rightChild!=null){ 282 list.addAll(preIterator(root.rightChild)); 283 } 284 return list; 285 } 286 287 //廣度優(yōu)先遍歷 288 public List<Node> breadthFirst(){ 289 return breadthFirst(root); 290 } 291 private List<Node> breadthFirst(Node root) { 292 Queue<Node> queue=new ArrayDeque<Node>(); 293 List<Node> list=new ArrayList<Node>(); 294 if(root==null) 295 return null; 296 queue.offer(root); 297 while(!queue.isEmpty()){ 298 Node node=queue.poll(); 299 list.add(node); 300 if(node.leftChild!=null){ 301 queue.offer(node.leftChild); 302 } 303 if(node.rightChild!=null){ 304 queue.offer(node.rightChild); 305 } 306 } 307 return list; 308 } 309 } View Code

可能有些地方理解的還是不到位,并且代碼的性能不是很高,請(qǐng)大家批評(píng)指正。

注:版權(quán)所有,轉(zhuǎn)載請(qǐng)注明出處。

轉(zhuǎn)載于:https://www.cnblogs.com/yaoyinglong/p/DataStruct%e6%8e%92%e5%ba%8f%e4%ba%8c%e5%8f%89%e6%a0%91.html

總結(jié)

以上是生活随笔為你收集整理的一步一图一代码之排序二叉树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。