2叉數的遍歷

該文主要介紹2叉數的基本遍歷的實現,在此以前,首先應該知道2叉數有哪些遍歷?java


先序遍歷:根-->左-->右    即先訪問根結點,而後訪問左子樹,最後訪問右子樹。在遍歷左、右子樹時,仍然如此。node

上圖遍歷結果:A,B,D,E,C,F,G。數據結構

中序遍歷:左-->根-->右    即先訪問左子樹,而後訪問根結點,最後訪問右子樹。在遍歷左、右子樹時,仍然如此。post

上圖遍歷結果:D,B,E,A,F,C,G。測試

後序遍歷:左-->右-->根    即先訪問左子樹,而後訪問右子樹,最後訪問根結點。在遍歷左、右子樹時,仍然如此。this

上圖遍歷結果:D,E,B,F,G,C,A。spa

層次遍歷:1層,2層,3層,依次訪問下來,若是某一層元素超過兩個,那麼從先左後右訪問。code

上圖遍歷結果:A,B,C,D,E,F,G。(這個已經簡單不行了)遞歸

深度遍歷:首先訪問根結點(A),而後沿着它的左結點依次訪問(B,D),至到訪問到最後一層(也就是D),再返回到它的父親(B),訪問他的右結點(E)。而後這樣重複地訪問完全部結點。隊列

上圖遍歷結果:A,B,D,E,C,F,G。

備註:

    1.上面的先、中、後序遍歷,主要看的就是根在訪問順序中所在的位置。「根左右」,根在前,因此叫先序遍歷。「左根右」,根在中,因此叫中序遍歷。

    2.在中序遍歷中,有一種很快得出其遍歷的結果的方法。叫作投影法。(你覺得我會把這個方法的連接放在這裏麼?No,我只會告訴你,請百度百科「中序遍歷」,這裏有我想給你看的「投影法」。)

如何實現

    先序遍歷:首先訪問根,而後遞歸訪問左子樹,再遞歸訪問右子樹便可。

    中/後序遍歷:相似於先序遍歷。等下看源碼就明白了。

層次遍歷

    首先將根入隊列(先進先出),而後就循環判斷這個隊列是否爲空。只要隊列不爲空,就取出隊列中的一個結點,訪問這個結點的值,再將這個結點的左結點入隊列,再將這個隊列的右結點入隊列。

層次遍歷詳細解釋

    以上圖的2叉數爲例,首先將根A結點入隊列,如今用while來循環判斷隊列是否爲空。很明顯,不爲空。因此取出隊列中的結點(A)來訪問,而後,這個結點(A)的左結點(B)不爲空,入隊列,這個結點的右結點(C)也不爲空,入隊列。因此如今隊列中就又有了B、C兩個結點,因此循環繼續。拿出B,訪問B,再將B的左右結點D、E入隊列。如今隊列中就有了C、D、E了。隊列不爲空,因此循環繼續,拿出C,訪問C,再將F,G入隊列。如今隊列中就是D、E、F、G了。隊列不爲空,拿出D訪問,D沒有子結點,那麼沒有新的結點入隊列,但隊列尚未爲空,因此接着拿出E來訪問,E也沒有子結點,因此也沒有新的結點入隊列,但隊列尚未爲空,接着再拿隊列中的F來訪問,依次類推了。(寫得很羅嗦,但願能把這個過程解釋清楚。)

深度遍歷

     首先將根入棧(先進後出),而後就循環判斷這個棧是否爲空。只要棧不爲空,就取出棧中的一個結點,訪問這個結點的值,再將這個結點的右結點入棧,再將這個結點的左結點入棧。(很相似於層次遍歷的實現,只是所用的數據結構由隊列變成了棧,入隊列是先左後右,入棧的順序是先右後左)

深度遍歷詳細解釋

    這個很相似於層次遍歷的詳細解釋,我簡單得說一下。首先根A入棧,而後循環判斷棧是否爲空,如今棧裏有結點A,因此不爲空,因此取出A,訪問A,將C、B入棧(也就是將A的右結點入棧,而後左結點入棧,和層次遍歷時是相反的)。再判斷棧是否爲空,如今棧中有C、B。因爲棧是後進先出的結構,因此這裏是B彈出棧,訪問B,再將B的子結點E、D入棧,那現棧中就有了C、E、D。判斷棧不空,又彈出D,訪問D,將D的子結點入棧。這樣類推下去,就完成了遍歷。

java代碼以下:(有點多,不過該代碼可測試運行)

package com.cdu.binaryTree;

import java.util.LinkedList;

public class MyBinaryTree {
    public static void main(String[] args) {
        //初始化一棵2叉數
        BinaryTree binaryTree = BinaryTree.initBinaryTree();

        // 先序遍歷
        System.out.println("先序遍歷:");
        binaryTree.preOrderTraversal(binaryTree);
        System.out.println("\n");
        
        // 中序遍歷
        System.out.println("中序遍歷:");
        binaryTree.midOrderTrversal(binaryTree);
        System.out.println("\n");
        
        // 後序遍歷
        System.out.println("後序遍歷:");
        binaryTree.postOrderTrversal(binaryTree);
        System.out.println("\n");
        
        // 層次遍歷
        System.out.println("層次遍歷:");
        binaryTree.levelTraversal(binaryTree);
        System.out.println("\n");
        
        // 深度遍歷
        System.out.println("深度遍歷:");
        binaryTree.depthTraversal(binaryTree);
        System.out.println("\n");
    }
}

class BinaryTree{
    private int data;                    //結點值 
    private BinaryTree left;             //左子結點
    private BinaryTree right;            //右子結點
    
    public BinaryTree(int data){
        this.data = data;
    }
    
    /**
     * @Description 初始化二叉數
     * @param 
     * @return 獲得以下所示的二叉數
     *                             1
     *                          *      *
     *                     2                3
     *                  *   *               *   *    
     *                 4       5          6        7
     *                  *     * *
     *                   9   10 11
     *                       *    
     *                      8
     * 
     * 先序遍歷結果:1,2,4,9,5,10,8,11,3,6,7
     * 中序遍歷結果:4,9,2,8,10,5,11,1,6,3,7
     * 後序遍歷結果:9,4,8,10,11,5,2,6,7,3,1
     * 層次遍歷結果:1,2,3,4,5,6,7,9,10,11,8
     * 深度遍歷結果:1,2,4,9,5,10,8,11,3,6,7
     */
    public static BinaryTree initBinaryTree(){
        BinaryTree root = new BinaryTree(1);
        BinaryTree node2 = new BinaryTree(2);
        BinaryTree node3 = new BinaryTree(3);
        BinaryTree node4 = new BinaryTree(4);
        BinaryTree node5 = new BinaryTree(5);
        BinaryTree node6 = new BinaryTree(6);
        BinaryTree node7 = new BinaryTree(7);
        BinaryTree node8 = new BinaryTree(8);
        BinaryTree node9 = new BinaryTree(9);
        BinaryTree node10 = new BinaryTree(10);
        BinaryTree node11 = new BinaryTree(11);
        
        root.setLeft(node2);
        root.setRight(node3);
        
        node2.setLeft(node4);
        node2.setRight(node5);
        
        node3.setLeft(node6);
        node3.setRight(node7);
        
        node4.setRight(node9);
        
        node5.setLeft(node10);
        node5.setRight(node11);
        
        node10.setLeft(node8);
        
        return root;
    }
    
    /**
     * @Description 先序遍歷
     * @param binaryTree 二叉數
     * @return
     */
    public void preOrderTraversal(BinaryTree binaryTree){
        // 當2叉數爲空時,遞歸結束。
        if (binaryTree == null){
            return ;
        }else{
            System.out.print(binaryTree.getData() + ",");            //訪問結點
            preOrderTraversal(binaryTree.getLeft());                 //遞歸遍歷左子樹
            preOrderTraversal(binaryTree.getRight());                //遞歸遍歷右子樹
        }
    }
    
    /**
     * @Description 中序遍歷
     * @param binaryTree 二叉數
     * @return
     */
    public void midOrderTrversal(BinaryTree binaryTree){
        if (binaryTree == null){
            return ;
        }else{
            midOrderTrversal(binaryTree.getLeft());
            System.out.print(binaryTree.getData() + ",");
            midOrderTrversal(binaryTree.getRight());
        }
    }
    
    /**
     * @Description 後序遍歷
     * @param binaryTree 二叉數
     * @return
     */
    public void postOrderTrversal(BinaryTree binaryTree){
        if (binaryTree == null){
            return ;
        }else{
            postOrderTrversal(binaryTree.getLeft());
            postOrderTrversal(binaryTree.getRight());
            System.out.print(binaryTree.getData()+ ",");
        }
    }
    
    /**
     * @Description 層次遍歷:先將根節點入隊列,而後判斷只要隊列不爲空,
     *         那麼就從隊列中poll一個結點來訪問,而後再將該結點的左結點入隊列,而後再將右結點入隊列
     * @param 
     * @return
     */
    public void levelTraversal(BinaryTree binaryTree){
        LinkedList<BinaryTree> queue = new LinkedList<BinaryTree>();
        if (binaryTree != null){
            queue.offer(binaryTree);
        }
        
        // 只要隊列不爲空,則遍歷隊列中結點
        while (!queue.isEmpty()){
            BinaryTree node = queue.poll();
            System.out.print(node.getData() + ",");
            
            // 若結點有子結點,那麼將該結點的左、右結點存入隊列
            if (node.getLeft() != null){
                queue.offer(node.getLeft());
            }
            if (node.getRight() != null){
                queue.offer(node.getRight());
            }
        }
    }
    
    /**
     * @Description 深度遍歷:先將根節點入隊列,而後判斷只要棧不爲空,
     *         那麼就在棧中pop一個結點來訪問,而後再將該結點的右結點壓棧,而後再將左結點壓棧
     * @param 
     * @return
     */
    public void depthTraversal(BinaryTree binaryTree){
        LinkedList<BinaryTree> stack = new LinkedList<BinaryTree>();
        if (binaryTree != null){
            stack.push(binaryTree);
        }
        
        // 只要棧不爲空,則遍歷棧中結點
        while(!stack.isEmpty()){
            BinaryTree node = stack.pop();
            System.out.print(node.getData() + ",");
            
            // 若結點有子結點,那麼將該結點的右、左結點存入隊列
            if (node.getRight() != null){
                stack.push(node.getRight());
            }
            if (node.getLeft() != null){
                stack.push(node.getLeft());
            }
        }
    }
    
    /*--------------getter and setter--------------------*/
    
    public int getData() {
        return data;
    }
    public void setData(int data) {
        this.data = data;
    }
    public BinaryTree getLeft() {
        return left;
    }
    public void setLeft(BinaryTree left) {
        this.left = left;
    }
    public BinaryTree getRight() {
        return right;
    }
    public void setRight(BinaryTree right) {
        this.right = right;
    }
}
相關文章
相關標籤/搜索