hnust 1965: 深度优先搜索
题目描述
 输入一个图,用邻接矩阵存储(实际上也可以选择邻接表),并实现DFSTraverse操作。
 拷贝前面已经实现的代码,主函数必须如下,完成剩下的部分。
int main()
 {
 Graph g;
 CreateUDG(g);
 DFSTraverse(g);
 cout << endl;
 DestroyUDG(g);
 return 0;
 }//main
输入
 输入的第一行是两个整数,分别是图的总顶点数n和总边数e
第二行是n个空格分开的字符串,是顶点的名字,依次对应编号0~n-1。
随后有e行,每行两个空格分开的顶点名字,表示一条边的两个顶点。
具体见样例。
输出
 输出图的DFS序列,遍历次序按教材,每个顶点后面跟一个空格。
具体见样例。
样例输入 Copy
 8 9
 v1 v2 v3 v4 v5 v6 v7 v8
 v1 v2
 v1 v3
 v2 v4
 v2 v5
 v3 v6
 v3 v7
 v4 v8
 v5 v8
 v6 v7
 样例输出 Copy
 v1 v2 v4 v8 v5 v3 v6 v7
 提示
 样例对应教材6.5的图G4
解题过程
注:本题按照书上算法解析完成,深度优先搜索的细化代码及函数分解请看合集《2024.6 hnust 23级 数据结构 课程设计》“推箱子游戏-深度优先搜索版本”
 图的深度优先遍历(DFS)需要借助栈来遍历:
 ①首先,选取图中某一顶点vi作为起始点访问;
 ②任意选取一个与vi邻接的顶点,且该顶点未被访问,一直重复下去,直到图中所有与vi连通的顶点都被访问到;【可概括为由起始顶点开始,沿着一条路径尽可能地深入搜索该图,直到无法再继续下去】
 ③若还有顶点未被访问到,则另外选取一个未被访问的顶点再次作为起始点,回溯到上一个未访问的顶点,重复以上步骤,直至图中所有结点被访问。
DFS的空间复杂度和时间复杂度
 对于一个图G=(V,E),由顶点集V和边集E组成。
 1、DFS算法的空间复杂度
 由于DFS算法是一个递归算法,即递归顶点集V,通过DFS遍历的空间复杂度为O(|V|)。
2、DFS算法的时间复杂度
 时间复杂度取决于图的存储结构,若通过邻接矩阵表示图,则查找顶点的邻接顶点所需时间为O(|V|),总时间复杂度为O(|V2|)(邻接矩阵为方阵n×n);若通过邻接表表示图,则查找所有顶点的邻接顶点所需时间为O(|E|),访问顶点所需时间为O(|V|),即总时间复杂度为O(|V|+|E|)。
这段C++代码实现了一个基于深度优先搜索(DFS)的无向图的拓扑排序算法。以下是对代码的详细解析:
-  头文件和命名空间: - 包含 <bits/stdc++.h>头文件,它包含了标准库中的大部分内容。
- 使用 using namespace std;来避免在标准库类型和函数前加std::。
 
- 包含 
-  输入图的参数: - 读取两个整数 n和e,分别代表图中顶点的数量和边的数量。
 
- 读取两个整数 
-  存储顶点信息: - 创建一个字符串数组 nodes来存储顶点的名称。
 
- 创建一个字符串数组 
-  输入顶点名称: - 使用循环读取 n个顶点的名称。
 
- 使用循环读取 
-  建立顶点位置映射: - 使用 map(映射)来存储每个顶点名称与其在数组中的索引位置。
 
- 使用 
-  创建无向图: - 使用 map来创建一个邻接表G,表示无向图中的边。
 
- 使用 
-  对邻接表进行排序: - 对每个顶点的邻接表进行排序,以便在后续的搜索中按顺序访问。
 
-  初始化访问标记: - 使用 map初始化所有顶点的访问状态为未访问。
 
- 使用 
-  使用栈实现DFS: - 使用 stack来实现DFS,首先将起始顶点压入栈中,并标记为已访问。
 
- 使用 
-  DFS搜索: - 当栈不为空时,执行循环: - 弹出栈顶元素作为当前访问的顶点。
- 遍历当前顶点的所有邻接顶点。
- 如果邻接顶点未被访问,将其标记为已访问,并压入栈中。
- 如果成功访问了一个邻接顶点,输出当前顶点名称,并设置 flag为 1。
- 如果没有邻接顶点可访问(flag为 0),则继续弹出栈中的元素。
 
 
- 当栈不为空时,执行循环: 
-  输出访问顺序: - 在访问过程中,每访问一个顶点,就输出其名称。
 
-  程序结束: - 当栈为空时,表示所有顶点都被访问完毕,程序结束。
 
代码逻辑分析:
- 这段代码通过DFS实现了拓扑排序,适用于无向图。
- 使用栈来存储待访问的顶点,使用映射来记录顶点的访问状态和位置信息。
潜在问题:
- 代码中注释掉的部分提供了另一种交换变量值的方法,但在当前实现中未使用。
- 代码中使用 9999作为邻接矩阵的初始值,这可能在某些情况下不是最佳选择,比如图中边的权重可能超过这个值。
改进建议:
- 考虑使用 std::vector替代数组,以提高代码的安全性和灵活性。
- 考虑使用 std::unordered_map替代std::map,以提高查找效率。
- 考虑使用 std::swap函数交换变量值,使代码更加简洁。
- 如果需要处理更大的图或更复杂的图结构,可以考虑优化内存使用和搜索算法。
AC代码
#include<bits/stdc++.h>
using namespace std;int main(int argc, char const *argv[])
{int n , e;cin >> n >> e;  // 输入 : 8 9string nodes[n];for (int i = 0; i < n; ++i)  // 输入: v1 v2 v3 v4 v5 v6 v7 v8{cin >> nodes[i];}map <string , int > location;for (int i = 0; i < n; ++i)   //排序数组{location[nodes[i]] = i;}map<string ,std::vector<string> > G;  //创建无向图for (int i = 0; i < e; ++i){string l , r;cin >> l >> r;G[l].push_back(r);G[r].push_back(l);}for (int i = 0; i < n; ++i)  //对无向图的排序{int j = G[nodes[i]].size();for (int p = 0; p < j; ++p){for (int q = 0; q < j; ++q){if(location[G[nodes[i]][q]] > location[G[nodes[i]][p]]){swap(G[nodes[i]][q],G[nodes[i]][p]);}}}}map<string,bool > vis; //是否被访问stack <string > s;s.push(nodes[0]);vis[nodes[0]] = true;cout << nodes[0] << " " ;while(s.size()){string curr;curr = s.top();bool flag = 0;for(auto next : G[curr]){if(!vis[next]){vis[next] = true;s.push(next);flag = 1;cout << next << " ";break;}}if(flag == 0){s.pop();}}return 0;
}