实验5-图
集美大学课程实验报告-实验2:线性表
| 项目名称 | 内容 |
|---|---|
| 课程名称 | 数据结构 |
| 昵称 | 西西 |
| 实验项目名称 | 实验5-图 |
| 上机实践日期 | 2026.5.28 |
| 上机实践时间 | 2学时 |
一、目的(本次实验所涉及并要求掌握的知识点)
以下内容请根据实际情况编写
1.掌握无向图、有向图邻接矩阵的存储结构原理,理解邻接矩阵存储图的优缺点。
2.掌握图的深度优先遍历(DFS)、广度优先遍历(BFS)两种核心遍历算法,理解两种遍历的执行逻辑、适用场景与遍历顺序差异。
3.掌握最小生成树核心算法(Prim算法、Kruskal算法),理解最小生成树的定义、生成条件,能够解决公路村村通等实际工程场景问题。
二、实验内容与设计思想
题目1-图的创建
函数相关伪代码
伪代码
struct Graph{
int vNum, eNum;
int edge[MAXN][MAXN];
}
InitGraph(G):
vNum=0,eNum=0
邻接矩阵全部置0
CreateGraph(G):
输入顶点数、边数
循环输入边(u,v)
G.edge[u][v]=G.edge[v][u]=1
PrintGraph(G):
遍历二维数组,输出矩阵数值
函数代码
#include <iostream>
using namespace std;
#define MAXN 100
struct Graph {
int vertexNum;
int edgeNum;
int edge[MAXN][MAXN];
};
void InitGraph(Graph& g) {
g.vertexNum = g.edgeNum = 0;
for(int i = 0; i < MAXN; i++){
for(int j = 0; j < MAXN; j++){
g.edge[i][j] = 0;
}
}
}
void CreateGraph(Graph& g) {
cin >> g.vertexNum >> g.edgeNum;
int u, v;
for (int i = 0; i < g.edgeNum; i++) {
cin >> u >> v;
g.edge[u][v] = g.edge[v][u] = 1;
}
}
void PrintGraph(Graph& g) {
cout << "邻接矩阵:" << endl;
for (int i = 0; i < g.vertexNum; i++) {
for (int j = 0; j < g.vertexNum; j++) {
cout << g.edge[i][j] << " ";
}
cout << endl;
}
}
int main() {
Graph g;
InitGraph(g);
CreateGraph(g);
PrintGraph(g);
return 0;
}
时间复杂度:O(n²)。
空间复杂度:O(n²)。
题目2-图的遍历(DFS、BFS)
函数相关伪代码
伪代码
DFS(v):
访问v,标记已访问
依次访问所有未访问邻接点
BFS(v):
起点入队、标记访问
循环出队,访问邻接点并入队
函数代码
相关主要代码
#include <iostream>
using namespace std;
#include <queue>
#define MAXN 100
struct Graph{
int vNum;
int eNum;
int edge[MAXN][MAXN];
};
void InitGraph(Graph &g){
g.vNum = 0;
g.eNum = 0;
for(int i=0;i<MAXN;i++)
for(int j=0;j<MAXN;j++)
g.edge[i][j] = 0;
}
void CreateGraph(Graph &g){
cin >> g.vNum >> g.eNum;
int u,v;
for(int i=0;i<g.eNum;i++){
cin >> u >> v;
g.edge[u][v] = 1;
g.edge[v][u] = 1;
}
}
bool visited[MAXN];
void ClearVisit(){
for(int i=0;i<MAXN;i++)
visited[i] = false;
}
//深度优先遍历DFS
void DFS(Graph &g, int v){
cout << v << " ";
visited[v] = true;
for(int j=0;j<g.vNum;j++){
if(g.edge[v][j]==1 && !visited[j])
DFS(g,j);
}
}
//广度优先遍历BFS
void BFS(Graph &g, int v){
queue<int> q;
cout << v << " ";
visited[v] = true;
q.push(v);
while(!q.empty()){
int cur = q.front();
q.pop();
for(int j=0;j<g.vNum;j++){
if(g.edge[cur][j]==1 && !visited[j]){
cout << j << " ";
visited[j] = true;
q.push(j);
}
}
}
}
int main() {
Graph g;
InitGraph(g);
CreateGraph(g);
cout << "DFS遍历序列:";
ClearVisit();
DFS(g,0);
cout << endl;
cout << "BFS遍历序列:";
ClearVisit();
BFS(g,0);
return 0;
}
时间复杂度:O(n²)
空间复杂度:O(n)
题目3-PTA图着色问题
函数相关伪代码
伪代码
输入顶点数V、边数E、颜色总数K
构建邻接表存储无向图
输入查询组数N
循环N次:
输入每个顶点的着色编号
检查是否存在颜色超出K,非法直接标记
遍历每一个顶点,遍历其所有邻接点
若相邻顶点颜色相同,判定方案非法
合法输出Yes,否则输出No
函数代码
相关主要代码
#include <iostream>
using namespace std;
#include <vector>
int main() {
int V, E, K;
cin >> V >> E >> K;
vector<vector<int>> g(V + 1);
for (int i = 0; i < E; ++i)
{
int a, b;
cin >> a >> b;
g[a].push_back(b);
g[b].push_back(a);
}
int N;
cin >> N;
while (N--)
{
vector<int> color(V + 1);
for (int i = 1; i <= V; ++i)
cin >> color[i];
int flag = 1;
for (int i = 1; i <= V; ++i)
{
if (color[i] > K)
flag = 0;
}
if (flag)
{
for (int u = 1; u <= V; ++u)
{
for (int v : g[u])
{
if (color[u] == color[v])
{
flag = 0;
break;
}
}
if (!flag) break;
}
}
if (flag) cout << "Yes\n";
else cout << "No\n";
}
return 0;
}
时间复杂度:O(n²)。
空间复杂度:O(n)。
题目4-公路村村通
函数相关伪代码
伪代码
边按权值从小到大排序
利用并查集合并节点
累计最小权值
凑齐n-1条边输出答案,否则输出-1
函数代码
相关主要代码
#include <iostream>
using namespace std;
const int MAX = 1005;
struct Edge {
int u, v, w;
};
Edge edge[5005];
int parent[MAX];
int n, m;
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]);
return parent[x];
}
void init() {
for (int i = 1; i <= n; i++)
parent[i] = i;
}
int main() {
cin >> n >> m;
init();
for (int i = 0; i < m; i++) {
cin >> edge[i].u >> edge[i].v >> edge[i].w;
}
for (int i = 0; i < m - 1; i++) {
for (int j = 0; j < m - i - 1; j++) {
if (edge[j].w > edge[j + 1].w) {
Edge t = edge[j];
edge[j] = edge[j + 1];
edge[j + 1] = t;
}
}
}
int sum = 0; // 总权值
int count = 0; // 选中的边数
for (int i = 0; i < m; i++) {
int fu = find(edge[i].u);
int fv = find(edge[i].v);
if (fu != fv) {
parent[fu] = fv;
sum += edge[i].w;
count++;
if (count == n - 1)
break;
}
}
if (count == n - 1)
cout << sum << endl;
else
cout << -1 << endl;
return 0;
}
时间复杂度:O(m²)。
空间复杂度:O(n+m)。
三、实验使用环境(本次实验所使用的平台和相关软件)
- 操作系统:Windows 11
- 编程语言:C++
- 开发工具:Visual Studio 2022
- 编译器:Visual Studio 2022
四、实验步骤和调试过程(实验步骤、测试数据设计、测试结果分析)
题目1—图的创建
本机运行截图

题目2-图的遍历(DFS、BFS)
本机运行截图

题目3-PTA图着色问题
PTA截图

题目4-公路村村通
本机运行截图

AI对话截图




五、实验小结(实验中遇到的问题及解决过程、实验体会和收获)
遇到的问题及解决方法:
1.问题:DFS遍历后BFS无输出
解决:两次遍历之间未清空访问数组,新增清空函数重置标记
2.问题:Kruskal算法大数据样例超时
解决:给并查集添加路径压缩,优化查询效率
实验体会和收获:
1.掌握了邻接矩阵图的创建、两种遍历算法以及最小生成树算法。
2.理解了DFS递归回溯、BFS队列逐层遍历的区别。
3.学会了合理利用AI辅助写代码,但是必须自主调试修改,不能直接复制使用。
4.通过VS断点调试,直观看懂了图遍历的执行流程,加深了对图论算法的理解。
六、附件(参考文献和相关资料)
- 图DFS、BFS遍历 官方可视化教学平台(新加坡国立大学)
https://visualgo.net/zh/dfsbfs - Kruskal最小生成树 官方算法详解(新加坡国立大学)
https://visualgo.net/zh/mst - 相关博客文章
浙公网安备 33010602011771号