幅優先探索と深さ優先探索の違い:訪れる順・データ構造・最短経路・メモリ・用途を比較

どちらも、グラフや木の頂点を、辺をたどって漏れなく訪れる探索の方法です。幅優先探索(BFS)は、出発点から辺1本で行ける頂点をすべて訪れてから、2本で行ける頂点へ、というように近い順に広がっていきます。深さ優先探索(DFS)は、1本の道を行けるところまで進み、行き止まりになったら戻って別の道を進みます。幅優先探索はキュー、深さ優先探索はスタックか再帰で実装し、隣接リストで表したグラフなら、どちらも頂点の数と辺の数の和に比例する手間で全体を訪れます。辺に重みのないグラフの最短経路を求めるなら幅優先探索、すべての道を調べ尽くす処理や閉路の検出なら深さ優先探索がよく使われます。

項目幅優先探索(BFS)深さ優先探索(DFS)
訪れる順出発点から近い順(たどる辺の数が少ない順)に、層ごとに広がる1本の道を奥まで進み、行き止まりになったら戻って、次の道へ進む
使うデータ構造キュー(先入れ先出し)スタック(後入れ先出し)、または再帰の呼び出し
最短経路辺に重みのないグラフでは、最初に到達したときの辺の数が、出発点からの最短になる最短は保証されない。遠回りの経路で先に到達することがある
計算量(頂点の数 V、辺の数 E)隣接リストでは O(V + E)、隣接行列では O(V²)幅優先探索と同じく、隣接リストでは O(V + E)、隣接行列では O(V²)
使うメモリ次に訪れる頂点をキューに覚えておく。枝分かれが多いと、1つの層の頂点がまとめてキューに入り、大きくなる再帰で書くと、今たどっている道の上の頂点を覚えておけばよく、道の深さに比例する。深すぎると、コールスタックがあふれることがある
解が見つかるか頂点が有限なら、必ず見つかる。探索の範囲が際限なく広がる場合でも、浅い位置の解から順に見つかる有限のグラフで訪れた頂点を記録すれば、必ず見つかる。際限なく深くなる場合は、1本の道を進み続けて戻ってこないことがある
木をたどる順レベル順(根から近い段ごとに、左から右へ)先行順(行きがけ順)、中間順(通りがけ順)、後行順(帰りがけ順)
主な用途重みのないグラフの最短経路、迷路の最短の手数、ネットワークで何段先まで届くかの計算迷路やパズルの全通りの探索(バックトラック)、連結成分や閉路の検出、トポロジカルソート

数値は代表的な目安で、世代や製品によって異なります。

どんなときに使うか

幅優先探索
辺に重みのないグラフで、最短の手数や経路を求めたいとき、出発点の近くから順に調べたいときに向きます。辺に重みがあるときの最短経路には、ダイクストラ法を使います。
深さ優先探索
すべての道や組み合わせを調べ尽くしたいとき、連結成分や閉路を見つけたいとき、作業の順序を決めるトポロジカルソートのときに向きます。再帰で短く書けます。

よくある質問

辺に重みがあるときも、幅優先探索で最短経路が求まりますか?

求まりません。たどる辺の数が最も少ない経路が、重みの合計も最も小さいとは限らないからです。重みが0以上なら、ダイクストラ法を使います。ダイクストラ法は、キューの代わりに、出発点からの距離が小さい頂点から取り出す優先度付きキューを使う方法で、幅優先探索を重みのあるグラフへ広げたものと見ることもできます。

深さ優先探索は、再帰とスタックのどちらで書けばよいですか?

再帰で書くと短く分かりやすくなりますが、とても深いグラフでは、呼び出しが重なってコールスタックがあふれることがあります。自分でスタックを用意して繰り返しで書けば、これを避けられます。ただし、隣の頂点をスタックに積む順番によっては、再帰と訪れる順が変わることがあります。

訪れた頂点を記録しないと、どうなりますか?

閉路のあるグラフでは、同じ頂点を何度も訪れてしまいます。幅優先探索ではキューが際限なく大きくなり、深さ優先探索では同じ閉路を回り続けて終わらなくなることがあります。そのため、どちらの方法でも、訪れた頂点(またはキューやスタックに入れた頂点)に印を付けて、二度と入れないようにします。

理解度チェック

辺に重みのないグラフで、出発点から各頂点までの最短の辺の数を求めたい。適した探索の方法と、そのとき使うデータ構造の組はどれか。

  1. A幅優先探索と、キュー
  2. B深さ優先探索と、スタック
  3. C幅優先探索と、スタック
答えと解説を見る

正解:A. 幅優先探索と、キュー

幅優先探索は、出発点から辺1本で行ける頂点、2本で行ける頂点…と、近い順に訪れます。見つけた頂点をキューの末尾に入れ、先頭から取り出して調べることで、この「近い順」が保たれるので、最初に到達したときの辺の数がそのまま最短の数になります。深さ優先探索(再帰やスタックを使う)は1本の道を行けるところまで進むので、遠回りの経路で先に到達することがあり、最短は保証されません。キューの代わりにスタックを使うと、深さ優先探索に近いたどり方になってしまいます。

辺に向きのないグラフで、各頂点の隣の頂点が次のとおりである。A: B, C / B: A, D, E / C: A, F / D: B / E: B, F / F: C, E。頂点 A から再帰的な深さ優先探索を行う。隣の頂点はここに書いた順に調べ、まだ訪れていない頂点が見つかったらすぐにその頂点へ進む。頂点を訪れる順はどれか。

  1. AA, B, C, D, E, F
  2. BA, B, D, E, C, F
  3. CA, B, D, E, F, C
答えと解説を見る

正解:C. A, B, D, E, F, C

A から B へ進み、B の隣で最初の未訪問の D へ進みます。D の隣は訪問済みの B だけなので B に戻って次の E へ進み、E から未訪問の F へ、F からその隣の C へと進みます。したがって A, B, D, E, F, C の順です。A, B, C, D, E, F は、出発点から近い順に訪れる幅優先探索の順です。A, B, D, E, C, F は、E から未訪問の F へ進まずに戻ってしまっており、深さ優先探索の順にはなりません。

頂点が100万個、辺が300万本ほどの道路網のように、頂点の数に比べて辺の少ない(疎な)グラフをメモリに記憶する方法として適切なものはどれか。

  1. A隣接行列。2つの頂点の間に辺があるかを O(1) で調べられ、記憶領域も最も少なく済む
  2. B隣接リスト。記憶領域は頂点の数と辺の数の和に比例し、ある頂点から出る辺を順にたどるのに向いている
  3. C隣接行列。記憶領域は辺の数だけに比例する
答えと解説を見る

正解:B. 隣接リスト。記憶領域は頂点の数と辺の数の和に比例し、ある頂点から出る辺を順にたどるのに向いている

隣接行列は頂点数 V に対して V×V の表を使うので、100万頂点では10¹²個の要素が必要で、1要素1ビットでも約125 GBになります。隣接リストは各頂点につながる頂点だけを並べるので、記憶領域は O(V + E) で、この例なら数百万件程度で済みます。隣接行列は辺の有無を O(1) で調べられる利点があり、辺の多い(密な)グラフや頂点の少ないグラフに向いています。幅優先探索やダイクストラ法のように、頂点から出る辺を順にたどる処理では、隣接リストの方が効率よく動きます。

  1. 辺に向きのないグラフで、辺の重み(距離)が S−A: 4、S−B: 1、A−B: 2、A−C: 1、B−C: 5、C−T: 3、A−T: 6 である。ダイクストラ法で S から T までの最短経路を求めたとき、その経路と長さはどれか。
  2. 空の二分探索木に、50, 30, 70, 20, 40, 60, 80 の順に値を挿入した。この木を後行順(帰りがけ順。左の部分木、右の部分木、その節の順に訪れる)でたどったときの順はどれか。

データ構造とアルゴリズムの練習問題へ

関連する用語の解説

幅優先探索
グラフや木を、出発点から近い順(辺1本で行ける頂点、次に2本で行ける頂点…)に訪れる探索の方法。キューを使って実装し、辺に重みのないグラフでは、出発点から各頂点への最短の辺の数が求まる。英語の頭文字からBFSともいう。
深さ優先探索
グラフや木を、1本の道を行けるところまで進み、行き止まりになったら戻って別の道を進む順に訪れる探索の方法。再帰やスタックで実装し、迷路の探索、連結成分や閉路の検出、トポロジカルソートなどに使われる。英語の頭文字からDFSともいう。
キュー
最初に入れた要素を最初に取り出す、先入れ先出し(FIFO)のデータ構造。末尾に入れる操作をエンキュー、先頭から取り出す操作をデキューという。処理待ちの行列、タスク間のデータの受け渡し、幅優先探索などに使われる。
スタック
最後に入れた要素を最初に取り出す、後入れ先出し(LIFO)のデータ構造。要素を積む操作を push、取り出す操作を pop という。関数呼び出しの戻り先や局所変数の管理(コールスタック)、逆ポーランド記法の式の計算、深さ優先探索などに使われる。
再帰
関数が処理の中で自分自身を呼び出すこと。問題を同じ形の小さな問題に分けて解き、それ以上分けない場合(基底)で呼び出しを終える。呼び出しごとにスタックを使うので深すぎるとあふれる。最後に自分を呼ぶだけの末尾再帰は、ループに変換できる。
ダイクストラ法
辺の重みが0以上のグラフで、1つの出発点から各頂点への最短経路を求めるアルゴリズム。距離が確定していない頂点のうち最も近いものを確定し、その隣の頂点の距離を更新することを繰り返す。負の重みの辺があると正しく求められない。
計算量
アルゴリズムが必要とする手間(時間計算量)や記憶領域(空間計算量)が、データの数 n に対してどのように増えるかを表したもの。O(n) や O(n log n)、O(n²) のようなオーダー記法(ビッグO記法)で、係数や低い次数の項を省いて書く。

関連する比較