在【Java】 大話數據結構(9) 樹(二叉樹、線索二叉樹)一文中,已經實現了採用遞歸方法的前、中、後序遍歷,本文補充了採用循環的實現方法、以及層序遍歷並進行了一個總結。html
/* * 前序遍歷 */ public void preOrder() { preOrderTraverse(root); System.out.println(); } private void preOrderTraverse(BiTNode<E> node) { if(node==null) return; System.out.print(node.data); preOrderTraverse(node.lchild); preOrderTraverse(node.rchild); } /* * 中序遍歷 */ public void inOrder() { inOrderTraverse(root); System.out.println(); } private void inOrderTraverse(BiTNode<E> node) { if(node==null) return; inOrderTraverse(node.lchild); System.out.print(node.data); inOrderTraverse(node.rchild); } /* * 後序遍歷 */ public void postOrder() { postOrderTraverse(root); System.out.println(); } private void postOrderTraverse(BiTNode<E> node) { if(node==null) return; postOrderTraverse(node.lchild); postOrderTraverse(node.rchild); System.out.print(node.data); }
非遞歸實現,須要先建立一個棧,利用其特性來進行儲存和輸出。java
下面代碼中,要注意node的結點位置和stack.peek()的位置關係。node
此外,在後序非遞歸遍歷的過程當中,棧中保留的是當前結點的全部祖先。這是和先序及中序遍歷不一樣的。在某些和祖先有關的算法中,此算法頗有價值。算法
/** * 前序遍歷(非遞歸) */ public void preOrder2() { preOrder2(root); System.out.println(); } private void preOrder2(BiTNode node) { Stack<BiTNode> stack = new Stack<BiTNode>(); while(node!=null||!stack.isEmpty()) { while(node!=null) { System.out.print(node.data); stack.push(node); node=node.lchild; } node=stack.pop().rchild; } } /** * 中序遍歷 */ public void inOrder2() { inOrder2(root); System.out.println(); } private void inOrder2(BiTNode node) { Stack<BiTNode> stack = new Stack<BiTNode>(); while(node!=null||!stack.isEmpty()) { while(node!=null) { stack.push(node); node=node.lchild; } node=stack.pop(); System.out.print(node.data); node=node.rchild; } } /** * 後序遍歷 */ public void postOrder2() { postOrder2(root); System.out.println(); } private void postOrder2(BiTNode node) { Stack<BiTNode> stack = new Stack<BiTNode>(); Stack<Integer> tag = new Stack<Integer>();
//下面這段註釋也能實現,與後面未註釋部分基本一致。表明了本身的思考過程,就不刪除了 // while(node!=null||!stack.isEmpty()) { // while(node!=null){ // stack.push(node); // tag.push(0); // node=node.lchild; // } //註釋中的tag用於標記當前結點是否完成左右子結點遍歷(因此用0,1表示) // while(!tag.isEmpty()&&tag.peek()==1) { //棧頂節點的左右子結點已完成遍歷 // System.out.print(stack.pop().data); // tag.pop(); // } // if(!tag.isEmpty()) { //上面和這裏的 !flag.isEmpty() 不可省略,否則會出錯。 // tag.pop(); // tag.push(1); // node=stack.peek().rchild; // } // } /*後序遍歷時,分別從左子樹和右子樹共兩次返回根結點(用tag表示次數), * 只有從右子樹返回時才訪問根結點,因此增長一個棧標記到達結點的次序。 */ while(node!=null||!stack.isEmpty()) { if(node!=null){ stack.push(node); tag.push(1); //第一次訪問 node=node.lchild; }else { if(tag.peek()==2) { System.out.print(stack.pop().data); tag.pop(); }else { tag.pop(); tag.push(2); //第二次訪問 node=stack.peek().rchild; } } } }
20191104:前序和後序的非遞歸遍歷還能夠合理利用棧的性質來實現,與上面的稍有不一樣。數據結構
前序:ide
public List<Integer> preorderTraversal(TreeNode root) { ArrayList<Integer> list = new ArrayList<Integer>(); Stack<TreeNode> stk = new Stack<>(); stk.push(root); while(!stk.isEmpty()){ TreeNode node = stk.pop(); if(node==null) continue; list.add(node.val); stk.push(node.right); stk.push(node.left); } return list; }
後序:post
public List<Integer> postorderTraversal(TreeNode root) { LinkedList<Integer> list = new LinkedList<Integer>(); Stack<TreeNode> stk = new Stack<>(); stk.push(root); while(!stk.isEmpty()){ TreeNode node = stk.pop(); if(node==null) continue; list.addFirst(node.val); //LinkedList's method. If using ArrayList here,then using 'Collections.reverse(list)'' in the end; stk.push(node.left); stk.push(node.right); } return list; }
合理利用隊列的性質便可。測試
public void levelOrder() { BiTNode<E> node =root; LinkedList<BiTNode<E>> list = new LinkedList<>(); list.add(node); while(!list.isEmpty()) { node=list.poll(); System.out.print(node.data); if(node.lchild!=null) list.offer(node.lchild); if(node.rchild!=null) list.offer(node.rchild); } }
package BiTree; import java.util.LinkedList; import java.util.Stack; class BiTNode<E>{ E data; BiTNode<E> lchild,rchild; public BiTNode(E data) { this.data=data; this.lchild=null; this.rchild=null; } } public class BiTree<E> { private BiTNode<E> root; public BiTree() { //root=new BiTNode(null, null, null); root=null; } /* * 前序遍歷 */ public void preOrder() { preOrderTraverse(root); System.out.println(); } private void preOrderTraverse(BiTNode<E> node) { if(node==null) return; System.out.print(node.data); preOrderTraverse(node.lchild); preOrderTraverse(node.rchild); } /* * 中序遍歷 */ public void inOrder() { inOrderTraverse(root); System.out.println(); } private void inOrderTraverse(BiTNode<E> node) { if(node==null) return; inOrderTraverse(node.lchild); System.out.print(node.data); inOrderTraverse(node.rchild); } /* * 後序遍歷 */ public void postOrder() { postOrderTraverse(root); System.out.println(); } private void postOrderTraverse(BiTNode<E> node) { if(node==null) return; postOrderTraverse(node.lchild); postOrderTraverse(node.rchild); System.out.print(node.data); } //===============循環遍歷=============== /** * 前序遍歷(非遞歸) */ public void preOrder2() { preOrder2(root); System.out.println(); } private void preOrder2(BiTNode node) { Stack<BiTNode> stack = new Stack<BiTNode>(); while(node!=null||!stack.isEmpty()) { while(node!=null) { System.out.print(node.data); stack.push(node); node=node.lchild; } node=stack.pop().rchild; } } /** * 中序遍歷 */ public void inOrder2() { inOrder2(root); System.out.println(); } private void inOrder2(BiTNode node) { Stack<BiTNode> stack = new Stack<BiTNode>(); while(node!=null||!stack.isEmpty()) { while(node!=null) { stack.push(node); node=node.lchild; } node=stack.pop(); System.out.print(node.data); node=node.rchild; } } /** * 後序遍歷 */ public void postOrder2() { postOrder2(root); System.out.println(); } private void postOrder2(BiTNode node) { Stack<BiTNode> stack = new Stack<BiTNode>(); Stack<Integer> tag = new Stack<Integer>(); // while(node!=null||!stack.isEmpty()) { // while(node!=null){ // stack.push(node); // tag.push(0); // node=node.lchild; // } //這裏的tag用於標記當前結點是否完成左右子結點遍歷(因此用0,1表示) // while(!tag.isEmpty()&&tag.peek()==1) { //棧頂節點的左右子結點已完成遍歷 // System.out.print(stack.pop().data); // tag.pop(); // } // if(!tag.isEmpty()) { //上面和這裏的 !flag.isEmpty() 不可省略,否則會出錯。 // tag.pop(); // tag.push(1); // node=stack.peek().rchild; // } // } /*後序遍歷時,分別從左子樹和右子樹共兩次返回根結點(用tag表示次數), * 只有從右子樹返回時才訪問根結點,因此增長一個棧標記到達結點的次序。 */ while(node!=null||!stack.isEmpty()) { if(node!=null){ stack.push(node); tag.push(1); //第一次訪問 node=node.lchild; }else { if(tag.peek()==2) { System.out.print(stack.pop().data); tag.pop(); }else { tag.pop(); tag.push(2); //第二次訪問 node=stack.peek().rchild; } } } } //=========層序遍歷============ public void levelOrder() { BiTNode<E> node =root; LinkedList<BiTNode<E>> list = new LinkedList<>(); list.add(node); while(!list.isEmpty()) { node=list.poll(); System.out.print(node.data); if(node.lchild!=null) list.offer(node.lchild); if(node.rchild!=null) list.offer(node.rchild); } } public static void main(String[] args) { BiTree<String> aBiTree = new BiTree<String>(); aBiTree.root=new BiTNode<String>("A"); aBiTree.root.lchild=new BiTNode<String>("B"); aBiTree.root.rchild=new BiTNode<String>("C"); aBiTree.root.lchild.rchild=new BiTNode<String>("D"); // BiTree<String> aBiTree = new BiTree<String>(); // aBiTree.root=new BiTNode("A"); // aBiTree.root.lchild=new BiTNode("B"); // aBiTree.root.lchild.lchild=new BiTNode("C"); // aBiTree.root.lchild.lchild.lchild=new BiTNode("D"); // aBiTree.root.lchild.rchild=new BiTNode("E"); // aBiTree.root.lchild.rchild.lchild=new BiTNode("F"); // aBiTree.root.lchild.rchild.lchild.rchild=new BiTNode("G"); // aBiTree.root.lchild.rchild.lchild.rchild.rchild=new BiTNode("H"); System.out.println("————前序————"); aBiTree.preOrder(); aBiTree.preOrder2(); System.out.println("————中序————"); aBiTree.inOrder(); aBiTree.inOrder2(); System.out.println("————後序————"); aBiTree.postOrder(); aBiTree.postOrder2(); System.out.println("————層序遍歷————"); aBiTree.levelOrder(); } }
————前序————
ABDC
ABDC
————中序————
BDAC
BDAC
————後序————
DBCA
DBCA
————層序遍歷————
ABCD
參考:經常使用數據結構算法:二叉樹的遍歷(遞歸和非遞歸)this