Javaのデータ構造 | 二分木の基本操作

目次

1. 二分木の格納方法

第二に、二分木の走査

事前注文トラバーサル

順序通りのトラバーサル

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

シーケンストラバーサル

 3. 二分木のその他の操作

ツリーのノード数を取得する

ツリー内のリーフ ノードの数を取得します

k 層ノードの数を取得する

二分木の深さを取得する


1. 二分木の格納方法

二分木は、チェーンまたはシーケンシャルに格納できます。

次に、リンクされたストレージ メソッドはポインターを使用し、シーケンシャル ストレージ メソッドは配列を使用します。

名前が示すように、連続して格納された要素はメモリ内に連続的に分散されますが、連結ストレージはポインターを使用して、さまざまなアドレスに散在するノードを直列に接続します。

チェーン ストレージを次の図に示します。

連鎖収納は誰もが慣れ親しんだ方法なので、順番に収納方法を見ていきましょう。

実際、配列は二分木を格納するために使用され、順次格納方法が図に示されています。

バイナリ ツリー トラバーサルを格納するために配列を使用する方法は?

親ノードの配列添え字が i の場合、その左の子は i * 2 + 1 であり、右の子は i * 2 + 2 です。

しかし、チェーンで表現された二分木の方が理解しやすいので、通常はチェーンを使用して二分木を格納します。

したがって、二分木は配列で表現できることを誰もが理解する必要があります。

第二に、二分木の走査

あるルールに従って合意が成立した場合、同じツリーに対する全員のトラバーサル結果は同じでなければなりません。N がルート ノードを表し、L がルート ノードの左側のサブツリーを表し、R がルート ノードの右側のサブツリーを表す場合、ルート ノードをトラバースする順序に従って、次のトラバーサル メソッドがあります。

NLR: Preorder traversal (Preorder Traversal は preorder traversal とも呼ばれます) - ルート ノード ---> ルートの左側のサブツリー ---> ルートの右側のサブツリーにアクセスします。LNR: Inorder Traversal (Inorder Traversal) - ルートの左側のサブツリー ---> ルート ノード ---> ルートの右側のサブツリー。LRN: postorder traversal (Postorder Traversal) - ルートの左サブツリー ---> ルートの右サブツリー ---> ルート ノード

レイヤー順序トラバーサル: 二分木のルート ノードから始めて、最初のレイヤーのノードにアクセスし、次に 2 番目のレイヤーのノードに左から右、上から下、というようにアクセスします。

上記のツリーを例として、バイナリ ツリーのトラバーサル実装を簡単に紹介します。

  • 事前注文トラバーサル

ルート ノード - 左のサブツリー - 右のサブツリー

予約注文トラバーサルの結果は次のとおりです。 A B D E H C F G

//前序遍历
   public void preOrder(TreeNode root){
        if(root == null){
            return;
        }
        System.out.println(root.val+" ");
        preOrder(root.left);
        preOrder(root.right);
​
   }
  • 順序通りのトラバーサル

左のサブツリー - ルート ノード - 右のサブツリー

順不同のトラバーサルの結果は次のとおりです。 DBE HAFCG 

// 中序遍历
    public void inOrder(TreeNode root){
        if(root == null){
            return;
        }
        inOrder(root.left);
        System.out.println(root.val+" ");
        inOrder(root.right);
    }
  • ポスト オーダー トラバーサル 

左のサブツリー - 右のサブツリー - ルート ノード

 // 后序遍历
    public void postOrde(TreeNode root){
        if(root == null){
            return;
        }
        postOrde(root.left);
        postOrde(root.right);
        System.out.println(root.val+" ");
    }
  • シーケンストラバーサル

ルート ノードから開始し、左から右へ、というように

シーケンストラバーサルの結果: A B C D E F G H

バイナリ ツリーのポスト オーダー トラバーサルの特徴: 最後のノードはルート ノードでなければなりません。

バイナリ ツリーの事前順トラバーサルは固有です。最初のノードはルート ノードでなければなりません。

  • リストを使用して、事前注文トラバーサルのノード要素を格納します

  public List<Character> preOrder2(TreeNode root){
        List<Character> ret = new ArrayList<>();
        if(root == null){
            return ret;
        }
        ret.add(root.val);
        List<Character> leftTree = preOrder2(root.left);
        ret.addAll(leftTree);
        List<Character> rightTree  = preOrder2(root.right);
        ret.addAll(rightTree);
        return ret;
    }

 3. 二分木のその他の操作

  • ツリーのノード数を取得する

ツリー内のノードの数を取得するには、トラバーサルの方法を使用するか、サブ問題のアイデアを使用して、再帰的な方法、つまり、左のサブツリー + 右のサブツリー + ルート ノード (+ 1) 達成する

size(root.left) +size(root.right)+1;
   /**
     *  遍历方法
     */
    public static int nodeSize = 0;
    public int size(TreeNode root){
        if(root == null){
            return 0;
        }
        nodeSize++;
        size(root.left);
        size(root.left);
        return nodeSize;
    }
    /**
     * 子树相加再加上根节点
     * @param root
     * @return
     */
    public int size2(TreeNode root){
        if(root == null){
            return 0;
        }
        int tmp = size(root.left) +size(root.right)+1;
        return tmp;
    }
  • ツリー内のリーフ ノードの数を取得します

ツリー内のリーフ ノードの数を取得します。つまり、左のサブツリーと右のサブツリーの両方が空の場合、root.left==null&&root.right==null、左のサブツリーのリーフ ノード + 上のすべてのリーフ ノード右のサブツリーまたは一時変数 leafSize++ を使用します。

 /**
     * 获取叶子节点的个数
     * @param root
     * @return
     */
  //子问题思路
    public int getLeafNodeCount(TreeNode root){
        if(root == null){
            return  0;
        }
        if(root.left==null&&root.right==null){
            return 1;
        }
        int tmp = getLeafNodeCount(root.left)+getLeafNodeCount(root.right);
        return tmp;
    }
     //遍历方法
    public static int leafSize = 0;
    public  int getLeafNodeCount2(TreeNode root){
        if(root == null){
            return 0;
        }
        if(root.left == null&&root.right == null){
            leafSize++;
        }
        getLeafNodeCount2(root.left);
        getLeafNodeCount2(root.right);
        return leafSize;
    }
  • k 層ノードの数を取得する

k 番目の層のノード数を求めると、左の木の k-1 層 + 右の木の k-1 層に変換できます。

K=3 のとき、左の木の 2 層目と右の木の 2 層目のノード数に変換し、最後に k = 1 のときに変換して、左から 2 層目のノード 2 と、右から 2 番目の層 3 番目の層のノードの数は、ノード 2 を追加すると 4 になります。

 public int getKLevelNodeCount(TreeNode root,int k){
        if(root == null|| k <= 0){
            return 0;
        }
        if(k==1){
            return 1;
        }
     int tmp = getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right,k-1);
      return tmp;
    }
  • 二分木の深さを取得する

public int getHeight(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        //左右子树的最大c
        return leftHeight > rightHeight ? leftHeight+1 : rightHeight +1;
   }

 

ced485cbb11e458d81a746890b32cf3f.gif

おすすめ

転載: blog.csdn.net/m0_56361048/article/details/127303470