コンテンツにスキップ

9.1   グラフ

グラフは非線形データ構造の一種で、頂点で構成されます。グラフ\(G\)は、頂点の集合\(V\)と辺の集合\(E\)の組み合わせとして抽象的に表現できます。以下の例は、5つの頂点と7つの辺を含むグラフを示しています。

\[ \begin{aligned} V & = \{ 1, 2, 3, 4, 5 \} \newline E & = \{ (1,2), (1,3), (1,5), (2,3), (2,4), (2,5), (4,5) \} \newline G & = \{ V, E \} \newline \end{aligned} \]

頂点をノード、辺をノードを接続する参照(ポインタ)と見なすと、グラフは連結リストから拡張されたデータ構造として見ることができます。下図に示すように、線形関係(連結リスト)や分割統治関係(木)と比較して、ネットワーク関係(グラフ)は自由度が高いため、より複雑です

連結リスト、木、グラフの関係

図 9-1   連結リスト、木、グラフの関係

9.1.1   グラフの一般的な種類と用語

グラフは、辺に方向があるかどうかによって無向グラフ有向グラフに分けることができます(下図参照)。

  • 無向グラフでは、辺は2つの頂点間の「双方向」接続を表します。例えば、Facebookの「友達」関係です。
  • 有向グラフでは、辺に方向性があります。つまり、辺\(A \rightarrow B\)\(A \leftarrow B\)は互いに独立しています。例えば、InstagramやTikTokの「フォロー」と「フォロワー」の関係です。

有向グラフと無向グラフ

図 9-2   有向グラフと無向グラフ

すべての頂点が接続されているかどうかによって、グラフは連結グラフ非連結グラフに分けることができます(下図参照)。

  • 連結グラフでは、任意の頂点から開始して他の任意の頂点に到達することが可能です。
  • 非連結グラフでは、任意の開始頂点から到達できない頂点が少なくとも1つ存在します。

連結グラフと非連結グラフ

図 9-3   連結グラフと非連結グラフ

辺に重み変数を追加することもでき、その結果として重み付きグラフが生まれます(下図参照)。例えば、Instagramでは、システムがあなたと他のユーザーとの間の相互作用レベル(いいね、閲覧、コメントなど)によってフォロワーとフォロー中のリストをソートします。このような相互作用ネットワークは重み付きグラフで表現できます。

重み付きグラフと重みなしグラフ

図 9-4   重み付きグラフと重みなしグラフ

グラフデータ構造には、以下のような一般的に使用される用語があります。

  • 隣接:2つの頂点を接続する辺がある場合、これら2つの頂点は「隣接」していると言われます。上図では、頂点1の隣接頂点は頂点2、3、5です。
  • パス:頂点Aから頂点Bまでに通過する辺のシーケンスを、AからBへのパスと呼びます。上図では、辺のシーケンス1-5-2-4は頂点1から頂点4へのパスです。
  • 次数:頂点が持つ辺の数です。有向グラフの場合、入次数はその頂点を指す辺の数、出次数はその頂点から出る辺の数を指します。

9.1.2   グラフの表現

グラフの一般的な表現には「隣接行列」と「隣接リスト」があります。以下の例では無向グラフを使用します。

1.   隣接行列

グラフの頂点数を\(n\)とすると、隣接行列\(n \times n\)の行列を使用してグラフを表現します。各行(列)は頂点を表し、行列要素は辺を表し、2つの頂点間に辺があるかどうかを\(1\)または\(0\)で示します。

下図に示すように、隣接行列を\(M\)、頂点のリストを\(V\)とすると、行列要素\(M[i, j] = 1\)は頂点\(V[i]\)と頂点\(V[j]\)の間に辺があることを示し、逆に\(M[i, j] = 0\)は2つの頂点間に辺がないことを示します。

隣接行列によるグラフの表現

図 9-5   隣接行列によるグラフの表現

隣接行列には以下の特性があります。

  • 頂点は自分自身に接続することはできないため、隣接行列の主対角線上の要素は意味がありません。
  • 無向グラフの場合、両方向の辺は等価であるため、隣接行列は主対角線に関して対称です。
  • 隣接行列の要素を\(1\)\(0\)から重みに置き換えることで、重み付きグラフを表現できます。

隣接行列でグラフを表現する場合、行列要素に直接アクセスして辺を取得できるため、追加、削除、検索、変更の操作が効率的で、すべて時間計算量\(O(1)\)です。ただし、行列の空間計算量は\(O(n^2)\)で、より多くのメモリを消費します。

2.   隣接リスト

隣接リスト\(n\)個の連結リストを使用してグラフを表現し、各連結リストノードは頂点を表します。\(i\)番目の連結リストは頂点\(i\)に対応し、すべての隣接頂点(その頂点に接続された頂点)を含みます。下図は隣接リストを使用して格納されたグラフの例を示しています。

隣接リストによるグラフの表現

図 9-6   隣接リストによるグラフの表現

隣接リストは実際の辺のみを格納し、辺の総数は\(n^2\)よりもはるかに少ないことが多く、より空間効率的です。ただし、隣接リストで辺を見つけるには連結リストを走査する必要があるため、その時間効率は隣接行列ほど良くありません。

上図を観察すると、隣接リストの構造はハッシュテーブルの「チェイン法」と非常に似ているため、同様の方法を使用して効率を最適化できます。例えば、連結リストが長い場合、それをAVL木や赤黒木に変換して、時間効率を\(O(n)\)から\(O(\log n)\)に最適化できます。連結リストをハッシュテーブルに変換することで、時間計算量を\(O(1)\)に削減することもできます。

9.1.3   グラフの一般的な応用

下表に示すように、多くの現実世界のシステムはグラフでモデル化でき、対応する問題はグラフ計算問題に削減できます。

表 9-1   現実生活の一般的なグラフ

頂点 グラフ計算問題
ソーシャルネットワーク ユーザー フォロー / フォロワー関係 潜在的フォロー推薦
地下鉄路線 駅間の接続性 最短ルート推薦
太陽系 天体 天体間の重力 惑星軌道計算