【リコウ筆問題】14日目——二分木の話題


二分木の紹介

多くの概念は以前のブログで見ることができます:バイナリ ツリー トラバーサル_Tatakai!!! のブログ - CSDN ブログ_バイナリ ツリー トラバーサル

二分木トラバーサル

  • Preorder トラバーサル: ルート周辺
  • 順序通りのトラバーサル: 左ルート右
  • ポストオーダー トラバーサル: 左右のルート
  • 層順トラバーサル: BFS

実現方法:

  • 再帰
  • 非再帰 (スタック)

1. 再帰的な実装

事前注文トラバーサル

コード

class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        List<Integer> res = new ArrayList<>();
        dfs(root, res);
        return res;
    }
    /**
        前:根左右
     */
    public static void dfs(TreeNode root, List<Integer> res){
    
    
        if(root == null){
    
    // 叶子节点
            return ;
        }
        res.add(root.val);
        dfs(root.left, res);
        dfs(root.right, res);

    }
}

順序通りのトラバーサル

コード

class Solution {
    
    
     List<Integer> ans = new ArrayList<>();
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
        dfs(root);
        return ans;
    }
    // 中序遍历
    public void dfs(TreeNode root){
    
    
        // 结束条件
        if(root == null) return;
        dfs(root.left);
        ans.add(root.val);
        dfs(root.right);
    }
}

ポスト オーダー トラバーサル

コード

class Solution {
    
    
    public List<Integer> postorderTraversal(TreeNode root) {
    
    
        List<Integer> res = new ArrayList<>();
        dfs(root, res);
        return res;
    }
    /**
        后:左右根
     */
    public static void dfs(TreeNode root, List<Integer> res){
    
    
        if(root == null){
    
    // 叶子节点
            return ;
        }
        dfs(root.left, res);
        dfs(root.right, res);
        res.add(root.val);

    }
}

2.反復実装

事前注文トラバーサル

アイデア: スタックを使用して、事前注文トラバーサル プロセスをシミュレートします。これは、スタック (先入れ後出し) であるためです。

  • ルート ノードの最初のスタック
  • スタックが空でない場合、最初に右の子がスタックにプッシュされ、次に左の子がスタックにプッシュされます (後入れ先出し)。

スタック シミュレーション: root left-right -> root right-left

コード

class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        List<Integer> res = new ArrayList<>();
        if(root == null){
    
    
            return res;
        }

        // 前:根左右
        Stack<TreeNode> stk = new Stack<>();
        stk.push(root);
        while(!stk.empty()){
    
    
            TreeNode node = stk.pop();
            res.add(node.val);

            // 右儿子先入栈
            if(node.right != null){
    
    
                stk.push(node.right);
            }
            // 做儿子入队
            if(node.left != null){
    
    
                stk.push(node.left);
            }
        }
        return res;
    }
}

ポスト オーダー トラバーサル

上記の反復法は、事前順序トラバーサルを取得します: 根左右—> 反復プロセスは、根右左の順序でトラバースおよび挿入し、最終的に事前順序トラバーサル ( 根左右)の結果を取得します。

そして、事後順序トラバーサルは であり左右根、その反転は であり、このツリーの根右左順序を取得する方法を見つけるだけでよく根左右、それを反転して後続のトラバーサルの結果を取得します! では、根右左トラバーサル順序の結果を取得するにはどうすればよいでしょうか。——予約注文トラバーサル反復の取得プロセスを模倣します。

  • 根左右⇒重ね順で根右左入手
  • 次に根右左—>積み上げ順で根左取得

コード

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    
    
    public List<Integer> postorderTraversal(TreeNode root) {
    
    
        List<Integer> list = new ArrayList<>();
        if(root == null){
    
    
            return list;
        }

        Stack<TreeNode> stk = new Stack<>();
        stk.push(root);
        // 先获取根右左的遍历次序结果
        while(!stk.empty()){
    
    
            TreeNode node = stk.pop();
            list.add(node.val);

            if(node.left != null){
    
    
                stk.push(node.left);
            }
            if(node.right != null){
    
    
                stk.push(node.right);
            }
        }
        // 翻转得到后序遍历结果
        Collections.reverse(list);
        return list;

    }
}

順序通りのトラバーサル

真ん中:左根右

反復法:

  • ルート ノードへのポインタを定義し、ノードが空でないかスタックが空でない場合はループを続けます

    • ポインターが空でない場合現在のノードがスタックにプッシュされ左の子がループされp指针空を指すまで ------- (左递归プロセスのシミュレーション)
    • ポインターが空の場合、スタックの一番上の要素がポップアウトされ、ポインターはスタックからポップアウトされたノードを指し、p = stk.pop()ノード値がval追加されますans(ルートをたどるプロセスをシミュレートし、回答を記録します)。ポインターはp現在のノードの右の子に移動し (走査プロセスの右の子をシミュレート)、次回に備えます (左ルート右)
  • というように、スタックが空になるまで。

コード

class Solution {
    
    
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
        TreeNode p = root;
        Stack<TreeNode> stk = new Stack<>();
        List<Integer> ans = new ArrayList<>();

        while(p != null || !stk.empty()){
    
    
            while(p != null){
    
    // 模拟一直左递归的过程
                stk.push(p);
                p = p.left;
            }
            // p走到了空
            // 根
            p = stk.pop();
            ans.add(p.val);
            
            // 右
            p = p.right;
        }
        return ans;
    }
}

おすすめ

転載: blog.csdn.net/qq_54773252/article/details/127170789