このチュートリアルでは、例と擬似コードを通じて深さ優先探索アルゴリズムについて学習します。さらに、CでDFSを実装する方法を学びます。
深さ優先探索または深さ優先探索は、グラフまたはツリーデータ構造のすべての頂点を検索するために使用される再帰的アルゴリズムです。トラバーサルとは、グラフのすべてのノードにアクセスすることを意味します。
1.深さ優先探索アルゴリズム
標準のDFS実装は、グラフの各頂点を2つのカテゴリに分類します。
- 訪問した
- 一度も訪れたことがない
このアルゴリズムの目的は、ループを回避しながら、各頂点を訪問済みとしてマークすることです。
DFSアルゴリズムの動作原理は次のとおりです。
- まず、グラフの頂点をスタックの一番上に置きます。
- スタックの最上位のデータ項目を取得し、それを訪問済みリストに追加します。
- この頂点の隣接ノードのリストを作成します。アクセスリストにないものをスタックの一番上に追加します。
- スタックが空になるまで、手順2と3を繰り返します。
2.深さ優先探索の凡例
例を見て、深さ優先探索アルゴリズムがどのように機能するかを見てみましょう。5つの頂点を持つ無向グラフを使用します。
頂点0から開始し、DFSアルゴリズムは最初にそれをアクセスリストに配置し、次に隣接するすべての頂点をスタックに配置します。
次に、スタックの最上位にある要素である1にアクセスし、隣接するノードに移動します。0はすでに訪問されているため、訪問2に変更します。
頂点2には未訪問の隣接頂点4があるため、スタックの一番上に追加して訪問します。
最後の要素3にアクセスした後、アクセスされていない隣接ノードがないため、グラフの深さ優先走査が完了しました。
3. DFS擬似コード(再帰的実装)
DFSの擬似コードを以下に示します。init()関数で、各ノードでDFS関数を実行していることに注意してください。これは、グラフに2つの異なる切断部分がある可能性があるため、各頂点が確実にカバーされるようにするために、各ノードでDFSアルゴリズムを実行できます。
DFS(G, u)
u.visited = true
for each v ∈ G.Adj[u]
if v.visited == false
DFS(G,v)
init() {
For each u ∈ G
u.visited = false
For each u ∈ G
DFS(G, u)
}
4.Cの例
深さ優先探索アルゴリズムのコードと例を以下に示します。コードが簡略化されたため、他の詳細ではなくアルゴリズムに集中できます。
// DFS algorithm in C
#include <stdio.h>
#include <stdlib.h>
struct node {
int vertex;
struct node* next;
};
struct node* createNode(int v);
struct Graph {
int numVertices;
int* visited;
// We need int** to store a two dimensional array.
// Similary, we need struct node** to store an array of Linked lists
struct node** adjLists;
};
// DFS algo
void DFS(struct Graph* graph, int vertex) {
struct node* adjList = graph->adjLists[vertex];
struct node* temp = adjList;
graph->visited[vertex] = 1;
printf("Visited %d \n", vertex);
while (temp != NULL) {
int connectedVertex = temp->vertex;
if (graph->visited[connectedVertex] == 0) {
DFS(graph, connectedVertex);
}
temp = temp->next;
}
}
// Create a node
struct node* createNode(int v) {
struct node* newNode = malloc(sizeof(struct node));
newNode->vertex = v;
newNode->next = NULL;
return newNode;
}
// Create graph
struct Graph* createGraph(int vertices) {
struct Graph* graph = malloc(sizeof(struct Graph));
graph->numVertices = vertices;
graph->adjLists = malloc(vertices * sizeof(struct node*));
graph->visited = malloc(vertices * sizeof(int));
int i;
for (i = 0; i < vertices; i++) {
graph->adjLists[i] = NULL;
graph->visited[i] = 0;
}
return graph;
}
// Add edge
void addEdge(struct Graph* graph, int src, int dest) {
// Add edge from src to dest
struct node* newNode = createNode(dest);
newNode->next = graph->adjLists[src];
graph->adjLists[src] = newNode;
// Add edge from dest to src
newNode = createNode(src);
newNode->next = graph->adjLists[dest];
graph->adjLists[dest] = newNode;
}
// Print the graph
void printGraph(struct Graph* graph) {
int v;
for (v = 0; v < graph->numVertices; v++) {
struct node* temp = graph->adjLists[v];
printf("\n Adjacency list of vertex %d\n ", v);
while (temp) {
printf("%d -> ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
int main() {
struct Graph* graph = createGraph(4);
addEdge(graph, 0, 1);
addEdge(graph, 0, 2);
addEdge(graph, 1, 2);
addEdge(graph, 2, 3);
printGraph(graph);
DFS(graph, 2);
return 0;
}
5.深さ優先探索の複雑さ
DFSアルゴリズムの時間計算量は、O(V + E)で表されます。ここで、Vはノードの数、Eはエッジの数です。
アルゴリズムの空間の複雑さはO(V)です。
6.DFSアルゴリズムの適用
- パスを見つける
- テストチャートが2部グラフであるかどうか
- グラフを見つけるための強力に接続されたコンポーネント
- グラフのサイクルを検出するために使用されます
参照文書
[1]パレワラボPvt。Ltd.Depth First Search(DFS)[EB / OL] .https://www.programiz.com/dsa/graph-dfs,2020-01-01。