【二叉樹的遍歷-1】前序遍歷(遞歸與非遞歸)

【二叉樹的遍歷-2】中序遍歷(遞歸與非遞歸)
【二叉樹的遍歷-3】後序遍歷(遞歸與非遞歸)
【二叉樹的遍歷-4】層序遍歷

本篇主要是二叉樹的遍歷的簡介和前序遍歷的代碼實現,另外幾種遍歷方式見上面鏈接

二叉樹的遍歷

關於二叉樹的遍歷,百度百科是這樣說的:

所謂遍歷(Traversal)是指沿着某條搜索路線,依次對樹中每個結點均做一次且僅做一次訪問。訪問結點所做的操作依賴於具體的應用問 題。 遍歷是二叉樹上最重要的運算之一,是二叉樹上進行其它運算之基礎。

遍歷方式主要有四種:

1.前序遍歷:根結點 --> 左子樹 --> 右子樹
2.中序遍歷:左子樹–> 根結點 --> 右子樹
3.後序遍歷:左子樹–> 右子樹 --> 根結點
4.層序遍歷:從上到下,從左到右一層一層的遍歷

前面三種其實很好記,可以想象成只是把根的訪問次序移了一下。

看一個具體的實例:
在這裏插入圖片描述
前序遍歷結果:A BDEH CFG
中序遍歷結果:DBEH A FCG
後序遍歷結果:DHEB FGC A
層序遍歷結果:A BC DEFG H

前序遍歷代碼實現

前序遍歷(DLR),也叫做先根遍歷、先序遍歷、前序周遊,遍歷次序可記做根左右。首先訪問根結點然後遍歷左子樹,最後遍歷右子樹。

記住一點:根結點 --> 左子樹 --> 右子樹

遞歸方式:

對於遞歸過程我們其實不需要太在意,主要是要想清楚讓計算機幹什麼。計算機都可能溢出,用人腦去遍歷就更不太可能了。
比如這個先序遍歷,我們要先打印頭節點對吧?那我打印完了頭節點,然後再打印左節點,再打印右節點。然後我們就只用告訴計算機我想先打印當前節點,再打印左邊結點,之後再打印右邊結點就可以了。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class BinaryTree {     
    public void preorderTraversal(TreeNode root) {
        if(root != null) {
            System.out.println(root.val); //每次遍歷都打印當前節點,然後再去打印左右子樹節點,至於左右子樹再怎麼向下遞歸打印我們就不care了
            preorderTraversal(root.left);  //遞歸調用,遍歷左子樹,打印左子樹的節點
            preorderTraversal(root.right); //遞歸調用遍歷右子樹,打印左子樹節點
        }
    }
}

非遞歸方式:

迭代解法本質上也是在模擬遞歸,因爲在遞歸的過程中使用了系統棧,所以在迭代的解法中常用Stack來模擬系統棧。

具體思路:
1.先創建一個Stack用來存放節點;
2.由於前序遍歷先打印根節點,所以先將根節點入棧,然後打印;
3.然後由於我們想先打印左子樹節點,然後右子樹節點。根據棧先入後出的特性,先加入棧的就應該是右子樹,然後左子樹。

代碼如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class BinaryTree {
    public void preorderTraversal(TreeNode root) {
        if(root == null) {     //空樹直接返回,就不用遍歷了
            return;
        }
        Stack<TreeNode> s = new Stack<>();
        s.push(root); //根節點入棧
        while(!s.empty()) {    //循環條件:棧不爲空,因爲棧不爲空說明每遍歷完
            TreeNode cur = s.pop();    //此時棧頂保存的就是根節點,由於前序遍歷先打印根節點,所以先將根節點出棧,
            System.out.println(cur.val);  //打印根節點
            //由於棧先進後出特性,所以想先打印左子樹節點,就將右子樹節點先入棧
            if(cur.right != null) {  
                s.push(cur.right);
            } 
            if(cur.left != null) {
                s.push(cur.left);
            }
        }
    }
}

附leetcode前序非遞歸遍歷代碼

題目鏈接點擊直達

代碼如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class  Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> ret = new ArrayList<>();
        if(root == null) {
            return ret;
        }
        Stack<TreeNode> s = new Stack<>();
        s.push(root);
        while(!s.empty()) {
            TreeNode cur = s.pop();
            ret.add(cur.val);
            if(cur.right != null) {
                s.push(cur.right);
            } 
            if(cur.left != null) {
                s.push(cur.left);
            }
        }
        return ret;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章