目次
1. ツリーの概念と構造
1.1 ツリーの概念
ツリーは非線形データ構造であり、n (n>=0) 個の有限ノードで構成される階層関係のセットです。根が上を向き、葉が下を向いている、逆さまの木に見えることからツリーと呼ばれています。
ルート ノードと呼ばれる特別なノードがあります。ルート ノードには先行ノードがありません
。ルート ノードを除き、他のノードは M (M>0) 個の互いに素な集合 T1、T2、...、Tm に分割されます。ここで、各集合はTi (1<= i<= m) は、ツリーと同様の構造のサブツリーです。各サブツリーのルート ノードには 1 つのみの先行ノードがあり、0 個以上の後続ノードを持つことができます。したがって、ツリーは再帰的に定義されます。ツリー構造では、ツリー構造に注意する必要があります。ノード間の交差はありませ
ん。サブツリー、それ以外の場合はツリー構造ではありません
上図のように、サブツリー間に交差がある場合、その構造は現時点ではツリーとは言えず、グラフと呼ぶ必要があります。
ノードの次数: ノードに含まれる部分木の数をノードの次数といいます; 上図に示すように: A は 6 葉のノード
または終端ノードです: 次数が 0 のノードは葉と呼ばれますノード; 上の図に示すように: B、C、H、I... などのノードは葉ノード、
非終端ノード、または分岐ノードです: 次数が 0 でないノード; 上の図に示すように: などのノードD、E、F、G... はブランチ ノード、
親ノード、または親ノードであるため、A ノードに子ノードが含まれる場合、このノードはその子ノードの親ノードと呼ばれます。上の図に示すように、A はB の親ノード 子ノード
または子ノード: ノードに含まれるサブツリーのルート ノードをノードの子ノードと呼びます; 上図に示すように: B は A の子ノード
です。上の図に示すように、同じ親ノードは兄弟ノードと呼ばれます: B と C は兄弟ノードです (兄弟である必要があることに注意してください)
。上の図に示すように、ノードの次数はツリーの次数と呼ばれます。 : ツリーの次数は 6 (ツリーの次数は、親ノードが次数として持つ子ノードの数としても理解できます)
ノードの階層: ルートから定義され、ルートは最初の層であり、ルートの子ノードは 2 番目のレイヤーなどです (上の図には 4 つのレイヤーがあります)
ツリーの高さまたは深さ: ツリー内のノードの最大レベル; 上の図のように: ツリーの高さは4 (4 層)
いとこノード: 親が同じ層にあるノードはいとこです; 上図に示すように: H と I は兄弟
ノードの互いの祖先です: ルートからノードまでの枝にあるすべてのノード;上の図に示すように: A はすべてのノードの
祖先です: ノードをルートとするサブツリー内のノードは、ノードの子孫と呼ばれます。上の図に示すように、すべてのノードはフォレストの子孫です
。m (m>0) の互いに素なツリーの集合はフォレストと呼ばれます。
ツリー構造は線形テーブルに比べて複雑で、保存や表現が面倒です。値の範囲が保存されるため、ノードとノード間の関係も保存されます。実際には、ツリーを表現する方法はたくさんあります。親表現、子表現、子の親表現、および子の兄弟表現として。ここでは、最も一般的に使用される子兄弟表記を簡単に理解します。
子兄弟表記法は、以下の図に示すように、左子右兄弟表記法とも呼ばれます。子ポインタはその子ノードを指し、兄弟ポインタはその兄弟を指します。
ツリーの実際の応用例は、コンピュータ内のファイル ディレクトリがツリー構造で実現されるようなものです。
2. 二分木の概念
2.1 概念
バイナリ ツリーは有限のノードのセットであり、そのセットは次のとおりです。
1. または空です
。 2. ルート ノードと、左サブツリーおよび右サブツリーと呼ばれる 2 つのバイナリ ツリーで構成されます。
上の図からわかります。
1. 二分木には次数が 2 より大きいノードはありません。
2. 二分木の部分木は左右に分割されており、順序を逆にすることはできないため、二分木は次のようになります。ツリーは順序付きツリーです
。 注: バイナリ ツリーは、次のような状況の組み合わせで構成されます。
実際には、下の図に示すように、バイナリ ツリーも見たことがあります (ツリーは完全なバイナリ ツリーです)。
2.2 特別なバイナリ ツリー:
1. 完全なバイナリ ツリー: バイナリ ツリーは、各層のノードの数が最大値に達すると、このバイナリ ツリーは完全なバイナリ ツリーになります。つまり、バイナリ ツリーの層の数が K で、ノードの総数が 2^k-1 であれば、それは完全なバイナリ ツリーになります。
2. 完全なバイナリ ツリー: 完全なバイナリ ツリーは非常に効率的なデータ構造であり、完全なバイナリ ツリーは完全なバイナリ ツリーから派生します。深さが K でノードが n のバイナリ ツリーの場合、各ノードが、深さのある完全なバイナリ ツリー内の 1 から n までの番号が付けられたノードと 1 対 1 対応する場合に限り、完全なバイナリ ツリーと呼ばれます。 Kさんの 完全なバイナリ ツリーは特別な種類の完全なバイナリ ツリーであることに注意してください。
2.4 二分木の性質1. ルートノードの層数を i と指定した場合、
空ではない二分木のi 番目の層には最大2^(i-1)個のノードが存在します
。ルート ノードの層数を h として指定すると、深さ h の二分木の最大ノード数は2^h-1
になります。葉ノードの数を X0、次数 2 の分岐ノードの数を X2 とすると、X0=X2+1
4. ルートノードの層数を h と指定すると、完全な二分木の深さは n になります。ノード: h= log(n+1) (log は 2、n+1 の対数に基づきます)
5. n 個のノードを持つ完全なバイナリ ツリーの場合、すべてのノードが配列の上から順に 0 から番号付けされているとします。下から左から右へ、シーケンス番号 i のノードについては次のようになります。
1. i>0 の場合、i 位置のノードの親番号: (i-1)/2; i=0、i はルート ノード番号、親ノードなし 2. 2i+1< n の場合、
左子の番号: 2i+ 1、2i+1>=n それ以外の場合、左側の子 3 はありません。2i
+2<n の場合、右側の子のシリアル番号: 2i+2、2i+2>=n、それ以外の場合は右側はありません。上記(1.2.3) は、配列内の親ノードを知り、左側の子ノードの添え字 2*parnet+1 を見つけ、右側の子ノードの添え字は 2*parent+2 であると理解できます
。いずれかの子ノードの子添字がわかっている場合は、親ノードの添字を (子 -1)/2 として見つけます。
次の図は、完全なバイナリ ツリーと完全なバイナリ ツリーの概略図です。
2.3 バイナリツリーの記憶構造
バイナリ ツリーは通常、シーケンシャル構造とチェーン構造の 2 つの構造を使用して格納できます。
1.シーケンシャル ストレージ
シーケンシャル構造ストレージでは、ストレージに配列が使用されます。一般に、配列は完全なバイナリ ツリーに対するスペースの無駄ではないため、完全なバイナリ ツリーを表す場合にのみ適しています。実際には、配列にはヒープのみが格納されます。バイナリ ツリー逐次ストレージは、物理的には配列であり、論理的にはバイナリ ツリーです。下の図のような不完全な二分木だ、かなりのスペースを無駄にしてしまいます。
2.リンクストレージ
二分木のリンクストレージ構造とは、二分木をリンクリストで表現する、つまり要素の論理的な関係をリンクで表現することを意味します。通常の方法では、リンク リストの各ノードは、データ フィールドと左右のポインタ フィールドの 3 つのフィールドで構成され、左右のポインタは、左の子と左の子がポイントするリンクのストレージ アドレスを与えるために使用されます。ノードの右の子が見つかります。チェーン構造はバイナリチェーンとトリプルチェーンに分けられ、バイナリツリーの実装は一般的にバイナリチェーン、赤黒ツリーなどのトリプルチェーンのデータ構造が使われます。
3. バイナリツリーの逐次構造とヒープの実装
3.1 ヒープの概念
通常のバイナリ ツリーは、無駄な領域が多くなる可能性があるため、配列での保存には適していません。完全なバイナリ ツリーは、順次構造の保存に適しています。実際には、通常、シーケンシャル構造の配列にヒープ (バイナリ ツリー) を格納します。ここでのヒープとオペレーティング システムの仮想プロセス アドレス空間内のヒープは 2 つの異なるものであることに注意してください。1 つはデータです。
ヒープの概念と構造 メモリの領域をセグメント化する ヒープの概念と構造
ヒープは、コンピューター サイエンスにおける特別なクラスのデータ構造の一般用語です。ヒープは通常、ツリーと考えることができるオブジェクトの配列です。ヒープは常に次の特性を満たします。
ヒープ内のノードの値は、常にその親ノードの値よりも大きくも小さくもなりません。
ヒープは常に完全なバイナリ ツリーです。
最大のルート ノードを持つヒープは最大ヒープまたはビッグ ルート ヒープと呼ばれ、最小のルート ノードを持つヒープは最小ヒープまたはスモール ルート ヒープと呼ばれます。一般的なヒープには、バイナリ ヒープ、フィボナッチ ヒープなどが含まれます。
ヒープは非線形データ構造であり、1 次元配列と同等です。
上の図は大きな山を示しています。これは、親ノードが子ノードよりも大きいという事実によって特徴付けられます (昇順でソートするため)。
上の図は小さなヒープの写真ですが、小さなヒープの特徴は、親ノードが子ノードよりも小さいことです(降順ソートの場合)
3.2 ヒープの実装
ヒープダウン調整アルゴリズム
ここで、論理的に完全なバイナリ ツリーとみなされる配列が与えられます。ルートノードから始まる下方調整アルゴリズムを通じて、それを小さなヒープに調整できます。下方調整アルゴリズムには前提条件があります。つまり、左右のサブツリーが調整対象のヒープである必要があります。
上の図のような構造を下方調整方法で調整すると、次の図が得られます。
しかし、順序が正しくなく、左右のサブツリーが小さなヒープではない配列が与えられた場合、どのようにヒープを構築すればよいでしょうか? 現時点では、ヒープをボトムアップで構築することを検討できます。上記のヒープを構築すると、このときのヒープ構築の時間計算量は O(n) になります。
3.3 ヒープの関連インターフェイスを実現する
3.5 下方調整方法
3.6 ヒープの初期化
3.7 ヒープの破壊
3.8 ヒープの最上位要素を取得する
3.9 ヒープ内の要素数を取得する
3.10 ヒープの挿入
まず配列の末尾に 10 を挿入し、ヒープが満たされるまで上方調整アルゴリズムを実行します。以下に示すように
コード
3.11 ヒープの削除
ヒープの削除では、ヒープの先頭のデータを削除し、ヒープの先頭のデータを最後のデータに置き換え、次に配列内の最後のデータを削除して、下方調整アルゴリズムを実行します。
3.12 ヒープソート
大きなヒープを構築すると昇順にソートできるのですが、なぜこんなことができるのでしょうか? このときヒープの先頭の要素が最大の要素なので、ヒープの先頭の要素を入れ替えるだけで済みます。下方調整方法では、次に大きい数値を選択し、それを再度変更するなどを繰り返し、最終的に配列内の数値が昇順になります。