mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-16 16:56:06 +00:00
Re-translate the Japanese version (#1871)
* Retranslate Japanese docs with GPT-5.4 * Retranslate Japanese code with GPT-5.4
This commit is contained in:
@@ -1,33 +1,37 @@
|
||||
# グラフ走査
|
||||
# グラフの走査
|
||||
|
||||
木は「一対多」の関係を表現し、グラフはより高い自由度を持ち、任意の「多対多」の関係を表現できます。したがって、木をグラフの特別なケースと見なすことができます。明らかに、**木の走査操作もグラフ走査操作の特別なケースです**。
|
||||
木は「一対多」の関係を表すのに対し、グラフはより高い自由度を持ち、任意の「多対多」の関係を表現できます。したがって、木はグラフの一種の特殊な場合とみなせます。明らかに、**木の走査操作もグラフの走査操作の一種の特殊な場合です**。
|
||||
|
||||
グラフと木の両方で、走査操作を実装するために探索アルゴリズムの応用が必要です。グラフ走査は2つのタイプに分けることができます:<u>幅優先探索(BFS)</u>と<u>深さ優先探索(DFS)</u>です。
|
||||
グラフと木はいずれも、走査操作を実現するために探索アルゴリズムを用いる必要があります。グラフの走査方法も、<u>幅優先走査</u>と<u>深さ優先走査</u>の 2 種類に分けられます。
|
||||
|
||||
## 幅優先探索
|
||||
## 幅優先走査
|
||||
|
||||
**幅優先探索は近くから遠くへの走査方法で、ある頂点から開始し、常に最も近い頂点を優先的に訪問し、層ごとに外側に展開していきます**。下図に示すように、左上の頂点から開始し、まずその頂点のすべての隣接頂点を走査し、次に次の頂点のすべての隣接頂点を走査し、以下同様に、すべての頂点が訪問されるまで続けます。
|
||||
**幅優先走査は、近いところから遠いところへ向かう走査方法であり、ある頂点から出発して、常に最も近い頂点を優先して訪問し、層ごとに外側へ広がっていきます**。以下の図に示すように、左上の頂点から出発し、まずその頂点のすべての隣接頂点を走査し、次に次の頂点のすべての隣接頂点を走査し、これを繰り返して、すべての頂点を訪問するまで続けます。
|
||||
|
||||

|
||||
|
||||
### アルゴリズムの実装
|
||||
|
||||
BFSは通常キューの助けを借りて実装されます(下記のコード参照)。キューは「先入先出」で、これは「近くから遠くへ」走査するBFSの考え方と一致します。
|
||||
BFS は通常キューを用いて実装され、コードは以下のとおりです。キューは「先入れ先出し」という性質を持ち、これは BFS の「近いところから遠いところへ」という考え方と本質的に一致しています。
|
||||
|
||||
1. 開始頂点`startVet`をキューに追加し、ループを開始します。
|
||||
2. ループの各反復で、キューの先頭の頂点をポップし、それを訪問済みとして記録し、次にその頂点のすべての隣接頂点をキューの末尾に追加します。
|
||||
3. すべての頂点が訪問されるまで手順`2.`を繰り返します。
|
||||
1. 走査の開始頂点 `startVet` をキューに追加し、ループを開始します。
|
||||
2. ループの各反復で、キュー先頭の頂点を取り出して訪問を記録し、その後その頂点のすべての隣接頂点をキューの末尾に追加します。
|
||||
3. 手順 `2.` を繰り返し、すべての頂点が訪問されると終了します。
|
||||
|
||||
頂点の再訪問を防ぐために、ハッシュセット`visited`を使用してどのノードが訪問されたかを記録します。
|
||||
頂点の重複走査を防ぐために、どの頂点が訪問済みかを記録するハッシュ集合 `visited` を用います。
|
||||
|
||||
!!! tip
|
||||
|
||||
ハッシュ集合は、`value` を持たず `key` だけを格納するハッシュテーブルとみなせます。これは $O(1)$ の時間計算量で `key` の追加・削除・検索・更新を行えます。`key` の一意性にもとづき、ハッシュ集合は通常、データの重複排除などの場面で用いられます。
|
||||
|
||||
```src
|
||||
[file]{graph_bfs}-[class]{}-[func]{graph_bfs}
|
||||
```
|
||||
|
||||
コードは比較的抽象的ですが、下図と比較することでより良く理解できます。
|
||||
コードはやや抽象的なので、以下の図と照らし合わせて理解を深めることを勧めます。
|
||||
|
||||
=== "<1>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -59,39 +63,39 @@ BFSは通常キューの助けを借りて実装されます(下記のコー
|
||||
=== "<11>"
|
||||

|
||||
|
||||
!!! question "幅優先走査のシーケンスは一意ですか?"
|
||||
!!! question "幅優先走査の順序列は一意ですか?"
|
||||
|
||||
一意ではありません。幅優先走査は「近くから遠く」の順序で走査することのみを要求し、**同じ距離の頂点の走査順序は任意にできます**。例えば、上図では、頂点$1$と$3$の訪問順序を交換できますし、頂点$2$、$4$、$6$の順序も同様です。
|
||||
一意ではありません。幅優先走査は「近いところから遠いところへ」の順で走査することだけを要求し、**同じ距離にある複数の頂点の走査順は任意に入れ替えて構いません**。上図を例にすると、頂点 $1$ と $3$ の訪問順は交換でき、頂点 $2$、$4$、$6$ の訪問順も任意に入れ替えられます。
|
||||
|
||||
### 計算量分析
|
||||
### 計算量の分析
|
||||
|
||||
**時間計算量**:すべての頂点が一度ずつエンキューおよびデキューされ、$O(|V|)$時間を使用します。隣接頂点を走査する過程で、無向グラフであるため、すべての辺が$2$回訪問され、$O(2|E|)$時間を使用します。全体で$O(|V| + |E|)$時間を使用します。
|
||||
**時間計算量**:すべての頂点は 1 回ずつキューに入り、1 回ずつキューから出るため、$O(|V|)$ 時間です。隣接頂点を走査する過程では、無向グラフであるため、すべての辺が $2$ 回訪問され、$O(2|E|)$ 時間です。したがって全体では $O(|V| + |E|)$ 時間です。
|
||||
|
||||
**空間計算量**:リスト`res`、ハッシュセット`visited`、キュー`que`の最大頂点数は$|V|$で、$O(|V|)$空間を使用します。
|
||||
**空間計算量**:リスト `res`、ハッシュ集合 `visited`、キュー `que` に含まれる頂点数は最大で $|V|$ であるため、$O(|V|)$ 空間です。
|
||||
|
||||
## 深さ優先探索
|
||||
## 深さ優先走査
|
||||
|
||||
**深さ優先探索は可能な限り遠くまで行き、それ以上のパスがない場合にバックトラックする走査方法です**。下図に示すように、左上の頂点から開始し、それ以上のパスがなくなるまで現在の頂点のいずれかの隣接頂点を訪問し、次に戻って続行し、すべての頂点が走査されるまで続けます。
|
||||
**深さ優先走査は、まず行けるところまで進み、進めなくなったら戻る走査方法です**。以下の図に示すように、左上の頂点から出発し、現在の頂点のある隣接頂点を訪問して、行き止まりに達するまで進んだら戻り、再び別の方向へ進んで行き止まりまで進んで戻る、ということを繰り返し、すべての頂点の走査が完了するまで続けます。
|
||||
|
||||

|
||||
|
||||
### アルゴリズムの実装
|
||||
|
||||
この「可能な限り遠くまで行ってから戻る」アルゴリズムパラダイムは通常再帰に基づいて実装されます。幅優先探索と同様に、深さ優先探索でも、再訪問を避けるために訪問済み頂点を記録するハッシュセット`visited`の助けが必要です。
|
||||
この「行き止まりまで進んでから戻る」アルゴリズムのパターンは、通常再帰にもとづいて実装されます。幅優先走査と同様に、深さ優先走査でも、頂点の重複訪問を避けるために、訪問済みの頂点を記録するハッシュ集合 `visited` を用います。
|
||||
|
||||
```src
|
||||
[file]{graph_dfs}-[class]{}-[func]{graph_dfs}
|
||||
```
|
||||
|
||||
深さ優先探索のアルゴリズムプロセスを下図に示します。
|
||||
深さ優先走査のアルゴリズムの流れは以下の図のとおりです。
|
||||
|
||||
- **破線は下向きの再帰を表し**、新しい頂点を訪問するために新しい再帰メソッドが開始されたことを示します。
|
||||
- **曲線の破線は上向きのバックトラックを表し**、この再帰メソッドがこのメソッドが開始された位置に戻ったことを示します。
|
||||
- **直線の破線は下向きの再帰呼び出し**を表し、新しい頂点を訪問するために新たな再帰メソッドが開始されたことを意味します。
|
||||
- **曲線の破線は上向きのバックトラック**を表し、この再帰メソッドがすでに戻って、呼び出し元の位置までたどり着いたことを意味します。
|
||||
|
||||
理解を深めるため、下図とコードを組み合わせて、DFSプロセス全体を頭の中でシミュレート(または描画)することをお勧めします。各再帰メソッドがいつ開始され、いつ戻るかを含めてです。
|
||||
理解を深めるために、以下の図とコードを結びつけて、DFS 全体の過程を頭の中でシミュレーションする(あるいは紙に書き出す)ことを勧めます。各再帰メソッドがいつ開始し、いつ戻るかも含めて追ってみてください。
|
||||
|
||||
=== "<1>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -123,14 +127,14 @@ BFSは通常キューの助けを借りて実装されます(下記のコー
|
||||
=== "<11>"
|
||||

|
||||
|
||||
!!! question "深さ優先走査のシーケンスは一意ですか?"
|
||||
!!! question "深さ優先走査の順序列は一意ですか?"
|
||||
|
||||
幅優先走査と同様に、深さ優先走査シーケンスの順序も一意ではありません。ある頂点が与えられた場合、どの方向を最初に探索することも可能です。つまり、隣接頂点の順序は任意にシャッフルできますが、すべて深さ優先走査の一部です。
|
||||
幅優先走査と同様に、深さ優先走査の順序列も一意ではありません。ある頂点が与えられたとき、どの方向を先に探索してもよく、つまり隣接頂点の順序は任意に入れ替えられ、それでも深さ優先走査になります。
|
||||
|
||||
木の走査を例にすると、「根 $\rightarrow$ 左 $\rightarrow$ 右」「左 $\rightarrow$ 根 $\rightarrow$ 右」「左 $\rightarrow$ 右 $\rightarrow$ 根」は、それぞれ先行順、中間順、後行順走査に対応します。これらは 3 種類の走査優先順位を示していますが、いずれも深さ優先走査に属します。
|
||||
|
||||
木の走査を例に取ると、「根 $\rightarrow$ 左 $\rightarrow$ 右」、「左 $\rightarrow$ 根 $\rightarrow$ 右」、「左 $\rightarrow$ 右 $\rightarrow$ 根」は、それぞれ前順、中順、後順走査に対応します。これらは3つの異なる走査優先度を示していますが、3つすべてが深さ優先走査と見なされます。
|
||||
### 計算量の分析
|
||||
|
||||
### 計算量分析
|
||||
**時間計算量**:すべての頂点は $1$ 回ずつ訪問されるため、$O(|V|)$ 時間です。すべての辺は $2$ 回ずつ訪問されるため、$O(2|E|)$ 時間です。したがって全体では $O(|V| + |E|)$ 時間です。
|
||||
|
||||
**時間計算量**:すべての頂点が一度訪問され、$O(|V|)$時間を使用します。すべての辺が2回訪問され、$O(2|E|)$時間を使用します。全体で$O(|V| + |E|)$時間を使用します。
|
||||
|
||||
**空間計算量**:リスト`res`、ハッシュセット`visited`の最大頂点数は$|V|$で、最大再帰深度は$|V|$です。したがって、$O(|V|)$空間を使用します。
|
||||
**空間計算量**:リスト `res` とハッシュ集合 `visited` に含まれる頂点数は最大で $|V|$ であり、再帰の深さも最大で $|V|$ であるため、$O(|V|)$ 空間です。
|
||||
|
||||
Reference in New Issue
Block a user