一看就會,二叉樹的創建和三種遍歷--前序、中序、後序(附java代碼實現)

轉載自原文

一、易懂的形象理解

其實從名字就可以很好的理解這三種遍歷,我在第二點時候說,但是估計能翻到我的文的同學們之前肯定看過好多類似的了,那咱們換個思路~ 先用我想的一種簡單易懂的形象思維理解一下前序、中序、後序 +層序!

1、先序遍歷

先序遍歷可以想象成,小人從樹根開始繞着整棵樹的外圍轉一圈,經過結點的順序就是先序遍歷的順序
先序遍歷結果:ABDHIEJCFKG
在這裏插入圖片描述
讓我們來看下動畫,和小人兒一起跑兩遍就記住啦,記住是繞着外圍跑哦
在這裏插入圖片描述
在這裏插入圖片描述

2、中序遍歷

中序遍歷可以想象成,按樹畫好的左右位置投影下來就可以了
中序遍歷結果:HDIBEJAFKCG
中序遍歷
下面看下投影的過程動畫,其實就是按左右順序寫下來就行了
在這裏插入圖片描述

3、後序遍歷

後序遍歷就像是剪葡萄,我們要把一串葡萄剪成一顆一顆的。
還記得我們先序遍歷繞圈的路線麼?
就是圍着樹的外圍繞一圈,如果發現一剪刀就能剪下的葡萄(必須是一顆葡萄),就把它剪下來,組成的就是後序遍歷了。
後序遍歷結果:HIDJEBKFGCA
在這裏插入圖片描述
讓我們來看下動畫
在這裏插入圖片描述

4、層序遍歷

層序遍歷太簡單了,就是按照一層一層的順序,從左到右寫下來就行了。
後序遍歷結果:ABCDEFGHIJK
在這裏插入圖片描述

不知道通過這種方式,有沒有覺得閉着眼睛都能寫出前序、中序、後序 、層序了呀,不過這只是爲了大家好理解,我想出的一種形象思維,爲了用代碼實現,我們還需要具體瞭解一下前序、中序、後序遍歷。

二、真正理解三種遍歷

來,讓我們先把所有空結點都補上。
還記得我們先序和後序遍歷時候跑的順序麼?按照這個順序再跑一次,就是圍着樹的外圍跑一整圈
讓我們來理解一下繞着外圍跑一整圈的真正含義是:遍歷所有結點時,都先往左孩子走,再往右孩子走。
在這裏插入圖片描述
觀察一下,你有什麼發現?
有沒有發現,除了根結點和空結點,其他所有結點都有三個箭頭指向它。
一個是從它的父節點指向它,一個是從它的左孩子指向它,一個是從它的右孩子指向它
一個結點有三個箭頭指向它,說明每個結點都被經過了三遍。一遍是從它的父節點來的時候,一遍是從它的左孩子返回時,一遍是從它的右孩子返回時

其實我們在用遞歸算法實現二叉樹的遍歷的時候,不管是先序中序還是後序,程序都是按照上面那個順序跑遍所有結點的
先序中序和後序唯一的不同就是,在經過結點的三次中,哪次訪問(輸出或者打印或者做其他操作)了這個結點。有點像大禹治水三過家門,他會選擇一次進去。
先序遍歷顧名思義,就是在第一次經過這個結點的時候訪問了它。就是從父節點來的這個箭頭的時候,訪問了它。
中序遍歷也和名字一樣,就是在第二次經過這個結點的時候訪問了它。就是從左孩子返回的這個箭頭的時候,訪問了它。
後序遍歷,就是在第三次經過這個結點的時候訪問了它。就是從右孩子返回的這個箭頭的時候,訪問了它。

怎麼樣,這樣有沒有很好的理解?其實不管是前序中序還是後序,在程序裏跑的時候都是按照同樣的順序跑的,每個結點經過三遍,第幾遍訪問這個結點了,就叫什麼序遍歷。
當我們腦子裏有這個概念的時候, 再去看實現代碼就很好理解了,下一篇博文我會貼出和講解具體的實現代碼。

三、代碼實現

需求:把一個數組生成一個二叉樹,並打印前序、中序、後序的結果。
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
這個數組生成的二叉樹如下:
在這裏插入圖片描述
創建個java文件叫:TreeNode.java,內容如下,可直接複製使用

public class TreeNode {
    private int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    private static List<Node> nodeList = null;

    //內部類 結點
    private static class Node {
        Node leftChild;
        Node rightChild;
        int data;

        //構造方法初始化
        Node(int newData) {
            leftChild = null;
            rightChild = null;
            data = newData;
        }
    }

    public void createBinTree() {
        if (array.length > 0) {
            nodeList = new LinkedList<Node>();
            // 將一個數組的值依次轉換爲Node節點
            for (int nodeIndex = 0; nodeIndex < array.length; nodeIndex++) {
                nodeList.add(new Node(array[nodeIndex]));
            }
            // 對前lastParentIndex-1個父節點按照父節點與孩子節點的數學關係建立二叉樹
            for (int parentIndex = 0; parentIndex < array.length / 2 - 1; parentIndex++) {
                // 左孩子
                nodeList.get(parentIndex).leftChild = nodeList.get(parentIndex * 2 + 1);
                // 右孩子
                nodeList.get(parentIndex).rightChild = nodeList.get(parentIndex * 2 + 2);
            }
            // 最後一個父節點:因爲最後一個父節點可能沒有右孩子,所以單獨拿出來處理
            int lastParentIndex = array.length / 2 - 1;
            // 最後一個節點的左孩子
            if (array.length != 1) {
                nodeList.get(lastParentIndex).leftChild = nodeList.get(lastParentIndex * 2 + 1);
            }
            // 最後一個節點的右孩子,如果數組的長度爲奇數並且不止一個節點才建立右孩子
            if (array.length != 1 && array.length % 2 == 1) {
                nodeList.get(lastParentIndex).rightChild = nodeList.get(lastParentIndex * 2 + 2);
            }

        }
    }

    /**
     * 先序遍歷
     */
    public static void preOrderTraverse(Node node) {
        if (node == null)
            return;
        System.out.print(node.data + " ");
        preOrderTraverse(node.leftChild);
        preOrderTraverse(node.rightChild);
    }

    /**
     * 中序遍歷
     */
    public static void inOrderTraverse(Node node) {
        if (node == null)
            return;
        inOrderTraverse(node.leftChild);
        System.out.print(node.data + " ");
        inOrderTraverse(node.rightChild);
    }

    /**
     * 後序遍歷
     */
    public static void postOrderTraverse(Node node) {
        if (node == null)
            return;
        postOrderTraverse(node.leftChild);
        postOrderTraverse(node.rightChild);
        System.out.print(node.data + " ");
    }

    public static void main(String[] args) {
        TreeNode binTree = new TreeNode();
        binTree.createBinTree();
        // nodeList中第0個索引處的值即爲根節點
        Node root = nodeList.get(0);
        System.out.println("先序遍歷:");
        preOrderTraverse(root);
        System.out.println();
        System.out.println("中序遍歷:");
        inOrderTraverse(root);
        System.out.println();
        System.out.println("後序遍歷:");
        postOrderTraverse(root);
    }
}

運行結果:

先序遍歷:
1 2 4 8 9 5 3 6 7 
中序遍歷:
8 4 9 2 5 1 6 3 7 
後序遍歷:
8 9 4 5 2 6 7 3 1 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章