該文主要介紹2叉數的基本遍歷的實現,在此以前,首先應該知道2叉數有哪些遍歷?java
先序遍歷:根-->左-->右 即先訪問根結點,而後訪問左子樹,最後訪問右子樹。在遍歷左、右子樹時,仍然如此。node
上圖遍歷結果:A,B,D,E,C,F,G。數據結構
中序遍歷:左-->根-->右 即先訪問左子樹,而後訪問根結點,最後訪問右子樹。在遍歷左、右子樹時,仍然如此。post
上圖遍歷結果:D,B,E,A,F,C,G。測試
後序遍歷:左-->右-->根 即先訪問左子樹,而後訪問右子樹,最後訪問根結點。在遍歷左、右子樹時,仍然如此。this
上圖遍歷結果:D,E,B,F,G,C,A。spa
層次遍歷:1層,2層,3層,依次訪問下來,若是某一層元素超過兩個,那麼從先左後右訪問。code
上圖遍歷結果:A,B,C,D,E,F,G。(這個已經簡單不行了)遞歸
深度遍歷:首先訪問根結點(A),而後沿着它的左結點依次訪問(B,D),至到訪問到最後一層(也就是D),再返回到它的父親(B),訪問他的右結點(E)。而後這樣重複地訪問完全部結點。隊列
上圖遍歷結果:A,B,D,E,C,F,G。
備註:
1.上面的先、中、後序遍歷,主要看的就是根在訪問順序中所在的位置。「根左右」,根在前,因此叫先序遍歷。「左根右」,根在中,因此叫中序遍歷。
2.在中序遍歷中,有一種很快得出其遍歷的結果的方法。叫作投影法。(你覺得我會把這個方法的連接放在這裏麼?No,我只會告訴你,請百度百科「中序遍歷」,這裏有我想給你看的「投影法」。)
如何實現?
先序遍歷:首先訪問根,而後遞歸訪問左子樹,再遞歸訪問右子樹便可。
中/後序遍歷:相似於先序遍歷。等下看源碼就明白了。
層次遍歷
首先將根入隊列(先進先出),而後就循環判斷這個隊列是否爲空。只要隊列不爲空,就取出隊列中的一個結點,訪問這個結點的值,再將這個結點的左結點入隊列,再將這個隊列的右結點入隊列。
層次遍歷詳細解釋:
以上圖的2叉數爲例,首先將根A結點入隊列,如今用while來循環判斷隊列是否爲空。很明顯,不爲空。因此取出隊列中的結點(A)來訪問,而後,這個結點(A)的左結點(B)不爲空,入隊列,這個結點的右結點(C)也不爲空,入隊列。因此如今隊列中就又有了B、C兩個結點,因此循環繼續。拿出B,訪問B,再將B的左右結點D、E入隊列。如今隊列中就有了C、D、E了。隊列不爲空,因此循環繼續,拿出C,訪問C,再將F,G入隊列。如今隊列中就是D、E、F、G了。隊列不爲空,拿出D訪問,D沒有子結點,那麼沒有新的結點入隊列,但隊列尚未爲空,因此接着拿出E來訪問,E也沒有子結點,因此也沒有新的結點入隊列,但隊列尚未爲空,接着再拿隊列中的F來訪問,依次類推了。(寫得很羅嗦,但願能把這個過程解釋清楚。)
深度遍歷
首先將根入棧(先進後出),而後就循環判斷這個棧是否爲空。只要棧不爲空,就取出棧中的一個結點,訪問這個結點的值,再將這個結點的右結點入棧,再將這個結點的左結點入棧。(很相似於層次遍歷的實現,只是所用的數據結構由隊列變成了棧,入隊列是先左後右,入棧的順序是先右後左)
深度遍歷詳細解釋:
這個很相似於層次遍歷的詳細解釋,我簡單得說一下。首先根A入棧,而後循環判斷棧是否爲空,如今棧裏有結點A,因此不爲空,因此取出A,訪問A,將C、B入棧(也就是將A的右結點入棧,而後左結點入棧,和層次遍歷時是相反的)。再判斷棧是否爲空,如今棧中有C、B。因爲棧是後進先出的結構,因此這裏是B彈出棧,訪問B,再將B的子結點E、D入棧,那現棧中就有了C、E、D。判斷棧不空,又彈出D,訪問D,將D的子結點入棧。這樣類推下去,就完成了遍歷。
java代碼以下:(有點多,不過該代碼可測試運行)
package com.cdu.binaryTree; import java.util.LinkedList; public class MyBinaryTree { public static void main(String[] args) { //初始化一棵2叉數 BinaryTree binaryTree = BinaryTree.initBinaryTree(); // 先序遍歷 System.out.println("先序遍歷:"); binaryTree.preOrderTraversal(binaryTree); System.out.println("\n"); // 中序遍歷 System.out.println("中序遍歷:"); binaryTree.midOrderTrversal(binaryTree); System.out.println("\n"); // 後序遍歷 System.out.println("後序遍歷:"); binaryTree.postOrderTrversal(binaryTree); System.out.println("\n"); // 層次遍歷 System.out.println("層次遍歷:"); binaryTree.levelTraversal(binaryTree); System.out.println("\n"); // 深度遍歷 System.out.println("深度遍歷:"); binaryTree.depthTraversal(binaryTree); System.out.println("\n"); } } class BinaryTree{ private int data; //結點值 private BinaryTree left; //左子結點 private BinaryTree right; //右子結點 public BinaryTree(int data){ this.data = data; } /** * @Description 初始化二叉數 * @param * @return 獲得以下所示的二叉數 * 1 * * * * 2 3 * * * * * * 4 5 6 7 * * * * * 9 10 11 * * * 8 * * 先序遍歷結果:1,2,4,9,5,10,8,11,3,6,7 * 中序遍歷結果:4,9,2,8,10,5,11,1,6,3,7 * 後序遍歷結果:9,4,8,10,11,5,2,6,7,3,1 * 層次遍歷結果:1,2,3,4,5,6,7,9,10,11,8 * 深度遍歷結果:1,2,4,9,5,10,8,11,3,6,7 */ public static BinaryTree initBinaryTree(){ BinaryTree root = new BinaryTree(1); BinaryTree node2 = new BinaryTree(2); BinaryTree node3 = new BinaryTree(3); BinaryTree node4 = new BinaryTree(4); BinaryTree node5 = new BinaryTree(5); BinaryTree node6 = new BinaryTree(6); BinaryTree node7 = new BinaryTree(7); BinaryTree node8 = new BinaryTree(8); BinaryTree node9 = new BinaryTree(9); BinaryTree node10 = new BinaryTree(10); BinaryTree node11 = new BinaryTree(11); root.setLeft(node2); root.setRight(node3); node2.setLeft(node4); node2.setRight(node5); node3.setLeft(node6); node3.setRight(node7); node4.setRight(node9); node5.setLeft(node10); node5.setRight(node11); node10.setLeft(node8); return root; } /** * @Description 先序遍歷 * @param binaryTree 二叉數 * @return */ public void preOrderTraversal(BinaryTree binaryTree){ // 當2叉數爲空時,遞歸結束。 if (binaryTree == null){ return ; }else{ System.out.print(binaryTree.getData() + ","); //訪問結點 preOrderTraversal(binaryTree.getLeft()); //遞歸遍歷左子樹 preOrderTraversal(binaryTree.getRight()); //遞歸遍歷右子樹 } } /** * @Description 中序遍歷 * @param binaryTree 二叉數 * @return */ public void midOrderTrversal(BinaryTree binaryTree){ if (binaryTree == null){ return ; }else{ midOrderTrversal(binaryTree.getLeft()); System.out.print(binaryTree.getData() + ","); midOrderTrversal(binaryTree.getRight()); } } /** * @Description 後序遍歷 * @param binaryTree 二叉數 * @return */ public void postOrderTrversal(BinaryTree binaryTree){ if (binaryTree == null){ return ; }else{ postOrderTrversal(binaryTree.getLeft()); postOrderTrversal(binaryTree.getRight()); System.out.print(binaryTree.getData()+ ","); } } /** * @Description 層次遍歷:先將根節點入隊列,而後判斷只要隊列不爲空, * 那麼就從隊列中poll一個結點來訪問,而後再將該結點的左結點入隊列,而後再將右結點入隊列 * @param * @return */ public void levelTraversal(BinaryTree binaryTree){ LinkedList<BinaryTree> queue = new LinkedList<BinaryTree>(); if (binaryTree != null){ queue.offer(binaryTree); } // 只要隊列不爲空,則遍歷隊列中結點 while (!queue.isEmpty()){ BinaryTree node = queue.poll(); System.out.print(node.getData() + ","); // 若結點有子結點,那麼將該結點的左、右結點存入隊列 if (node.getLeft() != null){ queue.offer(node.getLeft()); } if (node.getRight() != null){ queue.offer(node.getRight()); } } } /** * @Description 深度遍歷:先將根節點入隊列,而後判斷只要棧不爲空, * 那麼就在棧中pop一個結點來訪問,而後再將該結點的右結點壓棧,而後再將左結點壓棧 * @param * @return */ public void depthTraversal(BinaryTree binaryTree){ LinkedList<BinaryTree> stack = new LinkedList<BinaryTree>(); if (binaryTree != null){ stack.push(binaryTree); } // 只要棧不爲空,則遍歷棧中結點 while(!stack.isEmpty()){ BinaryTree node = stack.pop(); System.out.print(node.getData() + ","); // 若結點有子結點,那麼將該結點的右、左結點存入隊列 if (node.getRight() != null){ stack.push(node.getRight()); } if (node.getLeft() != null){ stack.push(node.getLeft()); } } } /*--------------getter and setter--------------------*/ public int getData() { return data; } public void setData(int data) { this.data = data; } public BinaryTree getLeft() { return left; } public void setLeft(BinaryTree left) { this.left = left; } public BinaryTree getRight() { return right; } public void setRight(BinaryTree right) { this.right = right; } }