遍曆二叉樹就是遵循某種次序,訪問二叉樹中的所有節點,每個節點只訪問一次。
二叉樹的遍曆有三種方式:前序走訪,中序遍曆和後序遍曆。所謂的前序,中序和後序是針對根節點來說的。
前序走訪:首先訪問根節點,然後訪問左子樹,最後訪問右子樹。
中序遍曆:首先訪問左子樹,然後訪問根節點,最後訪問右子樹。
後續遍曆:首先訪問左子樹,然後訪問右子樹,最後訪問根節點。
下面我們對鏈式儲存的二叉樹進行遍曆。
範例程式碼:
package mianshiti;import java.util.*;public class BinarySearchTree<DataType> {private TreeNode<DataType> root=null;//根節點public static void main(String[] args) {// TODO Auto-generated method stubBinarySearchTree<Character> tree=new BinarySearchTree<Character>(init());System.out.println("前序走訪:");tree.preorder(tree.getRoot());System.out.println();System.out.println("中序遍曆:");tree.inorder(tree.getRoot());System.out.println();System.out.println("後序遍曆:");tree.postorder(tree.getRoot());System.out.println();}//前序走訪public void preorder(TreeNode<DataType> node){if(node!=null){this.getNodeInfo(node);preorder(node.getLeft());preorder(node.getRight());}}//中序遍曆public void inorder(TreeNode<DataType> node){if(node!=null){inorder(node.getLeft());this.getNodeInfo(node);inorder(node.getRight());}}//後序遍曆public void postorder(TreeNode<DataType> node){if(node!=null){postorder(node.getLeft());postorder(node.getRight());this.getNodeInfo(node);}}//構造一個二叉樹public static TreeNode init(){TreeNode<Character> a=new TreeNode<Character>('A');TreeNode<Character> b=new TreeNode<Character>('B',null,a);TreeNode<Character> c=new TreeNode<Character>('C');TreeNode<Character> d=new TreeNode<Character>('D',b,c);TreeNode<Character> e=new TreeNode<Character>('E');TreeNode<Character> f=new TreeNode<Character>('F',e,null);TreeNode<Character> g=new TreeNode<Character>('G',null,f);TreeNode<Character> h=new TreeNode<Character>('H',d,g);return h;}//建構函式public BinarySearchTree(TreeNode<DataType> root){this.root=root;}public TreeNode<DataType> getRoot(){return this.root;}public void getNodeInfo(TreeNode<DataType> treenode){if(treenode!=null){System.out.print(treenode.getData()+" ");}}}class TreeNode<DataType>{private DataType data;private TreeNode<DataType> left;//左子節點private TreeNode<DataType> right;//右子節點//建構函式public TreeNode(DataType data){this(data,null,null);}public TreeNode(DataType data,TreeNode<DataType> left,TreeNode<DataType> right){this.data=data;this.left=left;this.right=right;}//公有方法public DataType getData() {return data;}public void setData(DataType data) {this.data = data;}public TreeNode<DataType> getLeft() {return left;}public void setLeft(TreeNode<DataType> left) {this.left = left;}public TreeNode<DataType> getRight() {return right;}public void setRight(TreeNode<DataType> right) {this.right = right;}}
運行結果如下:
前序走訪:H D B A C G F E 中序遍曆:B A D C H G E F 後序遍曆:A B C D E F G H
上面是通過遞迴方式實現的對於二叉樹的遍曆,雖然這種方式比較簡單,但是我們知道會消耗系統較多的資源,下面我們使用非遞迴的方式實現二叉樹的遍曆。
首先是前序走訪,思想是:從根節點開始,如果該節點不為空白,則將其壓入堆棧,接著判斷堆棧是否為空白,如果不為空白,則彈出一個節點,並且輸出該節點的資料資訊,接著按照前後順序分別對該節點的右子樹和左子樹進行判斷,如果有右子樹,則將右子樹壓入棧中,如果有左子樹,則將左子樹壓入棧中,最後再判斷堆棧是否為空白,如果不為空白則繼續上面的操作,如果為空白,則遍曆結束。
實現的演算法為下:
//非遞迴方式實現前序走訪public void nonRecursivePreorder(TreeNode<DataType> node){Stack<TreeNode<DataType>> mystack=new Stack<TreeNode<DataType>>();if(node!=null){mystack.push(node);while(!mystack.isEmpty()){TreeNode<DataType> temp=mystack.pop();this.getNodeInfo(temp);if(temp.getRight()!=null){mystack.push(temp.getRight());}if(temp.getLeft()!=null){mystack.push(temp.getLeft());}}}}
其次是中序遍曆,演算法實現如下:
//非遞迴方式實現中序遍曆public void nonRecursiveInorder(TreeNode<DataType> node){Stack<TreeNode<DataType>> mystack=new Stack<TreeNode<DataType>>();while(node!=null){while(node!=null){if(node.getRight()!=null){mystack.push(node.getRight());}mystack.push(node);node=node.getLeft();}node=mystack.pop();while(!mystack.isEmpty()&&node.getRight()==null){this.getNodeInfo(node);node=mystack.pop();}this.getNodeInfo(node);if(!mystack.isEmpty()){node=mystack.pop();}else{node=null;}}}
最後是後序遍曆,演算法實現如下:
//非遞迴方式實現後續遍曆public void nonRecursivePostorder(TreeNode<DataType> node){Stack<TreeNode<DataType>> mystack=new Stack<TreeNode<DataType>>();TreeNode<DataType> temp=node;while(node!=null){for(;node.getLeft()!=null;node=node.getLeft()){mystack.push(node);}while(node!=null&&(node.getRight()==null||node.getRight()==temp)){this.getNodeInfo(node);temp=node;if(mystack.isEmpty())return;node=mystack.pop();}mystack.push(node);node=node.getRight();}}
運行結果如下所示:
遞迴方式實現前序走訪:H D B A C G F E 遞迴方式實現中序遍曆:B A D C H G E F 遞迴方式實現後序遍曆:A B C D E F G H 非遞迴方式實現前序走訪:H D B A C G F E 非遞迴方式實現中序遍曆:B A D C H G E F 非遞迴方式實現後序遍曆:A B C D E F G H
完整的程式如下所示:
package mianshiti;import java.util.*;public class BinarySearchTree<DataType> {private TreeNode<DataType> root=null;//根節點public static void main(String[] args) {// TODO Auto-generated method stubBinarySearchTree<Character> tree=new BinarySearchTree<Character>(init());System.out.println("遞迴方式實現前序走訪:");tree.preorder(tree.getRoot());System.out.println();System.out.println("遞迴方式實現中序遍曆:");tree.inorder(tree.getRoot());System.out.println();System.out.println("遞迴方式實現後序遍曆:");tree.postorder(tree.getRoot());System.out.println();System.out.println("非遞迴方式實現前序走訪:");tree.nonRecursivePreorder(tree.getRoot());System.out.println();System.out.println("非遞迴方式實現中序遍曆:");tree.nonRecursiveInorder(tree.getRoot());System.out.println();System.out.println("非遞迴方式實現後序遍曆:");tree.nonRecursivePostorder(tree.getRoot());System.out.println();}//前序走訪public void preorder(TreeNode<DataType> node){if(node!=null){this.getNodeInfo(node);preorder(node.getLeft());preorder(node.getRight());}}//中序遍曆public void inorder(TreeNode<DataType> node){if(node!=null){inorder(node.getLeft());this.getNodeInfo(node);inorder(node.getRight());}}//後序遍曆public void postorder(TreeNode<DataType> node){if(node!=null){postorder(node.getLeft());postorder(node.getRight());this.getNodeInfo(node);}}//非遞迴方式實現前序走訪public void nonRecursivePreorder(TreeNode<DataType> node){Stack<TreeNode<DataType>> mystack=new Stack<TreeNode<DataType>>();if(node!=null){mystack.push(node);while(!mystack.isEmpty()){TreeNode<DataType> temp=mystack.pop();this.getNodeInfo(temp);if(temp.getRight()!=null){mystack.push(temp.getRight());}if(temp.getLeft()!=null){mystack.push(temp.getLeft());}}}}//非遞迴方式實現中序遍曆public void nonRecursiveInorder(TreeNode<DataType> node){Stack<TreeNode<DataType>> mystack=new Stack<TreeNode<DataType>>();while(node!=null){while(node!=null){if(node.getRight()!=null){mystack.push(node.getRight());}mystack.push(node);node=node.getLeft();}node=mystack.pop();while(!mystack.isEmpty()&&node.getRight()==null){this.getNodeInfo(node);node=mystack.pop();}this.getNodeInfo(node);if(!mystack.isEmpty()){node=mystack.pop();}else{node=null;}}}//非遞迴方式實現後續遍曆public void nonRecursivePostorder(TreeNode<DataType> node){Stack<TreeNode<DataType>> mystack=new Stack<TreeNode<DataType>>();TreeNode<DataType> temp=node;while(node!=null){for(;node.getLeft()!=null;node=node.getLeft()){mystack.push(node);}while(node!=null&&(node.getRight()==null||node.getRight()==temp)){this.getNodeInfo(node);temp=node;if(mystack.isEmpty())return;node=mystack.pop();}mystack.push(node);node=node.getRight();}}//構造一個二叉樹public static TreeNode init(){TreeNode<Character> a=new TreeNode<Character>('A');TreeNode<Character> b=new TreeNode<Character>('B',null,a);TreeNode<Character> c=new TreeNode<Character>('C');TreeNode<Character> d=new TreeNode<Character>('D',b,c);TreeNode<Character> e=new TreeNode<Character>('E');TreeNode<Character> f=new TreeNode<Character>('F',e,null);TreeNode<Character> g=new TreeNode<Character>('G',null,f);TreeNode<Character> h=new TreeNode<Character>('H',d,g);return h;}//建構函式public BinarySearchTree(TreeNode<DataType> root){this.root=root;}public TreeNode<DataType> getRoot(){return this.root;}public void getNodeInfo(TreeNode<DataType> treenode){if(treenode!=null){System.out.print(treenode.getData()+" ");}}}class TreeNode<DataType>{private DataType data;private TreeNode<DataType> left;//左子節點private TreeNode<DataType> right;//右子節點//建構函式public TreeNode(DataType data){this(data,null,null);}public TreeNode(DataType data,TreeNode<DataType> left,TreeNode<DataType> right){this.data=data;this.left=left;this.right=right;}//公有方法public DataType getData() {return data;}public void setData(DataType data) {this.data = data;}public TreeNode<DataType> getLeft() {return left;}public void setLeft(TreeNode<DataType> left) {this.left = left;}public TreeNode<DataType> getRight() {return right;}public void setRight(TreeNode<DataType> right) {this.right = right;}}