データ構造の簡単な説明 - ツリーの概要

詳細については、WeChat で「 前端爱好者を検索し、 「私」をクリックしてご覧ください。

データ構造

データ構造はコンピューター サイエンスの基本概念の 1 つであり、効率的にアクセス、管理、操作できるようにデータを編成および保存する方法に関係します。データ構造はデータを記述または表現する方法であり、データの保存方法、関係、およびデータ操作の方法を定義します。

一般的なデータ構造タイプをいくつか示します。

  1. ツリー: これは、階層関係を持つデータを表すために使用される非線形データ構造です。ツリーの一般的な例はバイナリ ツリーであり、各ノードには最大 2 つの子ノードがあります。
  2. グラフ: これは、任意の数のノードとノード間の接続を表すために使用される非線形データ構造です。グラフは無向または有向にすることができ、サイクルを含めることができ、自己接続することもできます。
  3. ヒープ: これは、固有の要素を格納するために使用されるデータ構造です。コレクションの主な操作は、要素の追加 (add) と要素の削除 (remove) です。
  4. ハッシュ テーブル/ハッシュ テーブル (ハッシュ) : これは、高速検索操作を実装するために使用されるデータ構造です。ハッシュ テーブルは、ハッシュ関数を通じてキーをバケットにマッピングし、検索してバケットに保存します。
  5. スタック: これは、一方の端からのみ挿入および削除できる後入れ先出し (LIFO) データ構造です。スタックの主な操作は、プッシュ (要素の追加) とポップ (要素の削除) です。
  6. キュー: これは、一方の端から要素を追加し、もう一方の端から要素を削除できる先入れ先出し (FIFO) データ構造です。キューの主な操作は、エンキュー (要素の追加) と
  7. 配列: これは、同じタイプの一連の要素として見ることができる線形データ構造です。配列はメモリ内で連続しており、任意の位置の要素にインデックスによってアクセスできます。
  8. Likend List : これは一連のノードで構成される線形データ構造であり、各ノードには値と次のノードへのポインターが含まれます。リンク リストでは、すべての要素がメモリ内で連続している必要はありません。

これらの一般的なデータ構造にはそれぞれ独自の長所と短所があるため、特定のアプリケーション シナリオに従って適切なデータ構造を選択する必要があります。

たとえば、多数の要素の保存とアクセスには配列とハッシュ テーブルが、要素の挿入と削除操作の効率を維持する必要があるデータにはリンク リストと動的配列が、より良い選択となる可能性があります。要素の検索操作を維持する必要がある 効率的なデータ操作のためには、検索ツリーの方が良い選択かもしれません。

さらに、データ構造とアルゴリズムは密接に関連していることがよくあります。

さまざまなデータ構造とその操作方法を理解して習得することは、アルゴリズムをより効果的に設計および実装し、プログラムのパフォーマンスを最適化するのに役立ちます。

ツリー定義

树是n(n>=0)个结点的有限集。当n = 0时,称为空树

空ではないツリーでは、次の条件を満たす必要があります。

  • ルートと呼ばれる特定のノードは 1 つだけです。
  • n>1 の場合、残りのノードは m (m>0) 個の互いに素な有限集合 T1、T2、...、Tm に分割でき、各集合自体はツリーであり、ルートのサブツリーと呼ばれます。

明らかに、ツリーの定義は再帰的です。つまり、それ自体がツリーの定義で使用されます。ツリーは再帰的なデータ構造です。

ツリーは論理構造および階層構造として、次の 2 つの特性を持ちます。

  • ツリーのルート ノードには先行ノードがなく、ルート ノードを除くすべてのノードには先行ノードが 1 つだけあります。
  • ツリー内のすべてのノードは、0 個以上の後続ノードを持つことができます。

したがって、n 個のノードのツリーには n-1 個のエッジが存在します。

基本的な用語

ここでは樹木の基本的な用語や概念をイラストを交えて解説します。

结点、祖先、子孙、双亲、兄弟

ノードKについて考えてみましょう。ルート A からノード K への一意のパス上のノードは、ノード K祖先と呼ばれます。たとえば、ノード B はノード K の祖先であり、ノード K はノード B の子孫です。パス上のノード K に最も近いノードE は K のと呼ばれ、K はノード E の子です。ルート A は、ツリー内で親を持たない唯一のノードです。同じ親を持つノードは兄弟と呼ばれます。たとえば、ノード K とノード L は同じ親 E を持ちます。つまり、K と L は兄弟です。

ノードの次数、ツリーの次数

ツリー内のノードの子の数はノードの次数と呼ばれ、ツリー内のノードの最大次数はツリーの次数と呼ばれます。

たとえば、ノード B の次数は 2、ノード D の次数は 3、ツリーの次数は 3 です。

ブランチノード/非終端ノード、リーフノード/終端ノード
  • 次数が 0 より大きいノードはブランチ ノードと呼ばれます(非終端ノードとも呼ばれます)。
  • 次数 0 のノード (子ノードなし) は、リーフ ノード(ターミナル ノードとも呼ばれます) と呼ばれます。

ブランチ ノードでは、各ノードのブランチの数がノードの次数になります。

ノードの深さ、高さ、レベル
  • ノードの階層はツリーのルートから定義され、ルート ノードはレベル 1、その子ノードはレベル 2 などとなります。親が同じレベルにあるノードは互いにいとこです。図では、ノード G とノード E、F、H、I、J は互いにいとこです。
  • ノードの深さは、ルート ノードから始まり上から下に向かってレイヤーごとに累積されます。
  • ノードの高さは、リーフ ノードから始まり下から上に向かってレイヤーごとに累積されます。
  • ツリーの高さ (または深さ) は、ツリー内のノードの最大レベル数です。写真の木の高さは4です。
順序付けられたツリーと順序付けられていないツリー。
  • ツリー内のノードの各サブツリーは左から右に有次序不能互换と呼ばれ有序树、それ以外の場合は と呼ばれます无序树

画像が順序付けされた木であると仮定し、サブノードの位置を入れ替えると、それは木になります不同的树

パスとパスの長さ。

ツリー内の 2 つのノード間のパスは、2 つのノード間を通過する一連のノードで構成され、パスの長さはパス上を通過するエッジの数です。

注: ツリー内の枝は親から子へ向かうため、ツリー内のパスは上から下になり、同じ親の 2 つの子の間にパスはありません

森。

森はm (m ≥ 0) 個の木互不相交で構成されます集合

フォレストの概念はツリーの概念と非常によく似ています。ツリーのルート ノードが削除される限りフォレストになるからです。

逆に、m 個の独立したツリーにノードが追加され、これらの m 個のツリーがノードのサブツリーとして使用される限り、フォレストはツリーになります。

木の自然

ツリーには次の最も基本的なプロパティがあります。

ツリーストレージ構造

次の 3 つのストレージ構造を導入する過程で、次のツリーを例として取り上げます。

親の表現

ツリーのノードは一連の連続した空間に格納されており、各ノードにはリンク リスト内のノードの位置を示すインジケータが付けられていると双亲仮定します。言い換えれば、各ノードは、自分が誰であるかを知ることに加えて、その親がどこにいるかも知っています。

このうちデータは、ノードのデータ情報を格納するデータフィールドです。そして、parent は、配列内のノードの親の添字を格納するポインター フィールドです。

以下は、親表現のノード構造定義コードです。

/*树的双亲表示法结点结构定义*/
#define MAX_TREE_SIZE 100
typedef int TElemType;	//树结点的数据类型,目前暂定为整型

/*结点结构*/
typedef struct PTNode{
    
    
	TElemType data;	//结点数据
	int parent;	//双亲位置
}PTNode;

/*树结构*/
typedef struct{
    
    
	PTNode nodes[MAX_TREE_SIZE];	//结点数组
	int r, n;	//根的位置和结点数
}PTree;

このようなストレージ構造を使用すると、ノードの親ポインタに基づいて親ノードを簡単に見つけることができます。使用される時間計算量は 0(1) です。親が -1 の場合、ツリー ノードのルートが見つかったことを意味します。

ただし、ノードの子が何であるかを知りたい場合は、申し訳ありませんが、お願いします遍历整个结构

子の表現

具体的な方法は:各ノードの子ノードを配置し、単一リンク リストを記憶構造として使用します。n 個のノードには n 個の子リンク リストがあります。リーフ ノードの場合、単一リンク リストは空です。次に、n 個のヘッド ポインターが線形テーブルを形成します。このテーブルは、図に示すように、シーケンシャル ストレージ構造を使用し、1 次元配列に格納されます。

この目的のために、2 つのノード構造が設計されています。

1 つは子リンク リストの子ノードです。

で:

child是数据域,用来存储某个结点在表头数组中的下标。
next 是指针域,用来存储指向某结点的下一个孩子结点的指针。

もう 1 つはヘッダー配列のヘッダー ノードです。

で:

data是数据域,存储某结点的数据信息。
firstchild 是头指针域,存储该结点的孩子链表的头指针。

以下は、子表現の構造定義コードです。

/*树的孩子表示法结构定义*/
#define MAX_TREE_SIZE 100

/*孩子结点*/
typedef struct CTNode{
    
    
	int child;
	struct CTNode *next;
}*ChildPtr;

/*表头结点*/
typedef struct{
    
    
	TElemType data;
	ChildPtr firstchild;
}CTBox;

/*树结构*/
typedef struct{
    
    
	CTBox nodes[MAX_TREE_SIZE];	//结点数组
	int r, n;	//根的位置和结点数
}

このような構造を使用すると、ノードの子を検索したり、ノードの兄弟を検索したりする場合、このノードの子の単一リンク リストを検索するだけで済みます。また、ヘッド ノードの配列をループするだけで、ツリー全体を走査するのにも非常に便利です。

しかし、問題もあります。特定のノードの親が誰であるかをどうやって知るか?それはさらに面倒です。ツリー全体を走査する必要があります。親の表現と子の表現を結合することは可能ではないでしょうか? もちろん、それは可能です。可能です。読者は自分で組み合わせてみてください。ここでは詳細には触れません。

子供の兄弟の代表

先ほどはツリーの記憶構造を親の観点と子の観点から調べましたが、ツリーノードの兄弟の観点から見てみるとどうなるでしょうか?

もちろん、ツリーのような階層構造では、ノードの兄弟だけを研究することはできませんが、観察の結果、どのツリーでもそのノードが存在することがわかりました第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的したがって、ノードの最初の子とノードの右の兄弟を指す 2 つのポインターを設定します。

ノードの構造は次のとおりです。

で:

  • data はデータフィールドです。
  • firstchild は、ノードの最初の子ノードの記憶アドレスを格納するポインタ フィールドです。
  • rightib は、ノードの右側の兄弟ノードのストレージ アドレスを格納するポインタ フィールドです。

この表現は、ノードの子を見つけるのに便利です。

構造体定義コードは以下のとおりです。

/*树的孩子兄弟表示法结构定义*/
typedef struct CSNode{
    
    
	TElemtype data;
	struct CSNode *firstchild, *rightsib;
} CSNode, *CSTree;

この構造により、元のツリーを次のようなものに変えました。

これはただの二分木ではないでしょうか?

はい、実際、この表現の最大の利点は、複雑なツリーをバイナリ ツリーに変換できることです。

参考資料

  • https://blog.csdn.net/Bb15070047748/article/details/119208588
  • https://blog.csdn.net/Real_Fool_/article/details/113930623

おすすめ

転載: blog.csdn.net/BradenHan/article/details/135258400
おすすめ