順番通りの走査はどのように実行されるのでしょうか?

醉折花枝作酒筹
リリース: 2021-06-18 15:36:29
オリジナル
8506 人が閲覧しました

インオーダートラバーサルのトラバーサル方法は次のとおりです。現在のノードについては、最初に左側のサブツリーをトラバースし、次に現在のノードにアクセスし、最後に右側のサブツリーをトラバースします。インオーダートラバーサルはバイナリツリートラバーサルの一種で、ミッドルートトラバーサルやインオーダーツアーとも呼ばれます。

順番通りの走査はどのように実行されるのでしょうか?

このチュートリアルの動作環境: Windows 7 システム、C 17 バージョン、Dell G3 コンピューター。

二分木は重要なデータ構造であり、二分木を走査することも非常に重要です。ここでは、バイナリ ツリーを順番に走査する 3 つの方法を簡単に紹介します。バイナリ ツリーの順序トラバースでは、最初に左側のサブツリーをトラバースし、次に現在のノードにアクセスし、最後に右側のサブツリーをトラバースします。次のバイナリ ツリーの場合、順序トラバーサルの結果は次のようになります:


Result: [5,10,6,15,2]

直感的にわかるように、バイナリ ツリーの順序トラバーサルは、ノードを水平座標に投影することです。図に示すように:


1. 再帰的メソッド

これは最も単純なメソッドであり、考えやすく、実装も簡単です。再帰の終了条件は、現在のノードが空かどうかです。最初に再帰呼び出しは左側のサブツリーをたどり、次に現在のノードにアクセスし、最後に右側のサブツリーが再帰的に呼び出されます。コードは次のとおりです:

//recursive
class Solution1 {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;
        if(root==NULL)return ret;
        inorderHelper(ret,root);
        return ret;
    }
private:
    void inorderHelper(vector<int>& ret,TreeNode* root)
    {
        if(root==NULL)return;
        inorderHelper(ret,root->left);
        ret.push_back(root->val);
        inorderHelper(ret,root->right);
    }
};
ログイン後にコピー

2. 反復メソッド

反復メソッドでは、ルート ノードから開始してバイナリ ツリーの左端のノードを見つけ、渡されたノードをスタックに保存します。 , そして、一番左のノードを見つけます。ノードにアクセスした後、各ノードについて、それはそれ自体をルートとするサブツリーのルート ノードになります。訪問後、右の子に移動できます。コードは次のとおりです。

//iterate,using a stack
class Solution2 {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;
        if(root==NULL)return ret;
        TreeNode *curr=root;
        stack<TreeNode*> st;
        while(!st.empty()||curr!=NULL)
        {
            while(curr!=NULL)
            {
                st.push(curr);
                curr=curr->left;
            }
            curr=st.top();
            st.pop();
            ret.push_back(curr->val);
            curr=curr->right;
        }
        return ret;
    }
};
ログイン後にコピー

このメソッドの時間計算量は O(n) で、空間計算量も O(n) です。

3. モリスメソッド

このメソッドはモリスが発明したもので、読んでみて非常に絶妙だと感じました。このメソッドは再帰もスタックも使用せず、O(1) 空間計算量でバイナリ ツリーの走査を完了します。このメソッドの基本的な考え方は、右息子が NULL であるすべてのノードの右息子を後続ノードにポイントすることです (右息子が NULL ではないノードの場合、右息子が次にアクセスするノードになります)。このようにして、どのノードでも、アクセス後、その右側のノードが次に訪問するノードをポイントします。右端のノードの場合、そのような操作は必要ありません。この操作はトラバーサル中に完了し、ツリーはノード アクセスの完了後に復元されることに注意してください。ループ全体の判定条件は、現在のノードが空かどうかです。たとえば、上記のバイナリ ツリーでは、トラバーサル プロセスは次のようになります (現在のノード c の位置に基づく):

(1) 左の息子が空ではないため、現在のノードは 10 です。 c p の左側のサブツリーの右端のノードを見つけます:


結果: []

(2) 2 つあります。ノード c の左のサブツリーの右端のノードを見つけるための終了条件。右の 1 つの息子は空で、右の 1 つの息子は現在のノードを指します。次は、右側の息子が空の場合です。このケースは、最初にノード p の右側の息子を後続ノード c にポイントしてから構築し、次に c を下に移動する必要があります。

# 結果: []
(3) 現在のノード c の左の息子は空です。アクセスします。アクセス後、c を右側の息子 (つまり、後継ノード) にポイントします:

結果: [5]
(4) 続行左のサブツリーを検索します。右端のノード。今回の終了条件は、右端のノードが現在のノードであることです。これは、現在のノードの左側のサブツリーが走査されたことを示しています。現在のノードにアクセスした後、バイナリ ツリーを復元し、現在のノードが後継ノードを指すようにします:

結果: [5,10 ]
(5) c がバイナリ ツリー全体の右端のノードを指すまで、上記のプロセスを繰り返します:

左の息子は空です。アクセスすると、c が右の息子に進みます。右側の息子は空であり、判定条件を満たさないため、ループが終了し、トラバースが完了します。結果は次のようになります。
[5,10,6,15,2]

これはモリス法であり、時間計算量は O(n)、空間計算量は O です。 (1)。コードは次のとおりです:

//Morris traversal,without a stack
class Solution3 {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> ret;
        if(root==NULL)return ret;
        TreeNode *curr=root;
        TreeNode *pre;
        while(curr)
        {
            if(curr->left==NULL)
            {
                ret.push_back(curr->val);
                curr=curr->right;
            }
            else
            {
                pre=curr->left;
                while(pre->right&&pre->right!=curr)
                    pre=pre->right;
                if(pre->right==NULL)
                {
                    pre->right=curr;
                    curr=curr->left;
                }
                else
                {
                    ret.push_back(curr->val);
                    pre->right=NULL;
                    curr=curr->right;
                }
            }
        }
        return ret;
    }
};
ログイン後にコピー

推奨チュートリアル: "

C

#"

以上が順番通りの走査はどのように実行されるのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート