標籤:
import java.util.Stack;//二叉樹三種遍曆遞迴及非遞迴實現(Java)public class Traverse {/******************定義二叉樹**************************/private final int MAX_SIZE = 10; //鏈式儲存public static class BinaryTreeNode{int mValue;BinaryTreeNode mLeft;BinaryTreeNode mRight;public BinaryTreeNode(int mValue) {this.mValue = mValue;}}//順序儲存class BinaryTreeNode2{int[] data = new int[MAX_SIZE];int length;}//用以實現後續遍曆的輔助結構private class HelpNode{BinaryTreeNode treeNode;boolean isFirst;}/******************遞迴實現***************************///先序遍曆public int PreOrderTreeWalk(BinaryTreeNode pNode){if(pNode == null)return 0;visitNode(pNode);PreOrderTreeWalk(pNode.mLeft);PreOrderTreeWalk(pNode.mRight);return 1;}//中序遍曆public int InOrderTreeWalk(BinaryTreeNode pNode){if(pNode == null)return 0;InOrderTreeWalk(pNode.mLeft);visitNode(pNode);InOrderTreeWalk(pNode.mRight);return 1;}//後序遍曆public int PostOrderTreeWalk(BinaryTreeNode pNode){if(pNode == null)return 0;PostOrderTreeWalk(pNode.mLeft);PostOrderTreeWalk(pNode.mRight);visitNode(pNode);return 1;}/*****************非遞迴實現***********************///先序遍曆public int PreOrderTraverse(BinaryTreeNode pNode){Stack<BinaryTreeNode> stack = new Stack<>();if(pNode == null)return 0;while(!stack.isEmpty()||pNode != null){while(pNode != null){//先訪問visitNode(pNode);stack.push(pNode);//遍曆左節點pNode = pNode.mLeft;}//返回頂層元素pNode = stack.peek();stack.pop();//遍曆右節點pNode = pNode.mRight;}return 1;}//先序遍曆實現方法二public int PreOrderTraverse2(BinaryTreeNode pNode){if(pNode == null)return 0;Stack<BinaryTreeNode> stack = new Stack<>();stack.push(pNode);while(!stack.isEmpty()){pNode = stack.pop();visitNode(pNode);if(pNode.mRight != null)stack.push(pNode.mRight);if(pNode.mLeft != null)stack.push(pNode.mLeft);}return 1;}//中序遍曆public int InOrderTraverse(BinaryTreeNode pNode){Stack<BinaryTreeNode> stack = new Stack<>();if(pNode == null)return 0;while(!stack.isEmpty()||pNode != null){while(pNode!=null){stack.push(pNode);pNode = pNode.mLeft;}pNode = stack.pop();visitNode(pNode);pNode = pNode.mRight;}return 1;}//後序遍曆,用一個標記標記右子樹是否訪問過 /* * 第一種思路:對於任一結點P,將其入棧,然後沿其左子樹一直往下搜尋,直到搜尋到沒有左孩子的結點, * 此時該結點出現在棧頂,但是此時不能將其出棧並訪問,因此其右孩子還為被訪問。所以接下來按照相同 * 的規則對其右子樹進行相同的處理,當訪問完其右孩子時,該結點又出現在棧頂,此時可以將其出棧並訪 * 問。這樣就保證了正確的訪問順序。可以看出,在這個過程中,每個結點都兩次出現在棧頂,只有在第二 * 次出現在棧頂時,才能訪問它。因此需要多設定一個變數標識該結點是否是第一次出現在棧頂。 * */public int PostOrderTraverse(BinaryTreeNode pNode){if(pNode == null)return 0;Stack<HelpNode> stack = new Stack<>();HelpNode helpNode;while(!stack.isEmpty() || pNode != null){//一直迴圈至最左節點while(pNode != null){HelpNode temp = new HelpNode();temp.treeNode = pNode;temp.isFirst = true;stack.push(temp);pNode = pNode.mLeft;}if(!stack.isEmpty()){helpNode = stack.pop();if(helpNode.isFirst)//表示第一次,即每一個要被訪問的根節點要被push兩次{helpNode.isFirst = false;stack.push(helpNode);pNode = helpNode.treeNode.mRight;//右節點的是否有效則移至迴圈的開始出進行判斷}else {visitNode(helpNode.treeNode);pNode = null;}}}return 1;}//後序遍曆實現方法二:雙棧法public int PostOrderTraverse2(BinaryTreeNode pNode){if(pNode == null)return 0;Stack<BinaryTreeNode> stack1 = new Stack<>();Stack<BinaryTreeNode> stack2 = new Stack<>();//輔助棧//存入根節點,初始化stack1.push(pNode);//stack1彈出的元素,壓入stack2,在將該元素的左右節點壓入stack1while(!stack1.isEmpty()){pNode = stack1.pop();stack2.push(pNode);if(pNode.mLeft != null){stack1.push(pNode.mLeft);}if(pNode.mRight != null){stack1.push(pNode.mRight);}}//stack彈出的即是後序遍曆的順序while(!stack2.isEmpty()){visitNode(stack2.pop());}return 1;}//後序遍曆實現方法三/* * 第二種思路:要保證根結點在左孩子和右孩子訪問之後才能訪問,因此對於任一結點P,先將其入棧。 * 如果P不存在左孩子和右孩子,則可以直接存取它;或者P存在左孩子或者右孩子,但是其左孩子和右 * 孩子都已被訪問過了,則同樣可以直接存取該結點。若非上述兩種情況,則將P的右孩子和左孩子依次 * 入棧,這樣就保證了每次取棧頂元素的時候,左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點 * 前面被訪問。 * *///後序遍曆實現方法二:雙棧法public int PostOrderTraverse3(BinaryTreeNode pNode){if(pNode == null)return 0;BinaryTreeNode preVisitedNode = null;Stack<BinaryTreeNode> stack = new Stack<>();stack.push(pNode);while(!stack.isEmpty()){pNode = stack.peek();if((pNode.mLeft == null && pNode.mLeft == null)//左右子樹均為空白的情況,即葉子節點||(preVisitedNode != null && (preVisitedNode == pNode.mLeft || preVisitedNode == pNode.mRight)))//左右子樹已經被訪問的情況{visitNode(pNode);preVisitedNode = stack.pop();}else {if(pNode.mRight != null)stack.push(pNode.mRight);//注意push的順序,先訪問右子樹if(pNode.mLeft != null)stack.push(pNode.mLeft);}}return 1;}/*********輔助函數**********///訪問節點資料private void visitNode(BinaryTreeNode treeNode){System.out.print(treeNode.mValue);System.out.print("、");}public static void main(String[] args){/************************構造測試二叉樹鏈表組***********************/int[] data = {1,2,3,4,5,6,7,8,9,10};BinaryTreeNode[] treeNodes = new BinaryTreeNode[data.length];for(int i = 0; i < data.length; i++){treeNodes[i] = new BinaryTreeNode(data[i]);}for(int i = 0; i < (data.length/2); i ++){treeNodes[i].mLeft = treeNodes[(i + 1)*2 - 1];if(((i + 1) *2) < data.length){treeNodes[i].mRight = treeNodes[(i + 1)*2];}}Traverse traverse = new Traverse();BinaryTreeNode root = treeNodes[0];System.out.print("先序遍曆遞迴: ");traverse.PreOrderTreeWalk(root);System.out.println();System.out.print("先序遍曆非遞迴一:");traverse.PreOrderTraverse(root);System.out.println();System.out.print("先序遍曆非遞迴二:");traverse.PreOrderTraverse2(root);System.out.println();System.out.print("中序遍曆遞迴: ");traverse.InOrderTreeWalk(root);System.out.println();System.out.print("中序遍曆遞迴: ");traverse.InOrderTraverse(root);System.out.println();System.out.print("後序遍曆遞迴: ");traverse.PostOrderTreeWalk(root);System.out.println();System.out.print("後序遍曆非遞迴一:");traverse.PostOrderTraverse(root);System.out.println();System.out.print("後序遍曆非遞迴二:");traverse.PostOrderTraverse2(root);System.out.println();System.out.print("後序遍曆非遞迴三:");traverse.PostOrderTraverse3(root);System.out.println();/******************驗證輸出***********************///for(BinaryTreeNode treeNode : treeNodes)//{//System.out.print("根節點");//System.out.println(treeNode.mValue);//System.out.print("左節點");//if(treeNode.mLeft != null)//{//System.out.println(treeNode.mLeft.mValue);//}//else //{//System.out.println("null");//}////System.out.print("右節點");//if(treeNode.mRight != null)//{//System.out.println(treeNode.mRight.mValue);//}//else //{//System.out.println("null");//}//System.out.println();//}}}
二叉樹三種遍曆遞迴及非遞迴實現(Java)