mirror of
https://github.com/krahets/hello-algo.git
synced 2026-11-01 18:55:23 +08:00
* Retranslate the complete Japanese online edition from Chinese * Fit Japanese homepage labels and localize heading permalinks * Point Japanese contribution instructions to the Japanese preview * Replace locale conditionals with multilingual UI tables
6.1 KiB
6.1 KiB
グラフの基本操作
グラフの基本操作には、「辺」に対する操作と「頂点」に対する操作があります。「隣接行列」と「隣接リスト」では、実装方法が異なります。
隣接行列による実装
頂点数 n の無向グラフに対する各種操作は、下図のように実装できます。
- 辺の追加・削除:隣接行列の指定した辺を直接変更するだけなので、
O(1)時間です。無向グラフのため、両方向の辺を同時に更新する必要があります。 - 頂点の追加:隣接行列の末尾に行と列を一つずつ追加し、すべて
0で埋めます。O(n)時間かかります。 - 頂点の削除:隣接行列から行と列を一つずつ削除します。最悪の場合は先頭の行と列を削除するときで、
(n-1)^2個の要素を「左上に移動」するため、O(n^2)時間かかります。 - 初期化:
n個の頂点を受け取り、長さnの頂点リストverticesをO(n)時間で初期化します。n \times nの隣接行列adjMatの初期化にはO(n^2)時間かかります。
隣接行列によるグラフの実装を次に示します。
[file]{graph_adjacency_matrix}-[class]{graph_adj_mat}-[func]{}
隣接リストによる実装
無向グラフの頂点数を $n$、辺の総数を m とすると、下図の方法で各種操作を実装できます。
- 辺の追加:頂点に対応する連結リストの末尾に辺を追加するだけなので、
O(1)時間です。無向グラフのため、両方向の辺を同時に追加する必要があります。 - 辺の削除:頂点に対応する連結リストで指定した辺を探して削除するため、
O(m)時間かかります。無向グラフでは、両方向の辺を同時に削除する必要があります。 - 頂点の追加:隣接リストに連結リストを一つ追加し、新しい頂点をその先頭ノードにします。
O(1)時間です。 - 頂点の削除:隣接リスト全体を走査し、指定した頂点を含むすべての辺を削除するため、
O(n + m)時間かかります。 - 初期化:隣接リストに
n個の頂点と2m本の辺を作るため、O(n + m)時間かかります。
隣接リストの実装を次に示します。実際のコードは、上図と次の点が異なります。
- 頂点の追加と削除をしやすくし、コードを簡潔にするため、連結リストの代わりにリスト(動的配列)を使います。
- 隣接リストをハッシュテーブルに格納します。
keyは頂点のインスタンス、valueはその頂点に隣接する頂点のリスト(連結リスト)です。
また、隣接リストでは Vertex クラスで頂点を表します。隣接行列と同じようにリストのインデックスで頂点を区別すると、インデックス i の頂点を削除する際に、隣接リスト全体を走査し、i より大きいインデックスをすべて 1 ずつ減らす必要があり、非効率だからです。各頂点を固有の Vertex インスタンスにすれば、ある頂点を削除しても、ほかの頂点を変更する必要がありません。
[file]{graph_adjacency_list}-[class]{graph_adj_list}-[func]{}
効率の比較
グラフに n 個の頂点と m 本の辺があるとします。下表で、隣接行列と隣接リストの時間効率と空間効率を比較します。隣接リスト(連結リスト)は本節の実装に対応し、隣接リスト(ハッシュテーブル)は、すべての連結リストをハッシュテーブルに置き換えた実装を指します。
表 隣接行列と隣接リストの比較
| 隣接行列 | 隣接リスト(連結リスト) | 隣接リスト(ハッシュテーブル) | |
|---|---|---|---|
| 隣接しているかの判定 | O(1) |
O(n) |
O(1) |
| 辺の追加 | O(1) |
O(1) |
O(1) |
| 辺の削除 | O(1) |
O(n) |
O(1) |
| 頂点の追加 | O(n) |
O(1) |
O(1) |
| 頂点の削除 | O(n^2) |
O(n + m) |
O(n) |
| メモリ使用量 | O(n^2) |
O(n + m) |
O(n + m) |
上表だけを見ると、隣接リスト(ハッシュテーブル)が時間効率・空間効率ともに最も優れているように思えます。しかし実際には、隣接行列なら配列へのアクセスまたは代入が 1 回で済むため、辺の操作はより高速です。全体として、隣接行列は「空間を使って時間を節約する」考え方を、隣接リストは「時間を使って空間を節約する」考え方を表しています。









