データ構造とアルゴリズム:ツリー構造の基本部分

序文

この記事では、主にバイナリツリー、シーケンシャルストレージバイナリツリー、およびスレッド化されたバイナリツリーについて説明します。


データ構造とアルゴリズムの記事リスト

データ構造とアルゴリズムの記事リスト:ここをクリックしてジャンプして表示


目次

ここに画像の説明を挿入


(1)二分木

(1)なぜ木を使うのか

1)配列の
長所と短所を分析する長所:インデックスに従って要素をクエリし、大量のデータを格納でき、インデックスに従って配列をトラバースするのに便利です
短所:コンテンツに従って要素を見つけるのが遅く、配列のサイズを一度変更することはできません配列は1つのタイプのデータしか格納できず、要素の追加と削除は遅く、メソッドはカプセル化されていません。すべての操作はユーザーが定義する必要があります。
配列図:
ここに画像の説明を挿入

2)リンクリストの長所と短所を分析します。
長所:追加と削除が便利です。
短所:特定の値を探すときは、ヘッドノードからトラバースする必要がありますが、これは比較的非効率的です。
操作図:
ここに画像の説明を挿入

3)ツリーの保存方法を分析すると
、データの保存と読み取りの効率を向上させることができます。
例:[7、3、10、1、5、9、12]
ここに画像の説明を挿入


(2)樹形図

ここに画像の説明を挿入
ツリーの一般的な用語(概略的な理解と組み合わせる):

  1. ノード
  2. ルートノード
  3. 親ノード
  4. 子ノード
  5. リーフノード(子ノードのないノード)
  6. ノードの重み(ノード値)
  7. パス(ルートノードからノードのルートを検索します)
  8. サブツリー
  9. 木の高さ(最大層数)
  10. フォレスト:複数のサブツリーがフォレストを形成します

(3)二分木の概念

  1. ノード次数が2以下の順序付きツリーは、バイナリツリーと呼ばれます。
  2. 二分木の子ノードは、左右のノードに分かれています。
    概略図:
    ここに画像の説明を挿入
  3. 二分木に次数0のノードと次数2のノードのみがあり、次数0のノードが同じレベルにある場合、それを完全な二分木と呼びます。
    ここに画像の説明を挿入
  4. 深さがkでノードがnの二分木は、そのノードのそれぞれが深さkの完全な二分木の1からnまでの番号が付けられたノードに対応する場合にのみ、完全な二分木と呼ばれます。
    ここに画像の説明を挿入

(4)二分木探索の説明

  1. プレオーダートラバーサル:最初に親ノードを出力してから、左右のサブツリーをトラバースします
  2. 中次走査:最初に左側のサブツリーを走査し、次に親ノードを出力し、次に右側のサブツリーを走査します
  3. ポストオーダートラバーサル:最初に左側のサブツリーをトラバースし、次に右側のサブツリーをトラバースし、最後に親ノードを出力します
  4. 概要:出力親ノードの順序を調べて、それがプレオーダー、ミドルオーダー、ポストオーダーのいずれであるかを判別します。

(5)二分木探索アプリケーションの例(プレオーダー、ミドルオーダー、ポストオーダー)

アプリケーション例の説明とアイデア
ここに画像の説明を挿入
バイナリツリートラバーサルコード(ソースコードを表示するには、以下のリンクをクリックしてください)
バイナリツリートラバーサルアプリケーションの例(プレオーダー、ミドルオーダー、ポストオーダー)


(6)二分木-指定されたノードを検索します(プレオーダー、ミドルオーダー、ポストオーダー)

請求:

  1. プレオーダー検索、ミドルオーダー検索、ポストオーダー検索の方法を書いてください。
  2. そして、それぞれ3つの検索方法を使用して、heroNO = 5のノードを見つけます。
  3. そして、さまざまな検索方法を分析し、何回比較されたか
  4. アイデア分析図
    ここに画像の説明を挿入
    コード(ソースコードを表示するには、以下のリンクをクリックしてください):
    バイナリツリー-指定されたノードを検索します(プレオーダー、ミドルオーダー、ポストオーダー)

(7)二分木-ノードの削除

請求:

  1. 削除されたノードがリーフノードの場合は、ノードを削除します
  2. 削除されたノードが非リーフノードの場合は、サブツリーを削除します。
  3. テストし、No。5リーフノードとNo.3サブツリーを削除します。
  4. アイデアの削除分析
    ここに画像の説明を挿入
    コードを完成させます(ソースコードを表示するには、以下のリンクをクリックしてください):
    バイナリツリー-ノードの削除

(2)二分木の順次ストレージ

(1)二分木のシーケンシャルストレージの概念

基本的な手順:
データストレージの観点から、配列ストレージ方式とツリーストレージ方式は相互に変換できます。つまり、配列をツリーに変換でき、ツリーも配列に変換できます。を参照してください。右の概略図。
ここに画像の説明を挿入
請求:

  1. 右側の二分木のノードには、arrを格納するための配列が必要です:[1、2、3、4、5、6、6]
  2. 配列arrをトラバースする場合でも、ノードは、プレオーダートラバーサル、ミドルオーダートラバーサル、およびポストオーダートラバーサルの方法でトラバースできる必要があります。

シーケンシャルストレージバイナリツリーの特徴:

  1. シーケンシャル二分木は通常、完全な二分木のみを考慮します
  2. n番目の要素の左側の子ノードは2 * n +1です
  3. n番目の要素の右の子ノードは2 * n +2です。
  4. n番目の要素の親ノードは(n-1)/ 2
  5. n:二分木の要素数を示します(図に示すように0から番号を付け始めます)

(2)二分木探索のシーケンシャルストレージ

要件:配列{1,2,3,4,5,6,7}を指定します。これには、バイナリツリーのプレオーダートラバーサルでのトラバーサルが必要です。プレオーダートラバーサルの結果は、1、2、4、5、3、6、7になります。

public class ArrBinaryTreeDemo {
    
    
     public static void main(String[] args) {
    
    
          int[] arr = {
    
     1, 2, 3, 4, 5, 6, 7 };
          // 创建一个 ArrBinaryTree
          ArrBinaryTree arrBinaryTree = new  ArrBinaryTree(arr);
          arrBinaryTree.preOrder(); // 1,2,4,5,3,6,7
     }
}

// 编写一个ArrayBinaryTree, 实现顺序存储二叉树遍历
class ArrBinaryTree {
    
    
     private int[] arr;// 存储数据结点的数组
     public ArrBinaryTree(int[] arr) {
    
    
          this.arr = arr;
     }

     // 重载preOrder
     public void preOrder() {
    
    
          this.preOrder(0);
     }

     // 编写一个方法,完成顺序存储二叉树的前序遍历
     /**
      *
      * @param index 数组的下标
      */
     public void preOrder(int index) {
    
    
          // 如果数组为空,或者 arr.length = 0
          if (arr == null || arr.length == 0) {
    
    
              System.out.println("数组为空,不能按照二叉树的前序遍历");
          }
          // 输出当前这个元素
          System.out.println(arr[index]);
          // 向左递归遍历
          if ((index * 2 + 1) < arr.length) {
    
    
              preOrder(2 * index + 1);
          }
          // 向右递归遍历
          if ((index * 2 + 2) < arr.length) {
    
    
              preOrder(2 * index + 2);
          }
     }
}

結果:

1
2
4
5
3
6
7

(3)シーケンシャルストレージ二分木アプリケーション例

8つのソートアルゴリズムのヒープソートは、シーケンシャルストレージのバイナリツリーを使用します


(3)スレッド化された二分木

(1)問題

シーケンス{1、3、6、8、10、14}を二分木に構築します。n+ 1 = 7
ここに画像の説明を挿入
問題分析:

  1. 上記の二分木を順番にトラバースすると、数列は{8、3、10、1、6、14}になります。
  2. ただし、ノード6、8、10、および14の左右のポインターは十分に活用されていません。
  3. 各ノードの左右のポインターを最大限に活用して、各ノードが独自のフロントノードとバックノードを指すことができるようにするにはどうすればよいでしょうか。
  4. 解決策-手がかりの二分木

(2)手がかり二分木の基本的な紹介

  1. nノードのバイナリリンクリストには、n + 1 [式2n-(n-1)= n +1]のnullポインタフィールドが含まれています。バイナリリンクリストのnullポインタフィールドを使用して、ノードの先行ノードと後続ノードへのポインタを特定の走査順序で格納します(この種の追加のポインタは「手がかり」と呼ばれます)。
  2. 手がかりのあるこの種のバイナリリンクリストはスレッドリンクリストと呼ばれ、対応するバイナリツリーはスレッドバイナリツリー(スレッドバイナリツリー)と呼ばれます。手がかりの性質に応じて、手がかり二分木は、プレオーダー手がかり二分木、ミドルオーダー手がかり二分木、ポストオーダー手がかり二分木という3つのタイプに分けることができます。
  3. ノードの前のノードは先行ノードと呼ばれます
  4. ノードの次のノードは後続ノードと呼ばれます

(3)キュー二分木アプリケーションケース

アプリケーションケースの説明:次のバイナリツリーを順番に並べた手がかりのバイナリツリーにします。中次走査のシーケンスは{8、3、10、1、14、6}です。
ここに画像の説明を挿入
思考分析:中次走査の結果:{8、3、10、1、14、6}
ここに画像の説明を挿入
説明:バイナリの場合ツリーが手がかりになります。ノード左右のノードのプロパティは次のとおりです。

  1. leftは、左側のサブツリー、またはそれが指す先行ノードを指します。たとえば、①左側のサブツリーが左側のノードを指し、⑩ノードの左側が先行ノードを指します。
  2. rightは右のサブツリーを指すか、後継ノードを指す場合があります。たとえば、①noderightは右のサブツリーを指し、⑩noderightは後継ノードを指します。

コード(ソースコードを表示するには、以下のリンクをクリックしてください):
手がかりバイナリツリーアプリケーションケース


(4)手がかりの二分木をトラバースします

  1. 説明:順番に手がかりを使って前の二分木を横断します
  2. 分析:スレッドが回転すると各ノードのポイントが変わるため、元のトラバーサル方法は使用できません。現時点では、スレッド化された二分木をトラバースするための新しい方法が必要です。各ノードは線形にトラバースできるため、再帰的な方法を使用する必要はありません。また、トラバーサルの効率が向上します。トラバーサルの順序は、インオーダートラバーサルと一致している必要があります。
  3. コード(ソースコードを表示するには、以下のリンクをクリックしてください):
    手がかりの二分木をトラバースします

おすすめ

転載: blog.csdn.net/a13027629517/article/details/115263388