後續遍歷--遞迴與非遞迴(java版)
阿新 • • 發佈:2018-11-24
先訪問左右孩子,再訪問根節點。同樣還是採用棧的形式,但是問題是,先訪問左孩子出棧,根節點不能刪除,再訪問右孩子出棧,最後訪問根節點出棧。我們的思路是這樣的:
對於某個節點p:
1)將p壓入棧中,並將p所有的左孩子,全部壓入棧中:
while(stk.isEmpty() == false) { if(p!=null && p.left!=null) { stk.add(p.left); p = p.left; }else ..... }
2)將棧頂元素彈出,訪問。如果沒有右孩子,棧頂元素繼續出棧。如果有右孩子,將右孩子壓入棧中,pVisit標記其右孩子,表示已經訪問過了。當右孩子訪問過之後,回到 1 節點(如下圖),p.right = pVisit,表示右節點已經訪問過了。
4)直到stack.isEmpty == true,則遍歷結束;
需要一個輔助節點pRight,它專門指向已經訪問過的右節點,例如(結合程式看):
import java.util.Stack; class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } public class Main { //遞迴求解 public static void postOrder(TreeNode root) { if(root == null)return; postOrder(root.left); postOrder(root.right); System.out.print(root.val +" "); } //非遞迴求解 public static void postOrder2(TreeNode root) { if(root == null)return; TreeNode p = root; TreeNode pVisit = null; Stack<TreeNode> stk = new Stack<TreeNode>(); stk.add(p); while(stk.isEmpty() == false) { //只要你有左孩子,就將左孩子壓入棧中 if(p!=null && p.left!=null) { stk.add(p.left); p = p.left; }else { p = stk.peek();//棧頂元素,先出棧,可能還有右孩子 if(p.right==null || p.right==pVisit) {//如果沒有右孩子或右孩子已經訪問過了,出棧 System.out.print(p.val+" "); pVisit = p;//這個很重要,考慮一下只有右孩子的樹,得不斷的回溯 p = null;//沒有新節點加入,繼續進行出棧操作 stk.pop(); }else {//如果有右孩子,右孩子入棧 pVisit = p.right; stk.add(p.right); p = p.right; } } } } public static void main(String[] args) { // TODO Auto-generated method stub TreeNode root = new TreeNode(1); root.left = new TreeNode(2); root.right = new TreeNode(3); root.left.left = new TreeNode(4); root.left.right = new TreeNode(5); root.right.left = new TreeNode(6); root.right.right = new TreeNode(7); postOrder2(root); } }