1. 程式人生 > >二叉樹的遍歷方式(遞迴、非遞迴)——Java實現

二叉樹的遍歷方式(遞迴、非遞迴)——Java實現

二叉樹作為一種常用的資料結構,也是面試經常被問到的知識點,瞭解二叉樹的結構和性質也是很有必要的,對於眾多的樹結構,二叉樹只是入門的一種,先把二叉樹理解通透,再深入學習時,會更簡單一些。

二叉樹的性質:

(1) 在非空二叉樹中,第i層的結點總數不超過 , i>=1;

(2) 深度為h的二叉樹最多有 

個結點(h>=1),最少有h個結點;

(3) 對於任意一棵二叉樹,如果其葉結點數為N0,而度數為2的結點總數為N2,則N0=N2+1;

(4) 具有n個結點的完全二叉樹的深度為 (注:[ ]表示向下取整)

(5)有N個結點的完全二叉樹各結點如果用順序方式儲存,則結點之間有如下關係:

若I為結點編號則 如果I>1,則其父結點的編號為I/2;

如果2*I<=N,則其左孩子(即左子樹的根結點)的編號為2*I;若2*I>N,則無左孩子;

如果2*I+1<=N,則其右孩子的結點編號為2*I+1;若2*I+1>N,則無右孩子。

(6)給定N個節點,能構成h(N)種不同的二叉樹。

h(N)為卡特蘭數的第N項。h(n)=C(2*n,n)/(n+1)。

(7)設有i個枝點,I為所有枝點的道路長度總和,J為葉的道路長度總和J=I+2i 

相關術語: 

樹的結點(node):包含一個數據元素及若干指向子樹的分支;

孩子結點(child node):結點的子樹的根稱為該結點的孩子;

雙親結點:B 結點是A 結點的孩子,則A結點是B 結點的雙親;

兄弟結點:同一雙親的孩子結點; 堂兄結點:同一層上結點;

祖先結點: 從根到該結點的所經分支上的所有結點子孫結點:以某結點為根的子樹中任一結點都稱為該結點的子孫結點層:根結點的層定義為1;根的孩子為第二層結點,依此類推;

樹的深度:樹中最大的結點層

結點的度:結點子樹的個數

樹的度: 樹中最大的結點度。

葉子結點:也叫終端結點,是度為 0 的結點;

分枝結點:度不為0的結點;

有序樹:子樹有序的樹,如:家族樹;

無序樹:不考慮子樹的順序;

 看完二叉樹的性質和相關屬於,再來看一下二叉樹的遍歷。二叉樹有很多種遍歷方法,最基本的有三種:

1.前序遍歷:對於下圖二叉樹的前序遍歷結果為:1  2  4  8  9  5  10  3  6  7

2.中序遍歷:對於下圖二叉樹的中序遍歷結果為:8  4  9  2  10  5  1  6  3  7 

3.後序遍歷:對於下圖二叉樹的後 序遍歷結果為:8  9  4  10  5  2  6  7  3  1

一、前序遍歷

基本思想:先訪問根結點,再先序遍歷左子樹,最後再先序遍歷右子樹。

程式碼實現:

遞迴方法

/**
public class TreeNode {
    public int val;
    public TreeNode left;
    public TreeNode right;
    public TreeNode(int val) {
        this.val = val;
    }
}
*/

private void preOrderBinTree(TreeNode root) {
    if (root == null) return;
    System.out.print(root.val + "  ");        //輸出結果  1  2  4  8  9  5  10  3  6  7 
    if (root.left != null)
        preOrderBinTree(root.left);
    if (root.right != null)
        preOrderBinTree(root.right);
}

非遞迴,用棧實現

private void preIterateBinTree(TreeNode root) {
    if(root == null) return;
    Stack<TreeNode> s = new Stack<>();
    TreeNode node = root;
    while (node != null || s.size() > 0) {
        if (node != null) {
            System.out.print(node.val + "  ");
            s.push(node);
            node = node.left;
        } else {
            node = s.pop();
            node = node.right;
        }
    }
}

二、中序遍歷

基本思想:先中序遍歷左子樹,然後再訪問根結點,最後再中序遍歷右子樹即 左—根—右

遞迴方法

private void inOrderBinTree(TreeNode root) {
    if (root == null) return;
    if (root.left != null)
        inOrderBinTree(root.left);
    System.out.print(root.val + "  ");        //輸出 8  4  9  2  10  5  1  6  3  7
    if (root.right != null)
        inOrderBinTree(root.right);
}

非遞迴,用棧實現

private void inIterateBinTree(TreeNode root) {
    if(root == null) return;
    Stack<TreeNode> s = new Stack<>();
    TreeNode node = root;
    while (node != null || s.size() > 0) {
        if (node != null) {
            s.push(node);
            node = node.left;
        } else {
            node = s.pop();
            System.out.print(node.val + "  ");
            node = node.right;
        }
    }
}

三、後序遍歷

基本思想:先後序遍歷左子樹,然後再後序遍歷右子樹,最後再訪問根結點即 左—右—根。

遞迴實現

private void afterOrderBinTree(TreeNode root) {
    if (root == null) return;
    if (root.left != null)
        afterOrderBinTree(root.left);
    if (root.right != null)
        afterOrderBinTree(root.right);
    System.out.print(root.val + "  ");        //輸出 8  9  4  10  5  2  6  7  3  1
}

非遞迴,棧實現

private void afterIterateBinTree(TreeNode root) {
    Stack<TreeNode> stack1 = new Stack<>();
    Stack<Integer> stack2 = new Stack<>();
    int i = 1;
    while(root != null || !stack1.empty()) {
        while (root != null) {
            stack1.push(root);
            stack2.push(0);
            root = root.left;
        }

        while(!stack1.empty() && stack2.peek() == i)
        {
            stack2.pop();
            System.out.print(stack1.pop().val + "  ");
        }

        if(!stack1.empty())
        {
            stack2.pop();
            stack2.push(1);
            root = stack1.peek();
            root = root.right;
        }
    }
}

四、層次遍歷

非遞,佇列歸實現

private void layerIterateBinTree(TreeNode root) {
    if(root == null) return;
    Queue<TreeNode> q = new ArrayDeque<>();
    TreeNode node = root;
    while (node != null || !q.isEmpty()) {
        if (node != null) {
            System.out.print(node.val + "  ");    //輸出 1  2  3  4  5  6  7  8  9  10  
            if(node.left != null)
                q.add(node.left);
            if(node.right != null)
                q.add(node.right);
            node = null;
        } else {
            node = q.remove();
        }
    }
}