1. 程式人生 > 實用技巧 >java-二叉樹遍歷

java-二叉樹遍歷

1,完全二叉樹-建樹,先建簡單的樹,用簡單的樹學習各種遍歷之後再學其他建樹

  1 //先簡單建樹-按完全二叉樹節點插入順序建樹,即層序遍歷。
  2 
  3 /**二叉樹:每個節點最多兩個孩子節點(計劃生育-最多生二胎);
  4  * 完全二叉樹(遏制人口老齡化:必須生兩胎,否則不準後代傳宗接代):
  5  *            根節點(爺爺)先生,生不滿兩胎接著生,爺爺生完,老大(左爸爸)生,
  6  *            生不滿二胎,爺爺的小兒子不準生,。。。依次類推。
  7 * */
  8 
  9 /**按層間遍歷順序加入節點
 10  層序遍歷用佇列,根節點入隊,
 11
執行迴圈,當佇列不為空{對首X出隊,若X左孩子非空,入隊,右孩子非空入隊} 12 */ 13 14 /**層序遍歷(用佇列先進先出效能實①現先訪問根節點(第一層) 15 ②再依次訪問根節點的左右孩子節點(第二層) 16 ③再依次訪問根節點左右孩子節點的左右孫子節點(第三層), 17 ④..... 18 */ 19 20 /**? 21 * 功能 22 * ①,建樹--體會完全二叉樹,新增節點過程(先建簡單的,主要還是體會各種遍歷) 23 * ②,4種遍歷,7種方法,前、中、後序遞迴遍歷,前、中、後非遞迴遍歷,層序遍歷。
24 * ③,刪樹, 25 * ④,求樹高 26 * ⑤,樹狀列印 27 * ⑥, 28 */ 29 30 import java.util.LinkedList; 31 import java.util.Queue; 32 import java.util.Stack; 33 34 public class Easy_BiTree { 35 //內部Node類 36 public class Node { 37 private int data=Integer.MAX_VALUE; 38 private Node lchild=null
; 39 private Node rchild=null; 40 41 public Node(){} 42 public Node(int data){ 43 this.data=data; 44 } 45 46 } 47 48 private Node root=new Node(); 49 private int size=0; 50 public Easy_BiTree(){} 51 52 //新增節點 53 public void addNode(Node root,int data){ 54 //根節點 55 if(size==0){ 56 root.data=data; 57 size++; 58 }else{ 59 Node newNode=new Node(data); 60 61 // 新增節點用層序遍歷方法目的不是為了遍歷每一個節點,而是按層次順序找到第一個孩子不滿(沒生二胎)的節點 62 // 當遇到孩子節點沒滿的Node,新增節點-退出; 63 Queue<Node> queue=new LinkedList<>(); 64 queue.add(root); 65 while(!queue.isEmpty()){ 66 Node curroot=queue.poll(); 67 if(curroot.lchild!=null) 68 queue.add(curroot.lchild); 69 else{ 70 curroot.lchild=newNode; 71 size++; 72 return; 73 } 74 if(curroot.rchild!=null) 75 queue.add(curroot.rchild); 76 else{ 77 curroot.rchild=newNode; 78 size++; 79 return; 80 } 81 } 82 } 83 } 84 85 //遍歷-前序非遞迴, 86 87 /** 88 * ①順著根節點的左孩子一路到底,一邊輸出一邊入棧, 89 * ②到底後,判斷棧頂有沒有右子樹,有以右子節點為根節點重複①,沒有則出棧, 90 */ 91 public void preOrder(Node root){ 92 if(size==0) 93 System.out.println("樹空無遍歷"); 94 else{ 95 System.out.print("樹前序非遞迴: "); 96 Stack<Node> stack=new Stack<>(); 97 while(root!=null||!stack.isEmpty()){ 98 while(root!=null){ 99 System.out.print(root.data+" "); 100 stack.add(root); 101 root=root.lchild; 102 } 103 if(!stack.isEmpty()){ 104 root=stack.pop(); 105 root=root.rchild; 106 } 107 } 108 System.out.println(); 109 } 110 } 111 //遍歷-中序非遞迴, 112 public void inOrder(Node root){ 113 if(size==0) 114 System.out.println("樹空,無遍歷"); 115 else { 116 System.out.print("樹中序非遞迴: "); 117 Stack<Node> stack=new Stack<>(); 118 while(root!=null||!stack.isEmpty()){ 119 while(root!=null){ 120 stack.add(root); 121 root=root.lchild; 122 } 123 if(!stack.isEmpty()){ 124 root=stack.pop(); 125 System.out.print(root.data+" "); 126 root=root.rchild; 127 } 128 } 129 System.out.println(); 130 } 131 } 132 //遍歷-後序非遞迴, 133 /** 134 *①順著根節點的左孩子一路到底,入棧, 135 * ②到底後,判斷棧頂有沒有右子樹,沒有出棧,輸出 136 * ③有右子節點,右子節點遍歷之前不能出棧,preNode,即標識右子節點有沒有遍歷, 137 * 以右子節點為根節點重複①,②③ 138 */ 139 public void postOrder(Node root){ 140 if(size==0) 141 System.out.println("樹空,無遍歷"); 142 else { 143 System.out.print("樹後序非遞迴: "); 144 Stack<Node> stack=new Stack<>(); 145 while(root!=null||!stack.isEmpty()){ 146 while(root!=null){ 147 stack.push(root); 148 root=root.lchild; 149 } 150 boolean tag=true; 151 Node preNode=null; 152 while(!stack.isEmpty()&&tag==true){ 153 root=stack.peek(); 154 if(root.rchild==preNode){ 155 root=stack.pop(); 156 System.out.print(root.data+" "); 157 if(stack.isEmpty()){ 158 System.out.println(); 159 return; 160 } 161 else 162 preNode=root; 163 }else{ 164 root=root.rchild; 165 tag=false; 166 } 167 } 168 } 169 System.out.println(); 170 } 171 } 172 173 /** 174 * 額。。遞迴寫起來是很簡單,我也說不好原理,233 175 */ 176 //遍歷-前序遞迴, 177 public void preOrderRec(Node root){ 178 if(root==null) 179 return; 180 else { 181 System.out.print(root.data+" "); 182 preOrderRec(root.lchild); 183 preOrderRec(root.rchild); 184 } 185 } 186 //遍歷-中序遞迴, 187 public void inOrderRec(Node root){ 188 if(root==null) 189 return; 190 else{ 191 inOrderRec(root.lchild); 192 System.out.print(root.data+" "); 193 inOrderRec(root.rchild); 194 } 195 } 196 //遍歷-後序遞迴, 197 public void postOrderRec(Node root){ 198 if(root==null) 199 return; 200 else{ 201 postOrderRec(root.lchild); 202 postOrderRec(root.rchild); 203 System.out.print(root.data+" "); 204 } 205 } 206 207 208 209 //遍歷,-層間遍歷 210 public void levelOrder(Node root){ 211 if(this.size==0) 212 System.out.println("空樹,無法遍歷"); 213 else{ 214 System.out.println("樹層間遍歷:"); 215 Queue<Node> queue=new LinkedList<>(); 216 queue.add(root); 217 while(!queue.isEmpty()){ 218 Node curroot=queue.poll(); 219 System.out.print(curroot.data+" "); 220 if(curroot.lchild!=null) 221 queue.add(curroot.lchild); 222 if(curroot.rchild!=null) 223 queue.add(curroot.rchild); 224 } 225 System.out.println(); 226 } 227 } 228 229 //刪樹 230 //java有記憶體回收機制,只要把根節點狀態,換成空樹根節點狀態即可; 231 //C++也是類似遍歷一遍,把遍歷到的每一個節點free; 232 233 //呃。。。。我猜的,哈哈哈哈哈哈哈哈 234 public void deleteTree(){ 235 root.lchild=null; 236 root.rchild=null; 237 root.data=Integer.MAX_VALUE; 238 size=0; 239 } 240 241 /** 242 * 樹高-遞迴和非遞迴方法 243 * 完全二叉樹,節點和高有方程,log(size)向下取整+1 244 * 這裡用非特殊二叉樹求樹高, 245 */ 246 247 //轉載:https://blog.csdn.net/shijie97/article/details/79775399 248 /**非遞迴-佇列, 249 * 根節點入隊,出隊,新增第二層,新增完後記錄隊size(0/1/2),然後將(0/1/2)個出隊,將他們的孩子入隊,記錄每一層 250 * 孩子數,遍歷完,即可知道層數 251 */ 252 public int treeHeight(Node root){ 253 if(root==null||root.data==Integer.MAX_VALUE) 254 return 0; 255 else if(size==1) 256 return 1; 257 else{ 258 Queue<Node> queue=new LinkedList<>(); 259 queue.add(root); 260 int height=0; 261 //記錄每層孩子個數,root入隊長為1 262 int len=1; 263 while(!queue.isEmpty()){ 264 int length=0; 265 for(int i=0;i<len;i++){ 266 Node curroot=queue.poll(); 267 if(curroot.lchild!=null){ 268 queue.add(curroot.lchild); 269 length++; 270 } 271 if(curroot.rchild!=null){ 272 queue.add(curroot.rchild); 273 length++; 274 } 275 } 276 len=length; 277 height++; 278 } 279 return height; 280 } 281 } 282 //遞迴 283 public int treeHeightRec(Node root){ 284 if(root==null||root.data==Integer.MAX_VALUE) 285 return 0; 286 else{ 287 int a =treeHeightRec(root.lchild); 288 int b = treeHeightRec(root.rchild); 289 return (a>b)?(a+1):(b+1); 290 } 291 } 292 293 //樹狀列印 294 /** 295 * 思路:先確定樹高h-最後一層2^(h-1)個數,好知道根節點放在哪裡(預留空間保證根再中間) 296 * 設每個data三位數=space,元素之間空三位數,每行 (2^H+1)*3 個“ ” 297 * _數_數_數_數_數_ 每層2^(h-1)個數,2^(h-1)+1個space,最後一行長2^h+1個space 298 * 299 * 當層數多的時候稍亂,2333不想弄了, 300 */ 301 public void printTree(Node root){ 302 int H=treeHeight(root); 303 int h=H; 304 //System.out.println("樹高:"+H); 305 if(H==0) 306 System.out.println("樹空,無列印"); 307 else{ 308 System.out.println("列印樹:"); 309 Queue<Node> queue=new LinkedList<>(); 310 queue.add(root); 311 int height=1; 312 //記錄每層孩子個數 313 int len=1; 314 while(h>0){ 315 int length=0; 316 String space=""; 317 for(int i=0;i<(((Math.pow(2,H)+1)*3)/(Math.pow(2,height)+1));i++) 318 space+=" "; 319 for(int i=0;i<len;i++){ 320 Node curroot=queue.poll(); 321 if(curroot.data==Integer.MAX_VALUE){ 322 System.out.print(space); 323 }else 324 System.out.print(space+curroot.data); 325 326 if(curroot.lchild!=null){ 327 queue.add(curroot.lchild); 328 } 329 else 330 queue.add(new Node()); 331 length++; 332 if(curroot.rchild!=null){ 333 queue.add(curroot.rchild); 334 } 335 else 336 queue.add(new Node()); 337 length++; 338 } 339 System.out.println(); 340 System.out.println(); 341 len=length; 342 height++; 343 h--; 344 } 345 System.out.println(); 346 } 347 } 348 349 350 public static void main(String args[]) { 351 Easy_BiTree t=new Easy_BiTree(); 352 t.addNode(t.root,1); 353 t.addNode(t.root,2); 354 t.addNode(t.root,3); 355 t.addNode(t.root,4); 356 t.addNode(t.root,5); 357 t.addNode(t.root,6); 358 t.addNode(t.root,7); 359 t.addNode(t.root,8); 360 // t.addNode(t.root,9); 361 // t.addNode(t.root,10); 362 // t.addNode(t.root,11); 363 // t.addNode(t.root,12); 364 // t.addNode(t.root,13); 365 // t.addNode(t.root,14); 366 // t.addNode(t.root,15); 367 // t.addNode(t.root,16); 368 // t.addNode(t.root,17); 369 // t.addNode(t.root,18); 370 // t.addNode(t.root,19); 371 // t.addNode(t.root,20); 372 // t.addNode(t.root,21); 373 374 t.levelOrder(t.root); 375 System.out.println("非遞迴求樹高: "+t.treeHeight(t.root)); 376 System.out.println("遞迴求樹高: "+t.treeHeightRec(t.root)); 377 378 t.printTree(t.root); 379 380 t.preOrder(t.root); 381 t.inOrder(t.root); 382 t.postOrder(t.root); 383 384 System.out.print("樹前序遞迴遍歷: "); 385 t.preOrderRec(t.root); 386 System.out.println(); 387 System.out.print("樹中序遞迴遍歷: "); 388 t.inOrderRec(t.root); 389 System.out.println(); 390 System.out.print("樹後序遞迴遍歷: "); 391 t.postOrderRec(t.root); 392 System.out.println(); 393 394 395 t.deleteTree(); 396 System.out.println("非遞迴求樹高: "+t.treeHeight(t.root)); 397 398 } 399 }
View Code