グラフ/グラフ保存/グラフ走査

グラフの概念: グラフのデータ構造は 2 つのセットで構成され、1 つは頂点セット V (頂点)、もう 1 つはエッジセット E (Edge) です。無向グラフは一般に G(V , E として記録されます) ); 有向グラフは G<V, E> として記録されます。

有向グラフとは、エッジの方向が方向によって区別されることを意味します。たとえば、A→B、AからB、ただしBはAに到達できません(有向グラフのエッジは円弧と呼ばれる矢印であり、円弧の頭は w 、円弧の尾は v)
無向グラフのエッジには方向の区別がなく、AB である限り、A から B へ、および B から A へ移動できます。

重要な概念は次のとおりです。

1: グラフは空のグラフであってはなりません。つまり、頂点セットは空であってはならず、エッジ セットは空であっても構いません。 2: 完全な
グラフ: 任意の 2 つの頂点の間にエッジがある場合 (エッジに注意してください)ここにある 2 つの頂点は互いに直接接続されています)、グラフは完成したと言われます。
無向完全グラフには n*(n-1) / 2 つのエッジがあります。
有向完全グラフは n*(n-1) 個のエッジを持ちます。
3: サブグラフ: グラフ内の特定の部分の頂点と、その頂点に接続されたエッジの一部で構成される新しいグラフがサブグラフです。(単に「エッジのサブセット」や「頂点のサブセット」と表現してはいけないことに注意してください。サブグラフを形成するには頂点に接続されたエッジでなければなりません)

無向グラフの場合、非常に重要な概念は次のとおりです。

4: 接続されています: 頂点 A から頂点 B へのパスがある場合、AB は接続されていると言われます。
5: 接続されたグラフと接続されていないグラフ: グラフ内の 2 つの頂点にパスがある場合 (必ずしも直接接続されたパスである必要はありません。ここでは完全なグラフの概念とは区別されます)、一部の頂点が他の頂点に接続されていない、つまり一部の頂点が孤立している場合、グラフは接続グラフと呼ばれます。これは文字通り「グラフ全体が接続されている」ことを意味します。 、これは非接続グラフと呼ばれます。
6: 連結成分 (最大連結部分グラフとも呼ばれます): グラフ G に ABC 連結と DE 連結がある場合、2 つの連結成分、つまり 2 つの最大連結部分グラフがあると言われます (つまり、グラフ G、、接続されたサブグラフ)。
ここに画像の説明を挿入
(7) 無向グラフの場合、接続されたグラフを形成するには N 個の頂点が少なくとも N-1 個のエッジを必要とします (描画が理解しやすい)。N 個の頂点が完全なグラフを形成する必要がある場合、少なくとも n*(n-1) は次のようになります。必要/2面。
エッジの数が n-1 未満の場合、グラフを切断する必要があります。

有向グラフの場合、非常に重要な概念は次のとおりです。

8: 強い接続性: この概念は、無向グラフの接続性とは区別する必要があります。有向グラフは有向性があるため、その接続性は「より強力な」接続性でなければなりません。そのため、強い接続性を覚えておいてください。AB が強く接続されている場合、A->B および A<- B が存在する必要があります。つまり、強い接続性と呼ばれるには両方向が存在する必要があります。
9: 強接続グラフ: 有向グラフ G で、グラフ内の任意の 2 つの頂点にパスがある場合 (直接接続パスは必要ありません。パスがある限り N 個の頂点を通過できます)、グラフ G は次のようになります。強連結グラフ
10: 強連結成分 (超強連結サブグラフとも呼ばれます): 無向グラフの連結成分の概念とは区別する必要があります。強連結成分とは、サブグラフ内に循環が存在する必要があることを意味します。有向グラフに強い連結成分があるかどうかを判定する. 連結成分の場合はループを見つける必要がある. ループが存在しない場合, 最後の頂点 D から最初の頂点 A まで遡ることができないことが証明される. D から A へのパスがない場合、強く接続されていません。
11: 有向グラフの場合、N 個の頂点を持つ有向グラフで強く接続されたグラフを形成するには、少なくとも n 個のエッジ (リングを形成) が必要です。有向完全グラフ (有向完全グラフは強く接続されたグラフでなければならず、どの頂点にも 2 つの前後の矢印パスがある) を形成するには、n*(n-1) 個のエッジが必要です。

最大接続サブグラフと最小接続サブグラフ:

12: これらはすべて無向グラフ用です。最大値と最小値の違いは、最大値にはサブグラフのすべてのエッジが含まれている必要があること、つまり、接続されているだけでなく、すべてのエッジが保持されている必要があることです。最小接続サブグラフでは、グラフが確実に接続される、つまり接続できるようにするために、最小数のエッジを維持するだけで済みます。
注 ⚠️: スパニング ツリーは最小接続のサブグラフですが、スパニング ツリーは最大接続のサブグラフではありません (すべてのエッジが含まれていないため)。したがって、当然のことながら、スパニング ツリーは接続コンポーネントではありません。

密なグラフと疎なグラフ:

13: 密、疎はエッジのことで、エッジの数が密、エッジの数が疎です。(漁網を想像してください。面が多ければ、網全体は非常に密になります。面が少なければ、網全体は非常にまばらになります。)

グラフの例:

(1) N 個の頂点と N 個のエッジを持つ無向グラフにはサイクルが必要です (各頂点にエッジがある場合はサイクルが存在する必要があることがグラフを描くことでわかります) が、サイクルは必ずしも接続されているわけではないことに注意してください。それはエッジの数に依存します (n 個のノードを持つ無向グラフに n*(n-1)/2 のエッジがある場合、それは完全なグラフである必要があり、完全なグラフは接続されており、サイクルを持っている必要があります)。 vertex ディープ検索を実行するかワイド検索を実行するかは、グラフ全体を横断することができます。

(2) グラフの横断は、単に特定の頂点から開始して残りの頂点を横断することではありません。グラフは切断されている可能性があるため、特定の頂点から開始すると、特定のサブグラフのみをトラバースでき、他のサブグラフの頂点をトラバースすることはできません。そのため、グラフをトラバースするには、頂点セット V をループし、トラバースする必要があります。 1 つのトラバーサルが完了した後、まだトラバーサル マークでマークされていない頂点がいくつかある場合は、頂点セット V のすべての頂点 (この時点のサブグラフ内の頂点) がトラバーサル マークでマークされるまで、次のサイクルが開始されます。時間も走査としてマークされています) は、完全なグラフ走査とみなされます。

(3) 28 個の辺を持つ非接続無向グラフには少なくとも () 頂点がある
分析: 28 個の接続されていない辺があり、最小の頂点数が必要です。頂点の数が最も少ない場合、頂点の数はこの放蕩息子の場合、28 個のエッジで無向完全グラフがいくつ形成できるかを見て、式を代入してみましょう: N*(N-1) / 2 = 28; 解は N です= 8; 8 つの頂点は 28 個のエッジによって形成されます 完全に無向グラフが作成されますが、トピックは接続されていないため、孤立した頂点を追加します (頂点は 9 つで十分です)。同様のトピックはたくさんありますが、それらはすべて、無向グラフと有向グラフの完全なグラフのエッジの数の式に関するものです。


(4) [2010] 無向グラフ G(V , E) に 7 つの頂点がある場合、どのような場合でもグラフ G が確実に接続されるようにするには、頂点が 7 つあるため、少なくとも (16) のエッジが必要です。あらゆる状況が接続されていることを確認します。追加されるエッジの数のみが表示され、別のエッジを追加するには接続する必要があります。つまり、最初にその 6 つの頂点で無向の完全なグラフを形成し、6 * (6-1) / 2 = を消費します。エッジが 15 個ある場合、+ 1 = 16 なので、7 番目の頂点に接続する必要があります。このようにして、グラフ G は接続されたグラフであることが保証されなければなりません。すでに 15 個のエッジで 6 つの頂点が埋められているため、追加のエッジを追加する場所がなく、7 番目の頂点との関係のみを持つことができ、関係が発生すると、すぐに接続されたグラフが形成されます。


6 つの頂点を持つ無向グラフの場合、() エッジがある場合、接続されたグラフであることが保証できます

(5) グラフ G は n 個の頂点を持ちますが、接続された無向グラフの場合、辺の数は少なくとも次のようになります:
式によれば、接続性が保証されている限り、n 個の頂点を持つ無向グラフは n-1 だけ必要です強く接続された有向グラフ
の場合、エッジの数は少なくとも次のとおりです:
式によれば、強い接続性を確保するには、n 個の頂点が n 個のエッジを使用してリングを囲む必要があります。

(6) 無向グラフ G には 23 の辺があり、次数 4 の頂点が 5 つ、次数 3 の頂点が 4 つ、残りは次数 2 の頂点です。グラフ G には合計でいくつの頂点がありますか?
分析:
1 つのエッジは 2 度を寄与できるため、合計 46 度があり、次数 4 の 5 つの頂点は 20 度を消費します。次数 3 の 4 つの頂点は 12 度を消費します。残りの 46 - 12- 20 = 14。タイトルには次のように書かれています。残りは次数 2 なので、14 / 2 = 7、つまり次数 2 の頂点が 7 つあり、グラフ G には合計 7 + 5 + 4 = 16 つの頂点があります。

(7) n 個の頂点と e 個のエッジを持つ無向グラフがフォレストである場合、そのフォレストには () ツリーがなければなりません。
極端ではあるが合理的な例 (たとえば、次数が 3 のツリーには 10086 個のノードがあり、深さを尋ねます)と木の高さ、ノード スタックの数として 10083 を直接使用し、葉ノードの倒錯的な例として最後の 3 を使用します) アイデア 1: ここでは、森に
x 本の木があると仮定します。その場合、x- を使用する必要があります。新しいツリーを形成するための 1 つのエッジですが、元の x ツリーには e つのエッジがあるため、新しいツリーには合計 x-1+e のエッジがあります。ツリーの性質によれば、ルート ノードにエッジが接続されていないことを除き、他のすべてのノードにはそれを指すエッジが少なくとも 1 つあるため、サマリー ポイントの数 = エッジの総数 + 1 は n = (
x- 1+e) + 1
x = ne
アイデア 2: たとえば、e 個のエッジのそれぞれが 2 つの頂点に接続されてツリーを形成すると仮定すると、2e 個の頂点が消費されて e ツリーが形成され、残りの頂点で 1 つのツリーが形成されます。エッジ ツリーを含まない単一ツリー、つまり残り: n - 2e 頂点、合計 n - 2e ツリー、
合計: n-2e+e = n - e ツリーになります。

(8) [2017] 既知の無向グラフ G には 16 個のエッジ、次数 4 の頂点 3 つ、次数 3 の頂点 4 つ、次数 3 未満のその他の頂点が含まれている場合、グラフ G に含まれる頂点の数は少なくとも ()
分析:
16 の辺が 32 度を割り当て、次数 4 には 3 があり、12 度を消費します。次数 3 には 4 があり、12 度を消費します。その後、残り: 32 - 12 -12 = 8 度; 残り 次数 1 と 2 の頂点が存在する可能性があります
。ただし、トピックに含まれる頂点の数は少なくとも、つまり許可される頂点の最小数である必要があります。その場合、次数 2 を選択する必要があります。そのような頂点は 2 度を消費し、残りをできるだけ早く消費できます。度。8 / 2 = 4; つまり、次数 2 の頂点があと 4 つだけ必要になります。頂点の合計は3 + 4 + 4 = 11
になります。

グラフストレージ

隣接行列法 (密なグラフに適しています):

typedef struct {
    
    
	char v[100];
	int e[100][100];
} Graph;
隣接行列法で無向グラフを保存する場合、次数と次数を区別しないため、対称行列である必要があります。対称行列であるため、圧縮ストレージ、つまり上位または次数のみをサポートします。下三角部分が密に保存されるので、グラフの応用において非常に効果的です。

具体的な保存方法は以下の通りです。
頂点が4つの無向グラフの場合
(1)頂点がABCDあると仮定して4*4の正方行列を生成し、行と列をABCDとし、先頭から順に行から先頭まで A列は01から始まります(辺1あり、辺0なし)
ここに画像の説明を挿入
この行列の番号は1なので、ある地点からある地点までの経路長が何本あるかを表します1. すると、A から A までの長さがゼロ、A から B、B から C であることがはっきりわかります。
(2) 行列をそれ自体で乗算すると、行列の 2 乗が得られます。平方次数は 2 で、これは、ある点からある点まで、経路長 2 の経路が何本あるかを意味します: たとえば、
ここに画像の説明を挿入
行列から反映すると、A から A への経路が 2 本あります。 [A]と[B](左の行列2列の1行目)×【B】【A】(右の行列の1行目2列目)の2の長さ+【A 】【C】×【C】【A】=2。また、これら 2 つのルートは、A から B、次に B から A、または A から C、そして C から A であることも意味します。これは驚くべきことですか。別の例を挙げてください。C から C への新しい行列は次のとおりです
。 Cの経路長2の3ルート
【C】【A】×【A】【C】 + 【C】【B】×【B】【C】 + 【C】【D 】 【D】【C】を掛ける=3
つまり、CからA、そしてAからCに戻る、
CからB、そしてBからCに戻る、
CからD、そしてDからCに戻る
ルートとルートを完璧に組み合わせた番号が表示されます。

(3) 正方形を 2 つ掛けて 3 次行列にすると、ある地点からある地点まで、経路長 3 の経路が何本あって、どのように進むかがわかります。
ここに画像の説明を挿入

パス長 2 に基づいて、A から C までのパス長 3 のルートが 4 つあります。

(1) 【A】【A】×【A】【C】 + (2) 【A】【B】×【B】【C】 + (3) 【A】【D】×【D】 [C] = 4
左側の行列は正方形に基づいて取得されるため、正方形に戻るときにロードマップを確認する必要があります。
これは長さ 3 の 4 つのパスを表します:
(1)
ここで [A] [ A]は行列です 【A】【B】×【B】【A】+【A】【C】×【C】【A】=2をAからBへ、そしてBから戻ると2乗したときに生成されるパスA から A
、そして
A から C へ、A から C へ、そして C から A に戻り、そして A から C へ
(2)
[A] [B] は行列を 2 乗したときに生成されるパス [ A] [C] に [C] [B] を乗算する = 1
A から C、次に C から B、そして B から C
(3)
[A] [D] は行列が次の場合に生成されるパスです。 [A] [C] の 2 乗に [C] [D] を乗算 = 1、
A から C、次に C から D、最後に D から C に戻ります。

このように迂回するのはばかばかしいように思えますが、これは確かに、ある地点からある地点に道がつながっていることを示すことができます。戻りたくない場合は、他のビジネス ロジックを追加してフィルタリングすることができます。この効果は今でも非常に強力です。
隣接行列には有向グラフが格納されます。

有向グラフでは、出力次数を表すのに 1 が使用されます。これは、出力グラフの対応する添字が 1 で、入力次数が 0 であることを意味します (ここで 1 は、この道路が通行可能であることを意味し、入力次数が 0 であることを意味します)。有向グラフの次数は現在の頂点に対するものです。通行不可です。これは道路がないことに相当します。したがって 0 です。外側の次数のみが通行可能です。これは 1) 必要に応じて、ここではパスの長さ 1 も参照します
ここに画像の説明を挿入
。 2の経路長を確認するには、これを行うこともできます行列の2乗は無向グラフと同じです

利点:
直観的で便利、シンプル、コーディングの実装が簡単です。
密なグラフを格納する場合、上三角行列と下三角行列を1次元配列に変換する圧縮方法を組み合わせた無向グラフであれば、大幅なスペースを節約できます。

短所:
効率が比較的低く、計算量が多く、中間結果の保存に多くのメモリ スペースが必要になります。
行列はn*n正方行列に固定されているため、スパースなグラフだと不要な空き領域が大量に生成されてしまいます。
隣接行列内のノードを削除したい場合は、時間計算量 O(n) をトラバースする必要があります。

隣接リスト方式

スパース行列をより効率的かつ便利に保存するために、配列 + リンク リスト (ハッシュ テーブルに似た) の保存方法を使用し、各頂点に配列の添え字の位置を割り当て、同時に頂点に接続された配列添字の位置を割り当てます。頂点の配列添字はノードの後ろにリンクされます。

// 边表结点
typedef struct ArcNode{
    
    
	int index;   // 该边指向的顶点的数组下标
	struct ArcNode *next; 		//下一个边表结点的指针
} ArcNode;

// 顶点表结点
typedef struct VNode{
    
    
	char data;  // 顶点信息,存储例如:ABCD,1234之类的值
	ArcNode *next;    // 链接第一个边表结点
} AdjList[100];

// 邻接表结构
typedef struct {
    
    
	AdjList[100];
	int vexnum; arcnum;  // 顶点数和弧数
} ALGraph

無向グラフの場合、エッジは同時に 2 つのエッジ テーブル ノードに存在しますが、有向グラフの場合、エッジのみが記録され、エッジは 1 つのエッジ テーブル ノードにのみ存在します (この図) Wangdao
ここに画像の説明を挿入
データ構造から取得されます)

無向グラフを格納するために隣接リストが使用される場合は、偶数のエッジ テーブル ノードが存在する必要があり、奇数のエッジ テーブル ノードの場合は、有向グラフである必要があります。

例:
(1) n 個の頂点を持つ無向グラフの隣接リストには、最大で (n*(n-1)) 個のエッジ リスト ノードがあります。 分析 : n 個の
頂点を持つ無向グラフの場合、それが完全なグラフであれば、ほとんどのエッジ。最大で n*(n-1) / 2 個のエッジがあり、各エッジは 2 つのエッジ テーブル ノードを生成するため、最大で n*(n-1) 個のエッジ テーブル ノードが存在します。

(2) n 個の頂点があり、e エッジの有向グラフが隣接リストで表されると仮定すると、特定の頂点 v に関連するすべてのエッジを削除する時間計算量は次のようになります。 O(n+e) 分析:特定の
頂点を削除するには
頂点のすべてのエッジについて、ループして対応する頂点 v を見つけ、その出力エッジ テーブルを順番に削除する必要があります。このとき、頂点 v の出力エッジはすべて削除されます。ほとんどの n-1 出力エッジ テーブル、つまり v が他のすべての頂点に対して出力エッジを持っていると仮定します
。上記のサイクルでは、その入力エッジを削除する必要があります。入力エッジを削除するには、最初に頂点テーブル ノード O(n) を走査し、 V を除く頂点テーブル ノードの出力エッジ テーブルを 1 つずつ見つけます。O(e) をリンクし、V に関連する出力エッジを削除します。これにより、V の入力エッジも消えます。合計の複雑さは O(n+
e )

(3) [2021] 無向接続グラフ G は、G 内の奇数次数の頂点の数が偶数であるとき、頂点集合 V と辺集合 E から構成されることが知られています。 |E|>0 2 より大きい場合、G には |E| の長さのすべてのパス (EL と呼ばれる) パスが含まれます (グラフ G は隣接行列に格納されます) (1)
G に EL パスが存在する場合、それがあるかどうかを判断するアルゴリズムを設計します。 、1を返す、それ以外の場合は0を返す; アルゴリズムを与える 基本的な考え方
(実を言うと、タイトルに記載されている内容を当時見ました。奇数次数と偶数次数以下の頂点の数) 2 には EL パスが含まれていました。このセクションは長い間行き詰まっていて、理解したくありませんでした。また、奇数の頂点の数を数えるだけでよいことがわかったのも、分析を読んだ後です。フェザー EL パスに関係なく、それが 0 か 2 かを確認します) 隣接行列を使用しているため、外側のループを開始するだけで済みます。
最初の行から最後の行までを移動し、メモリ ループは最初の列から移動します。最後の列まで、各行は頂点の入出力次数情報です。1 の場合は ++、最後にその次数を使用して %2=0 かどうかを判断し、はいの場合は、現在の頂点が偶数であることを証明します。 、そうでない場合は、現在の頂点の次数が奇数であることを証明し、奇数頂点 sum++;
最後に合計が 0 か 2 かを確認し、ある場合は EL パスがあり、そうでない場合は存在しません。

(2) コード

(3) 設計したアルゴリズムの時間計算量と空間計算量を説明する
隣接行列は n*n の正方行列であるため、サイクルコストは O(n^2)、空間計算量は O(1)

グラフの走査:

深さ優先 BFS (進む道がない場合は 1 つのパスに最後まで集中し、その後戻って別のパスを選択します)

ここに画像の説明を挿入

処理:
補助キューの初期化
(1) ルートノード a から始めてノード b とノード c が接続されていると仮定し、まず a をキューに入れ、次に a をキューから取り出し、次に b、c をキューに入れます。キュー (2) b
アウト チーム、b の近くに de をチームに入れる; c チームの外、c の近くに fg をチームに入れる
(3) d アウト、hi in、e out、チームには何もない、f out、j in, g チーム外、k チーム内
(4) hi チーム外、jk チーム外
(5) 深さ検索が完了
補助配列を使用しているため、サイズは通常、数値に設定されます
隣接リスト ストレージを使用する場合の空間計算量は O(V) です。時間:
頂点の接続点を検索するとき、エッジに沿って探索するため、各エッジは片側を横断する必要があり、時間計算量は次のようになります。 O(E).
隣接行列ストレージを使用する場合:
N*N 頂点の正方行列のため、時間計算量は O(V^2) 倍になります

幅優先スパニングツリーと呼ばれる、幅優先に従ってツリーを生成できますが、幅優先スパニングツリーは一意ではありません
幅優先 DFS (近くから遠くまで、各方向の各ステップ)

ここに画像の説明を挿入
深さ検索は通常、再帰的に実行されます
(1) a から開始し、最初に b を見つけ、b から d、d から h、最初のパスが終了し、d に戻ります
(2) d から i、2 番目のパスも終了します。 、dに戻り、dはこの道を通過したことがわかり、bに戻ります
(3)bからeへ、最後にbに戻り、bは道路を通過したことがわかり、aに戻ります(4)
aからc 。
(5) すべてのパスがなくなるまで手順 1 ~ 4 を続行します (これが深さ優先探索です)

頂点の数、再帰の回数、再帰に使用される再帰作業スタック、つまり空間複雑さは O(V) です。

隣接リスト ストレージを使用する場合:
時間計算量は O(V + E)、
隣接行列ストレージを使用する場合:
N*N 頂点の正方行列のため、時間計算量は O(V^2) 倍

同様に、深さ優先探索に従って、深さ優先スパニングツリーも生成できます。

おすすめ

転載: blog.csdn.net/whiteBearClimb/article/details/127984040