二叉樹的前序、中序、後序的非遞歸遍歷實現

一,二叉樹的遍歷html

二叉樹的遞歸遍歷很是簡潔,遞歸調用須要用到棧。所以,要想實現非遞歸遍歷,就相似於模擬程序的自動壓棧、出棧,就須要建立一個棧。java

本程序使用java.util.LinkedList 來表示棧。node

 

二,前序非遞歸遍歷實現算法

先序遍歷是先訪問該結點,再訪問左子樹,而後再訪問右子樹數組

所以,先訪問該結點;而後將該結點入棧。(第10行)dom

而後,不斷遍歷該結點的左孩子(左左孩子....)(第8行while循環),當走到空時(第8行while不成立)。說明最「裏層」的結點的左子樹已經訪問完畢ide

因而,接着訪問它的左子樹中的結點(第15行的 if 語句塊中的第18行)。當找到它的右孩子以後,又按照前面的步驟遍歷左孩子(左左孩子...)(回到第6行的大while循環,首先判斷第8行的while循環)post

第8行的while循環代表:結點還有左孩子...ui

第15行的 if 表示:結點的左孩子爲空了,須要「切換」到右孩子的路徑上去了(再優先訪問 右孩子的 左孩子...)this

 1 private void nonRecurPreTraverse(BinaryNode root){
 2         LinkedList<BinaryNode> stack = new LinkedList<MyBinaryTree.BinaryNode>();
 3         BinaryNode currentNode;
 4         BinaryNode tmp;
 5         currentNode = root;
 6         while(currentNode != null || !stack.isEmpty())
 7         {
 8             while(currentNode != null)//一直往一個方向走
 9             {
10                 System.out.print(currentNode.ele + " ");//visit
11                 stack.push(currentNode);
12                 currentNode = currentNode.left;
13             }
14             
15             if(!stack.isEmpty())//變換方向
16             {
17                 tmp = stack.pop();
18                 currentNode = tmp.right;
19             }
20         }
21     }

 

前序的遞歸實現:(基準條件必定不能忘,這是遞歸的結束條件。)

1     private void preorder(BinaryNode root){
2         if(root == null)
3             return;//base condition
4         System.out.print(root.ele + " ");//visit
5         preorder(root.left);
6         preorder(root.right);
7     }

 

三,中序遍歷的非遞歸實現

先一直沿着「左孩子方向」不斷地走,當走到了最左下結點時(第9行while不成立),準備出棧,訪問該結點。(第15行if語句)

當出棧訪問完該結點(第1八、19行)以後,切換到該結點的左孩子的「子樹」中,回到第6行大循環,與前面同樣,繼續對該「子樹」先沿着「左孩子方向」不斷地走....

 1     private void nonRecurInTraverse(BinaryNode root){
 2         LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>();
 3         BinaryNode currentNode, tmp;
 4         currentNode = root;
 5         
 6         while(currentNode != null || !stack.isEmpty())
 7         {
 8             //先"走完"左孩子
 9             while(currentNode != null)
10             {
11                 stack.push(currentNode);
12                 currentNode = currentNode.left;
13             }
14             //結點沒有左孩子了,出棧,訪問結點
15             if(!stack.isEmpty())
16             {
17                 tmp = stack.pop();
18                 System.out.print(tmp.ele + " ");//visit
19                 currentNode = tmp.right;
20             }
21         }
22     }

 

中序的遞歸遍歷:

1     private void inorder(BinaryNode root){
2         if(root == null)
3             return;
4         inorder(root.left);
5         System.out.print(root.ele + " ");//visit
6         inorder(root.right);
7     }

 

四,後序遍歷的非遞歸實現

後序遍歷的非遞歸實現比前序、中序的非遞歸實現 要複雜一點。須要一個標識來標記某結點是否第一次位於棧頂(該結點的左子樹已經遍歷完畢,從左子樹返回準備遍歷它的右子樹)

對於後序遍歷而言,結點的左右子樹都遍歷完成以後,才訪問該結點。某結點會兩次位於棧頂,第一次是該結點的左子樹都遍歷完了,而後 獲取 棧頂結點,切換到該結點的右孩子,準備遍歷的右子樹,當該結點的右子樹也都遍歷完後,就會第二次位於棧頂,此時將棧頂元素出棧

 1     private void postNonRecurTraverse(BinaryNode root){
 2         LinkedList<BinaryNode> stack = new LinkedList<MyBinaryTree.BinaryNode>();
 3         
 4         BinaryNode currentNode, tmp;
 5         currentNode = root;
 6         while(currentNode != null || !stack.isEmpty())
 7         {
 8             while(currentNode != null)
 9             {
10                 stack.push(currentNode);
11                 currentNode = currentNode.left;
12             }
13             if(!stack.isEmpty())
14             {
15                 tmp = stack.getFirst();
16                 //從左子樹返回,須要判斷它的右子樹是否已經訪問了
17                 if(tmp.isFirst == false)//右子樹還未被訪問
18                 {
19                     tmp.isFirst = true;
20                     currentNode = tmp.right;
21                 }
22                 else{//左右子樹都已經訪問了
23                     tmp = stack.pop();
24                     System.out.print(tmp.ele + " ");//visit
25 //                    currentNode = null;
26                 }
27             }
28         }//while
29     }

 

對於後序遍歷而言,須要判斷某個結點第一次位於棧頂,所以上面方法須要在結點類中添加一個boolean 屬性表示該節點是否第一次位於棧頂。

class BinaryNode{
    BinaryNode left;
    BinaryNode right;
    int ele;
    boolean isFirst; public BinaryNode(int ele)
    {
        this.ele = ele;
        left = right = null;
        isFirst = false;  
     }
}

 

五,整個程序完整實現:

buildTree()方法是根據一維整型數組 隨機構造一棵二叉樹。而後,對該二叉樹進行各類遍歷操做。關於如何構建二叉樹,可參考:二叉查找樹的遞歸實現及遞歸分析

import java.util.LinkedList;
import java.util.Random;


/**
 * 
 * @author psj
 *
 */
public class MyBinaryTree {
    private static final Random rand = new Random();//insert left or right
    
    private static class BinaryNode{
        int ele;
        BinaryNode left;
        BinaryNode right;
        boolean isFirst;
        
        public BinaryNode(int ele) {
            this.ele = ele;
            this.left = this.right = null;
            this.isFirst = false;
        }
    }
    
    private BinaryNode root;//二叉樹的根結點
    
    //隨機構建二叉樹
    public void buildTree(){
        int[] ndoes = {3,0,7,4,9,10,45};
        for (int i : ndoes) {
            insert(i);
        }
    }
    public BinaryNode insert(int ele){
        return root = insert(root, ele);
    }
    private BinaryNode insert(BinaryNode root, int ele){
        if(root == null)
            return root = new BinaryNode(ele);
        if(rand.nextInt() %2 == 0)
            root.left = insert(root.left, ele);
        else
            root.right = insert(root.right, ele);
        return root;
    }
    
    //中序非遞歸遍歷
    public void nonRecurInTraverse(){
        if(root == null)
            return;
        nonRecurInTraverse(root);
    }
    private void nonRecurInTraverse(BinaryNode root){
        LinkedList<BinaryNode> stack = new LinkedList<BinaryNode>();
        BinaryNode currentNode, tmp;
        currentNode = root;
        
        while(currentNode != null || !stack.isEmpty())
        {
            //
            while(currentNode != null)
            {
                stack.push(currentNode);
                currentNode = currentNode.left;
            }
            //
            if(!stack.isEmpty())
            {
                tmp = stack.pop();
                System.out.print(tmp.ele + " ");//visit
                currentNode = tmp.right;
            }
        }
    }
    //中序遞歸遍歷
    public void inorder(){
        inorder(root);
    }
    private void inorder(BinaryNode root){
        if(root == null)
            return;
        inorder(root.left);
        System.out.print(root.ele + " ");//visit
        inorder(root.right);
    }
    //先序非遞歸遍歷
    public void nonRecurPreTraverse(){
        if(root == null)
            return;
        nonRecurPreTraverse(root);
    }
    private void nonRecurPreTraverse(BinaryNode root){
        LinkedList<BinaryNode> stack = new LinkedList<MyBinaryTree.BinaryNode>();
        BinaryNode currentNode;
        BinaryNode tmp;
        currentNode = root;
        while(currentNode != null || !stack.isEmpty())
        {
            while(currentNode != null)
            {
                System.out.print(currentNode.ele + " ");//visit
                stack.push(currentNode);
                currentNode = currentNode.left;
            }
            
            if(!stack.isEmpty())
            {
                tmp = stack.pop();
                currentNode = tmp.right;
            }
        }
    }
    //先序遞歸遍歷
    public void preOrder(){
        preorder(root);
    }
    private void preorder(BinaryNode root){
        if(root == null)
            return;//base condition
        System.out.print(root.ele + " ");//visit
        preorder(root.left);
        preorder(root.right);
    }
    //後序非遞歸遍歷
    public void postNonRecurTraverse(){
        if(root == null)
            return;
        postNonRecurTraverse(root);
    }
    private void postNonRecurTraverse(BinaryNode root){
        LinkedList<BinaryNode> stack = new LinkedList<MyBinaryTree.BinaryNode>();
        
        BinaryNode currentNode, tmp;
        currentNode = root;
        while(currentNode != null || !stack.isEmpty())
        {
            while(currentNode != null)
            {
                stack.push(currentNode);
                currentNode = currentNode.left;
            }
            if(!stack.isEmpty())
            {
                tmp = stack.getFirst();
                //從左子樹返回,須要判斷它的右子樹是否已經訪問了
                if(tmp.isFirst == false)//右子樹還未被訪問
                {
                    tmp.isFirst = true;
                    currentNode = tmp.right;
                }
                else{//左右子樹都已經訪問了
                    tmp = stack.pop();
                    System.out.print(tmp.ele + " ");//visit
//                    currentNode = null;
                }
            }
        }//while
    }
    
    public void postOrder(){
        postOrder(root);
    }
    private void postOrder(BinaryNode root){
        if(root == null)
            return;
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.ele + " ");//visit
    }
    
    public static void main(String[] args) {
        MyBinaryTree mbt =  new MyBinaryTree();
        mbt.buildTree();
        System.out.println("in order");
        mbt.nonRecurInTraverse();
        System.out.println();
        mbt.inorder();
        System.out.println("\npre order");
        mbt.preOrder();
        System.out.println();
        mbt.nonRecurPreTraverse();
        
        System.out.println("\n post order");
        mbt.postOrder();
        System.out.println();
        mbt.postNonRecurTraverse();
        
    }
}
View Code

 

六,二叉查找樹中序遍歷應用

判斷一棵樹,是不是二叉查找樹。採用中序遍歷,若是遍歷是有序的,則是一棵二叉查找樹。代碼以下:

import java.util.LinkedList;
import java.util.List;

public class Solution {

    public boolean isValidBST(TreeNode root) {
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode currentNode,tmp;
//        int currentVal = Integer.MIN_VALUE;
        long currentVal = Long.MIN_VALUE;
        currentNode = root;
        while (currentNode != null || !stack.isEmpty()) {
            while (currentNode != null) {
                stack.push(currentNode);
                currentNode = currentNode.left;
            }

            if (!stack.isEmpty()) {
                tmp = stack.pop();
                if (currentVal >= tmp.val) {
                    return false;
                }else {
                    currentVal = tmp.val;
                }
                currentNode = tmp.right;
            }
        }
        return true;
    }

    public List<Integer> inOrderNonRecurse(TreeNode root, List<Integer> nodes) {
        LinkedList<TreeNode> stack = new LinkedList<>();
        TreeNode currentNode, tmp;
        currentNode = root;
        while (currentNode != null || !stack.isEmpty()) {
            while (currentNode != null) {
                stack.push(currentNode);
                currentNode = currentNode.left;
            }

            if (!stack.isEmpty()) {
                tmp = stack.pop();
                nodes.add(tmp.val);
                currentNode = tmp.right;
            }
        }
        return nodes;
    }


    public List<Integer> inOrder(TreeNode root, List<Integer> nodes) {
        if (root == null) {
            return nodes;
        }
        inOrder(root.left, nodes);
        nodes.add(root.val);
        inOrder(root.right, nodes);
        return nodes;
    }

    public static class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode(int x) {
            val = x;
        }
    }
}

 

參考資料:

JAVA實現二叉樹

二叉樹的建立算法

二叉樹的構造(http://www.cnblogs.com/hapjin/p/5738354.html)

相關文章
相關標籤/搜索