【アルゴリズムとデータ構造09】木、二分木、二分探索木とは?

みなさん、こんにちは!私は[AI菌]不熬夜プログラマ。热爱AI、热爱分享、热爱开源このブログは私の要約であり、学習についての考察です。あなたも深度学习、机器视觉、算法、Python、C++興味があるなら、あなたは私のダイナミックに集中することができます、私たちは一緒に学び、一緒に進歩します〜

木と言えば、誰もが木に慣れ親しんでいるということは、結局のところ、日常生活の中で一般的なことです。しかし、今日の主役はツリーではありません。データ構造内のツリー、バイナリツリー、バイナリサーチツリー、およびそれらの基本的な操作について話しましょう。

ここに画像の説明を挿入


1つ、ツリーとバイナリツリー

1.1木とは?

ツリーはデータ構造であり、n(n> = 1)個の有限ノードで構成される階層的なコレクションです。逆さまの木のように見えるため、「木」と呼ばれます。つまり、根が上を向き、葉が下を向きます。

ツリーはノードとエッジで構成され、リングにはデータ構造がありません。次の図から、ツリーの構造をより直感的に理解できます。

ここに画像の説明を挿入

ツリーは、再帰的な定義の特性を満たします。つまり、データ構造がツリー構造の場合、ルートノードを削除すると、いくつかのサブ構造もツリーになり、通常はサブツリーと呼ばれます。

ツリーでは、ノード間の階層関係に応じて、ノードの名前も異なります。次の図に示すように、次のツリーを見てみましょう。
ここに画像の説明を挿入
さまざまなノードの関係と名前は次のとおりです。

  • 上位レベルのノードはノードBとノードCであり、AとC Bは親ノード、A、B、Cは子ノードです。
  • BとCの両方がAの「子」である場合、BとCは兄弟ノードと呼ばれます。
  • Aに親ノードがない場合、Aはルートノードと呼ばれます
  • ノードG、H、I、Fには子ノードがないため、G、H、I、Fはリーフノードと呼ばれます。

ツリーがある場合は、深度レイヤー使用して、ツリー内のノードの場所を説明する必要があります上の図に示すように、ノードのレベルはルートノードからカウントされます。

  • ルートは次のような最初のレベルです:A
  • ルートの「子」は、B、Cなどの第2レベルです
  • ルート「子」の「子」は、D、E、Fなどの第3レベルです
  • 同様に、4番目のレイヤー(最後のレイヤー)は、G、H、Iです。

ツリー内のノードのレイヤーの最大数は、ツリーの深さ(深さと呼ばれ、高さとも呼ばれます)であるため、これは深さ4のツリーです。

1.2二分木とは何ですか?

大規模なツリーファミリーには、頻繁に使用される特別なツリーがあり、これはバイナリツリーです。バイナリツリーでは、各ノードには最大で2つのブランチがあります。つまり、各ノードには最大で2つの子ノードがあり、それらは左の子ノード右の子ノード呼ばれます

バイナリツリーには、次の図に示すように、2つの最も特殊なタイプがあります。

ここに画像の説明を挿入

  • 完全なバイナリツリーは、リーフノードに2つの子ノードがある以外のすべてのノードとして定義されます
  • 完全な二分木は、最後の層を除く他の層のノードの最大数として定義され、最後の層の葉ノードはすべて左側に配置されます。

完全なバイナリツリーは完全に見えませんが、なぜそれをそのように呼ぶのですか?これは、実際にはバイナリツリーの格納に関連しています。バイナリツリーを格納する方法は2つあります。1つはポインタベースのチェーンストレージメソッド、もう1つは配列ベースのシーケンシャルストレージメソッドです。

  • チェーンストレージメソッドはリンクリストに似ています。次の図に示すように、各ノードには3つのフィールドがあり、1つはデータを格納し、他の2つは左と右の子ノードへのポインターを格納します。

ここに画像の説明を挿入

  • 逐次格納方式は、下図のようにノードを法則に従って配列に格納する方式であり、計算の便宜上、添え字が1の位置にルートノードを配置することに同意します。続いて、ノードBは下付き文字2の位置に格納され、ノードCは下付き文字3の位置に格納されます。
    ここに画像の説明を挿入

完全二分木と呼ばれるのは記憶空間の利用効率の観点からです。完全なバイナリツリーの場合、無駄なのは添え字0の格納場所だけです。それが不完全なバイナリツリーである場合、多くのストレージスペースが無駄になります。

次の図に示す不完全なバイナリツリーでは、5と6の位置を予約する必要があります。同時に、2つの子ノード10と11の5の位置と2つの子ノード12と13の6の位置。このような二分木は、アレイの記憶領域を完全には利用しません。
ここに画像の説明を挿入


次に、ツリーの前順、中次、および後順のトラバーサル

次に、二分木を例にとり、ツリーの操作を紹介しますが、他の種類のツリーの操作も二分木と基本的に同じです。

これまでに学習したデータ構造はすべて「1対1」の関係であることがわかります。つまり、以前のデータは、リンクリスト、スタック、キューなど、次のデータとの接続関係しかありません。ツリー構造は「1対多」の関係です。つまり、前の親ノードには、以下のいくつかの子ノードとの接続関係があります。

「1対1」の構造では、検索には特定の値があり、各データを直接順番にたどることができます。ただし、ツリーは「1対多」の関係なので、どの順序でトラバースする必要がありますか?

実際、ツリーをトラバースするための3つの非常に古典的な方法があり、前順トラバーサル、中次トラバーサル、および後順トラバーサルです。ここでの順序とは、親ノードのトラバース順序を指します。最初の順序は最初に親ノードをトラバースすることであり、中央の順序は親ノードを中央でトラバースすることであり、後者の順序は親ノードを最後にトラバースすることです。

どのようなトラバーサルであっても、再帰呼び出しによって行われます以下に示すように:

ここに画像の説明を挿入

  • preorder traversalは、ツリー内の任意のノードについて、最初にこのノードを出力し、次にその左サブツリーをpreorderでトラバースし、最後にその右サブツリーをpreorderでトラバースします。
  • Middle-order traversalは、ツリー内の任意のノードについて、最初にその左側のサブツリーを中央の順序でトラバースし、次にこのノードを出力し、最後にその右側のサブツリーを中央の順序でトラバースします。
  • ツリー内の任意のノードのポストオーダートラバーサルは、左のサブツリーを順にトラバースし、次に右のサブツリーをポストオーダーして、最後にそれ自体を出力します。

三、二分探索木の特徴

特別なプロパティのないバイナリツリーの場合、トラバーサルの時間の複雑さは別として、実際に追加および削除操作を実行する時間の複雑さはO(1)です。ツリーデータの検索操作はリンクリストと同じですが、各データをトラバースして判断する必要があるため、時間の複雑さはO(n)です。

ただし、バイナリツリーにいくつかの特性(バイナリサーチツリーなど)がある場合、これらの特性を使用して時間の複雑さを軽減できます。

バイナリ検索ツリー(バイナリ検索ツリーとも呼ばれます)には、次の特性があります。

  • 二分探索木のどのノードでも、左側のサブツリーの各ノードの値はこのノードの値より小さくなければならず、右側のサブツリーの各ノードの値はこれより大きくなければなりません。ノードの値。
  • 二分探索木では、2つのノードの値が等しいという状況は可能な限り回避されます。
  • バイナリ検索ツリーを順番にたどることにより、順序付けられたデータキューを小さなものから大きなものへと出力できます。次の図に示すように、順序トラバーサルの結果は10、13、15、16、20、21、22、26です。

ここに画像の説明を挿入
したがって、二分探索木は、ルールでソートされた二分木と簡単に考えることができます。


第四に、二分探索木の追加・削除・確認操作

3.1検索操作

二分探索木を使用して探索操作を実行する場合、以下の判断を下すことができます。

  • まず、ルートノードが検索するデータと等しいかどうかを判断し、等しい場合は返します。
  • ルートノードが検索するデータよりも大きい場合、検索は左側のサブツリーでリーフノードまで再帰的に実行されます。
  • ルートノードが検索対象のデータよりも小さい場合、検索は、リーフノードまで右側のサブツリーで再帰的に実行されます。

このような「バイナリ検索」によって消費される時間の複雑さは、O(logn)に削減できます二分探索については、アルゴリズムの部分で後で説明します。

3.2挿入操作

バイナリ検索ツリーで挿入操作を実行することも非常に簡単です。ルートノードから開始して、挿入するデータがルートノードのデータよりも大きく、ルートノードの右側の子ノードが空でない場合は、ルートノードの右側のサブツリーで挿入操作の実行を続けます。挿入は、空の子ノードが見つかるまで実行されます。

下の図に示すように、挿入するXの値が14の場合、Xとルートノードのサイズ関係を決定する必要があります。

  • 14は16未満なので、左側のサブツリーに注目し、Xと13の関係を判断し続けます。
  • 14は13より大きいため、正しいサブツリーに焦点を当て、Xと15の関係を判断し続けます。
  • 14は15未満なので、左側のサブツリーに注目します。

このとき、左側のサブツリーは空であるため、15個のノードの左側のポインターとノードXの関係がポインターを介して直接確立され、挿入アクションが完了します。
ここに画像の説明を挿入
バイナリ検索ツリーにデータを挿入する時間の複雑さはO(logn)です。しかし、これは通常の二分木よりも複雑であることを意味しません。その理由は、ここでの時間の複雑さは、データをトラバースして検索位置を見つけることに費やされ、実際に挿入アクションを実行する時間の複雑さは依然としてO(1)であるためです。

3.3削除操作

特定のノードを削除した後のツリーは、バイナリ検索ツリーのプロパティを満たす必要があるため、バイナリ検索ツリーの削除操作はより複雑になりますディスカッションは、次の3つの状況に分けられます。

(1)削除するノードリーフノードの場合は、直接削除し、その親ノードポインターをnullにポイントします。
ここに画像の説明を挿入

(2)削除するノードに子ノードが1つしかない場合は、その親ノードが指す子ノードのポインターをその子ノードのポインターに置き換えます。
ここに画像の説明を挿入(3)削除するノードに2つのサブノードがある場合、実行可能な操作方法は2つあります。

  • 1つ目は、このノードの左側のサブツリーで最大のノードを見つけ、削除するノードを置き換えることです。

ここに画像の説明を挿入

  • 2つ目は、このノードの右側のサブツリーで最小のノードを見つけ、削除するノードを置き換えることです。

ここに画像の説明を挿入


この記事は「データ構造とアルゴリズムの再学習」を学習するための私の学習ノートです。学習とコミュニケーションにのみ使用されます。共有されるため、商業的に転載しないでください!記事の画像参照:https://kaiwu.lagou.com/course/courseInfo.htm?courseId=185#/detail/pc?id=3347

ここに画像の説明を挿入

最初に、次に見るように、習慣を身につけましょう!あなたのサポートが私の創造の最大の動機です!

おすすめ

転載: blog.csdn.net/wjinjie/article/details/108484738
おすすめ