データ構造|二分木の 3 つの走査方法、いくつマスターできましたか?

目次

1.トラバーサル方式

2. 予約トラバーサル

3. 順序通りのトラバーサル

1.トラバーサル方式

バイナリ ツリーの構造を学習する最も簡単な方法は、バイナリ ツリーをトラバースすることです。二分木のトラバースとは,特定の行を通って二分木の各ノードにアクセスすることです. アクセス方法には, 前順トラバーサル, インオーダートラバーサル, 後続トラバーサルの3つがあります. 層順トラバーサルのトラバーサル順序は次のとおりです.

  • 事前順序走査:ルート ノード= "ルート ノードの左サブツリー = "ルート ノードの右サブツリー
  • 順序通りのトラバーサル: ルート ノードの左側のノード = "ルート ノード=" ルート ノードの右側のサブツリー
  • 後続のトラバーサル: ルート ノードの左ノード = "ルート ノードの右ノード = "ルート ノード

二分木の走査では、走査の開始はヘッド ノードから始まり、走査の終了もヘッド ノードから終了します。


値が 123456 である 6 つのノード ABCDEF を持つバイナリ ツリーがあります。対応する構造は次のとおりです。

  • A がルート ノードの場合、A の左側のサブツリーは D、A の右側のサブツリーは E、A の値は 1 です。
  • B がルート ノードの場合、B の左側のサブツリーは D、B の右側のサブツリーは E、B の値は 2 です。
  • C がルート ノードの場合、C の左側のサブツリーは null、C の右側のサブツリーは F、C の値は 3 です。
  • D がルート ノードの場合、D の左側のサブツリーは null、F の右側のサブツリーは null で、値は 4 です。
  • E がルート ノードの場合、E の左側のサブツリーは null、F の右側のサブツリーは null で、値は 5 です。
  • F がルート ノードの場合、F の左側のサブツリーは null、F の右側のサブツリーは null で、値は 6 です。

このブログ投稿で実践されている走査方法はすべて、上の図のバイナリ ツリーに示されています。


2. 予約トラバーサル

トラバーサルを事前順序付けします。そのトラバーサル順序は次のとおりであることを上記で学びました:ルート ノード = "ルート ノードの左サブツリー = "ルート ノードの右サブツリー. したがって、上記で定義された二分木を前の順序でトラバースする順序は、ABDECF によって取得される値も 124536 である必要があります。具体的な実装方法については、次の説明を参照してください。

最初のステップは、ルート ノード A を取得することです。A ノードに左サブツリーがあるかどうかを判断します。そうであれば、次の左側のサブツリーにトラバースします。右のサブツリーがない場合は、右のサブツリーがトラバースされ、右のサブツリーがない場合は親ノードが返されます。親ノードがない場合、プログラムは終了します。

このステップは、A の左側のサブツリーをトラバースします。最初に、A ノードを取得し、A に左側のサブツリーがあることを確認してから、A の左側のサブツリー ノードを下方向にトラバースします。このとき、たどったノードは A、要素は 1 です。


2 番目のステップは、B ノードに来て、B ノードを取得することです。ノード B に左部分木があるかどうかを判断します。そうであれば、次の左側のサブツリーにトラバースします。右のサブツリーがない場合は、右のサブツリーがトラバースされ、右のサブツリーがない場合は親ノードが返されます。親ノードがない場合、プログラムは終了します。

このステップは、B の左側のサブツリーをトラバースし、B に左側のサブツリーがあることがわかった場合は、B の左側のサブツリー ノードを下にトラバースします。このとき、たどったノードは AB で、要素は 12 です。

 


3番目のステップは、Dノードに来て、Dノードを取得することです. 次に、D ノードに左部分木があるかどうかを判断し、次のノードにトラバースします。右のサブツリーがない場合は、右のサブツリーがトラバースされ、右のサブツリーがない場合は親ノードが返されます。

このとき、D には左部分木がないことがわかり、D の右部分木をたどると右部分木がないことがわかるので、ノード B に戻り、ノード B の右部分木までたどります。この時点で通過するノードは ABD で、要素は 124 です。


4番目のステップは、Eノードに来て、Eノードを取得することです。E に左部分木があるかどうかを判別します。その場合は、次のノードにトラバースします。右のサブツリーがない場合は、右のサブツリーがトラバースされ、右のサブツリーがない場合は親ノードが返されます。

このとき、E ノードに左右の部分木がないことが分かった場合は、B ノードに戻り、B ノードは A ノードに戻り、A ノードは再び C ノードにトラバースします。 、トラバースされたノードは ABDE、エレメントは 1245 です。


5番目のステップは、Cノードに来てCノードを取得することです。C に左部分木があるかどうかを判別します。その場合は、次のノードにトラバースします。右のサブツリーがない場合は、右のサブツリーがトラバースされ、右のサブツリーがない場合は親ノードが返されます。

このとき、Cノードには左部分木がないことがわかり、Cノードの右部分木Fノードにアクセスして、Fノードのルートノードを取得する。F の左部分木にたどると、このとき得られるノードは ABDEC、要素は 12453 です。


最後のステップは、F ノードに来て、F ノードを取得することです。F ノードには左右のサブツリーがなく、F ノードの親ノード C ノードが返され、C ノードは C の親ノード A ノードに返されます。最後に、A には親ノードがないことがわかり、プログラムは終了します。今回取得したノードはABDECF、エレメントは124536です。


上記は、事前注文トラバーサル手順の詳細な説明です. コードの実装を見てみましょう: 

//MyBinaryTree.java文件下
public class MyBinaryTree {

    //静态内部类BinaryTree
    static class BinaryTree {
        public int val;
        public BinaryTree left;
        public BinaryTree right;

        public BinaryTree(int val) {
            this.val = val;
        }
    }

    //根节点
    public BinaryTree root;

    //创建一个二叉树
    public void initBinaryTree() {
        BinaryTree A = new BinaryTree(1);
        BinaryTree B = new BinaryTree(2);
        BinaryTree C = new BinaryTree(3);
        BinaryTree D = new BinaryTree(4);
        BinaryTree E = new BinaryTree(5);
        BinaryTree F = new BinaryTree(6);
        A.left = B;
        A.right = C;
        B.left = D;
        B.right = E;
        C.right = F;
        root = A;
    }

    //前序遍历二叉树
    public void preOrder(BinaryTree tree) {
        if( tree == null) {
            return;
        }
        //节点的元素
        System.out.print(tree.val+" ");
        //节点的左子树
        preOrder(tree.left);
        //节点的右子树
        preOrder(tree.right);
    }
}

//Test.java文件下
public class Test {
    public static void main(String[] args) {
        MyBinaryTree myBinaryTree = new MyBinaryTree();
        myBinaryTree.initBinaryTree();
        myBinaryTree.preOrder(myBinaryTree.root);
    }
}

実行後の出力:  

実行できる結果は、上記の演習の最終結果と一致しています。プログラムを通して、バイナリ ツリーのトラバーサルが再帰的なアイデアであり、その終了条件がノード自体が空でないことであることがわかります。さらに、慎重な友人は、先頭ノードが最初に走査されるため、事前順序走査によって得られる最初の結果がこの二分木の先頭ノードであることを見つけることができます。 


3. 順序通りのトラバーサル

順序通りのトラバーサルの順序は次のとおりです。ルート ノードの左側のノード = 「ルート ノード」 = ルート ノードの右側のノード. したがって、現在のバイナリ ツリーの順序どおりのトラバーサルによって取得されるルート ノードの順序は DBEACF であり、ルート ノード要素は 425136 です。

最初のステップは、A の左側のノードをトラバースすることです。ノード A に A の左側のノードにトラバースする左側のノードがある場合、それが存在しない場合はノード A を取得し、ノード A の右側のノードにトラバースし、右側のノードも空の場合は親ノードに戻ります。この時点で、ノード B はトラバースされています。以下の各ノードもこのステップで実行されます。


2 番目のステップは、B ノードにトラバースすることです。ノード B の左側のノードが空でないことを確認します。ノード D までたどり、ノード D の左部分木が空であることを判断し、ノード D を取得し、D の右部分木が空であることを確認し、親ノード B に戻り、ノード B のルート ノードを取得します。このとき通過するノードは DB、要素は 42 です。


3 番目のステップは、E ノードにトラバースすることです。E ノードの左側のサブツリーは空で E ノードを取得し、右側のサブツリーも空で親ノード B を返し、B ノードは親ノード A を返し、A ノードのルート ノードを取得します。この時点で通過するノードは DBEA で、要素は 4251 です。


4 番目のステップは、 C ノードにトラバースすることです。C ノードの左部分木が空であるため、C ノードを取得し、C ノードの右部分木が空でないことを判断します。ノード F にトラバースすると、この時点でトラバースされたノードは DBEAC で、要素は 42513 です。


5 番目のステップは、F ノードにトラバースすることです。F ノードの左側のサブツリーは空です。F ノードを取得します。F ノードの右側のサブツリーも空です。親ノード C を返します。C ノードは親ノード A を返します。A ノードには親ノードがなく、プログラムは終了します。この時点で通過するノードは DBEACF で、要素は 425136 です。プログラムは終了します。


順序通りのトラバーサルの場合、上記のコードの preOrder メソッドでアクセス ノードのルート ノードの位置を少し変更するだけで、残りのコードは変更されません。 

    
//中序遍历二叉树
public void inOrder(BinaryTree tree) {
        if( tree == null) {
            return;
        }
        //节点的左子树
        preOrder(tree.left);
        //节点的元素
        System.out.print(tree.val+" ");
        //节点的右子树
        preOrder(tree.right);
    }

 実行後の出力:

上記の結果から、出力結果が上記の結果と一致していることがわかります。注意深い友人は、順番にトラバースすると、ヘッド ノードの左側が左側のサブツリーであり、ヘッド ノードの右側が右側のサブツリーであることがわかります。上記のコードでは、1 の左側は 425 で、1 の右側は 36 であり、これはバイナリ ツリーと完全に一致しています。したがって、二分木の先頭ノードが誰であるかがわかれば、二分木の左と右のツリーを順番にトラバーサルして推測できます。 


4. 注文後のトラバーサル

ポスト オーダー トラバーサルの手順は次のとおりです。ルート ノードの左側のノード = "ルート ノードの右側のノード = ルート ノード。この記事のバイナリ ツリーの例では、対応するトラバーサル ノードの順序は次のとおりです。DEBFCA、ノード要素は 452631 です。

以上、前順トラバーサルと後順トラバーサルのフローチャートと実装手順を示しましたが、実は後順トラバーサルも左ノード、右ノード、左ノード、右ノード、とルート ノード. ここでは、ブロガーはしません。

バイナリ ツリーのポスト オーダー トラバーサル コードでは、preOrder メソッドでルート ノードの位置を交換することもできます。

//后序遍历二叉树    
public void postOrder(BinaryTree tree) {
        if( tree == null) {
            return;
        }
        //节点的左子树
        preOrder(tree.left);
        //节点的右子树
        preOrder(tree.right);
        //节点的元素
        System.out.print(tree.val+" ");
    }

実行後の出力:

結果を実行すると、上記のトラバーサルによって得られた結果が一貫していることがわかります。観察を通して、私たちも知ることができます。二分木のポストオーダー トラバーサルがわかれば、ヘッド ノードを取得できます。これは、ポストオーダー トラバーサルの最後のデータがヘッド ノードであるためです。


二分木の前順序走査またはその後の走査結果と順序内走査結果がわかれば、二分木の全体像を簡単に推測できます。

たとえば、バイナリ ツリーの事前順序走査結果は ABDECF であり、順序内走査結果は DBEACF です。この場合、この二分木のヘッド ノードは A、左側のサブツリーは DBE、右側のサブツリーは CF です。したがって、この二分木の全体像は次のようになると推測できます。

もちろん、バイナリ ツリーのインオーダー トラバーサルとポストオーダー トラバーサルを知っていれば、このバイナリ ツリーを簡単に推測できますが、プレオーダー トラバーサルとポストオーダー トラバーサルを知っていても、このバイナリ ツリーを推測することはできません。左を取得できないメソッド、右のサブツリーは何ですか。


このブログはここにあります。誰もが理解できないことを理解するために絵を描いたり、ブロガーにプライベート メッセージを送信したり、コメントを残したりできます。読んでくれてありがとう、また次回!

おすすめ

転載: blog.csdn.net/weixin_64916311/article/details/130157918