【データ構造とアルゴリズム】グラフトラバーサル(深さ優先トラバーサルDFSアルゴリズム)

1.1 深さ優先トラバーサル

 深さ優先トラバーサル (深さ優先検索)。深さ優先検索または略して DFS とも呼ばれます。その主なアイデアは、たとえば、鍵を見つけることです。例: 車のキーを 1 つ紛失しましたが、それが家のどこかにあることは確かなので、部屋から探し始める必要がありますが、部屋の特定の場所で探すべきですか、それとも部屋全体 探した後、次の部屋はどこにありますか?深さ優先探索とは、車のキーが見つかるまで、他の部屋を検索する前に、部屋内のすべての場所を検索することを意味します。

今すぐタスクを完了する必要があるとします。自分が次の迷路の中にいるということを知る必要があります。頂点 A から始めて、グラフ内のすべての頂点を通過し、それらにマークを付ける必要があります。単に見て歩いているわけではないことに注意してください。このような平面グラフを現実と同じように歩き、迷路内のタスクを完了します。

明らかに、この種のグラフを横断するための戦略が必要です。そうでないと、この広大な道路で簡単に迷子になり、タスクを完了するには運に頼るしかありません。この記事を読んで深さ優先トラバースについてある程度理解していれば、このタスクを完了するのは難しくありません。

まずA地点からスタートし、通過の印を付けた後、目の前にBとFに続く道が2本あります。頂点が重複しない場合の原則を自分で決めます。 、常に右側のウォークに進むので、B 頂点に到達しました。パス全体のプロセスは次の図を参照してください。この時点で、C、I、G につながる 3 つの分岐があり、右手で C 頂点に到達します。F頂点まで行って、次の頂点を見つけたのでA頂点に戻り、F頂点で最後から2番目の右手の通路をG頂点まで進み、3つ遭遇しましたさらに道があったが、B、D を見つけた 私たちはすでに通過したので、H 頂点に到達しました H に到達したとき、2 つの交差点に遭遇し、両方とも通過しましたが、グラフの横断が完了していないことは明らかでしたで、H から G、F、E、D 頂点まで後退しました。D 頂点に到達すると、まだそこを歩いていないことがわかり、I まで歩いてこのタスクは完了です。

 

実際、上記の説明から、深さ優先走査は再帰的なプロセスであることがわかりますが、注意深く見ると、ツリーの前順序走査に似ていることがわかります。これは、グラフ内の特定の頂点 V から開始し、その頂点を訪問し、最初に V の未訪問の隣接点から、V とのパスを持つグラフ内のすべての頂点が訪問されるまで、グラフを深く横断します。

隣接行列の深さトラバーサルのコードは次のとおりです。

int visited[10]; 
//邻接矩阵的深度优先递归算法
void DFS(struct photo* G, int i)        //访问标志的数组
{
	int j;
	visited[i] = 1;
	cout << G->vex[i]<<" ";        //打印结点的内容
	for (j = 0; j < G->numnodes; j++)
	{
		if (G->arc[i][j] == 1 && visited[j] == 0)    //对未被访问的结点进行递归
			DFS(G, j);
	}
}
//邻接矩阵的深度遍历操作
void DFStraverse(struct photo* G)
{
	int i;
	for (i = 0; i < G->numnodes; i++)
		visited[i] = 0;        //初始化标志数组都为被访问
	for (i = 0; i < G->numnodes; i++)
		if (visited[i] == 0)
			DFS(G, i);        //对未被党文的顶点调用DFS
}

データの保存方法を含む、実行可能なコード全体は次のとおりです。

struct photo
{
	char vex[10];
	int arc[10][10]={0};
	int numnodes, numdges;
};

void creategraph(struct photo*G)
{
	cout << "请输入顶点数和边数:" << endl;
	cin >> G->numnodes >> G->numdges;
	for (int i = 0; i < G->numnodes; i++)
		cin >> G->vex[i];
	for (int i = 0; i < G->numnodes; i++)
		for (int j = 0; j < G->numnodes; j++)
			G->arc[i][j] = 0;
	for (int k = 0; k < G->numdges; k++)
	{
		int i, j;
		cout << "请输入有边点数:(i,j)" << endl;
		cin >> i>>j;
		G->arc[i][j] = 1;
		G->arc[j][i] = G->arc[i][j];
	}
}

void print(struct photo* G)
{
	for (int i = 0; i < G->numnodes; i++)
	{
		for (int j = 0; j < G->numnodes; j++)
		{
			cout <<setw(2)<< G->arc[i][j] << " ";
		}
		cout << endl;
	}
}

int visited[10]; 
void DFS(struct photo* G, int i)
{
	int j;
	visited[i] = 1;
	cout << G->vex[i]<<" ";
	for (j = 0; j < G->numnodes; j++)
	{
		if (G->arc[i][j] == 1 && visited[j] == 0)
			DFS(G, j);
	}
}

void DFStraverse(struct photo* G)
{
	int i;
	for (i = 0; i < G->numnodes; i++)
		visited[i] = 0;
	for (i = 0; i < G->numnodes; i++)
		if (visited[i] == 0)
			DFS(G, i);
}
int main()
{
	struct photo* y;
	y = (struct photo*)malloc(sizeof(struct photo));
	creategraph(y);
	print(y);
	DFStraverse(y);
	return 0;
}

一般的な実行結果は次のとおりです。上記の推論によれば、主にこのアイデアを観察して習得するために、次の図に入力したデータが推測できます。

隣接リストのコード DFStraverse 関数のコードはほぼ同じですが、再帰関数では記憶構造が配列からリンク リストに変更されているため異なります。

隣接リストの詳細なトラバーサルのコードは次のとおりです。

 

int visited[10];
void DFS(nodes* G, int i)
{
	struct dege* e;
	visited[i] = 1;
	cout << G->adj[i].data<<" ";
	e = G->adj[i].first;
	while (e)
	{
		if (visited[e->adv] == 0)
			DFS(G, e->adv);
		e = e->next;
	}
}
void DFStraverse(nodes* G)
{
	for (int i = 0; i < G->numnodes; i++)
		visited[i] = 0;
	for (int i = 0; i < G->numnodes; i++)
		if (visited[i] == 0)
			DFS(G, i);
}

完全な隣接リストと深さ優先トラバーサルを作成するコードは次のとおりです。

struct dege
{
	int adv;
	struct dege* next;
};

typedef struct vex
{
	char data;
	struct dege* first;
}adjlist[100];

struct nodes
{
	adjlist adj;
	int numnodes, numedges;
};

void create(struct nodes* G)
{
	struct dege* e;
	cout << "请输入顶点数目和边的数目:" << endl;
	cin >> G->numnodes >> G->numedges;
	for (int i = 0; i < G->numnodes; i++)
	{
		cin >> G->adj[i].data;
		G->adj[i].first = NULL;
	}
	for (int k = 0; k < G->numedges; k++)
	{
		cout << "请输入有边的结点i,j:" << endl;
		int i, j;
		cin >> i >> j;
		e = (struct dege*)malloc(sizeof(struct dege));
		e->adv = j;
		e->next = G->adj[i].first;
		G->adj[i].first = e;
		e = (struct dege*)malloc(sizeof(struct dege));
		e->adv = i;
		e->next = G->adj[j].first;
		G->adj[j].first = e;
	}
}

int visited[10];
void DFS(nodes* G, int i)
{
	struct dege* e;
	visited[i] = 1;
	cout << G->adj[i].data<<" ";
	e = G->adj[i].first;
	while (e)
	{
		if (visited[e->adv] == 0)
			DFS(G, e->adv);
		e = e->next;
	}
}
void DFStraverse(nodes* G)
{
	for (int i = 0; i < G->numnodes; i++)
		visited[i] = 0;
	for (int i = 0; i < G->numnodes; i++)
		if (visited[i] == 0)
			DFS(G, i);
}
int main()
{
	struct nodes* S;
	S = (struct nodes*)malloc(sizeof(struct nodes));
	create(S);
	DFStraverse(S);
	return 0;
}

最終的な実行結果は次のとおりです。

最近、私は少し混乱しています。主な理由は、中間試験の復習によって私自身の復習計画が混乱したためです。

私はこの言葉がとても好きです。「ティーンエイジャーは高いところに登りたいのではなく、安全で健康でありたいと思っています。」 

おすすめ

転載: blog.csdn.net/m0_61886762/article/details/124742616