集美大学课程实验报告-实验5:图
| 项目名称 | 内容 |
|---|---|
| 课程名称 | 数据结构 |
| 实验项目名称 | 实验5:图 |
| 上机实践日期 | 2026.5.29 |
| 上机实践时间 | 2学时 |
一、目的(本次实验所涉及并要求掌握的知识点)
- 学会创建图(邻接矩阵),掌握在图上的基本操作。
- 掌握图遍历算法:DFS与BFS。
- 掌握编写最小生成树算法。
二、实验内容与设计思想
以下请根据实际情况编写
题目1:图的创建
** LocateVex函数相关伪代码**
函数 LocateVex(G, key)
// 输入:图G,要查找的顶点值key
// 输出:顶点在数组中的下标,未找到返回-1
for i = 0 to G.vexNum - 1 do
if G.vexs[i] == key then
return i
end if
end for
return -1
** CreateUDGraphFromConsole函数相关伪代码**
函数 CreateUDGraphFromConsole(G)
// 输入:图G(引用传递)
// 输出:填充好的图G
// 步骤1:输入顶点数和边数
输入 G.vexNum, G.arcNum
// 步骤2:输入顶点信息
for i = 0 to G.vexNum - 1 do
输入 G.vexs[i]
end for
// 步骤3:初始化邻接矩阵
for i = 0 to G.vexNum - 1 do
for j = 0 to G.vexNum - 1 do
G.arcs[i][j] = 0
end for
end for
// 步骤4:输入边信息
for k = 0 to G.arcNum - 1 do
输入 v1, v2, w
i = LocateVex(G, v1)
j = LocateVex(G, v2)
if i != -1 and j != -1 then
G.arcs[i][j] = w
G.arcs[j][i] = w // 无向图对称赋值
end if
end for
** PrintMGraph函数相关伪代码**
函数 PrintMGraph(G)
// 输入:图G
// 输出:打印邻接矩阵
for i = 0 to G.vexNum - 1 do
end for
for i = 0 to G.vexNum - 1 do
end for
// 打印矩阵内容
for i = 0 to G.vexNum - 1 do
for j = 0 to G.vexNum - 1 do
end for
end for
函数代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define MAXVEXNUM 100
typedef int ArcCell;
typedef char VexType;
typedef struct {
VexType vexs[MAXVEXNUM];
ArcCell arcs[MAXVEXNUM][MAXVEXNUM];
int vexNum;
int arcNum;
} MyGraph;
int LocateVex(MyGraph G, VexType key) {
for (int i = 0; i < G.vexNum; i++) {
if (G.vexs[i] == key) {
return i;
}
}
return -1;
}
void CreateUDGraphFromConsole(MyGraph* G) {
printf("请输入顶点数和边数:");
scanf("%d %d", &(G->vexNum), &(G->arcNum));
printf("请输入 %d 个顶点:", G->vexNum);
for (int i = 0; i < G->vexNum; i++) {
scanf(" %c", &(G->vexs[i]));
}
memset(G->arcs, 0, sizeof(G->arcs));
printf("请输入 %d 条边(格式:顶点1 顶点2 权值):\n", G->arcNum);
for (int k = 0; k < G->arcNum; k++) {
char v1, v2;
int w;
scanf(" %c %c %d", &v1, &v2, &w);
int i = LocateVex(*G, v1);
int j = LocateVex(*G, v2);
if (i != -1 && j != -1) {
G->arcs[i][j] = w;
G->arcs[j][i] = w;
}
}
}
void PrintMGraph(MyGraph G) {
printf("\n========================================\n");
printf("邻接矩阵:\n");
printf(" ");
for (int i = 0; i < G.vexNum; i++) {
printf(" %c ", G.vexs[i]);
}
printf("\n");
printf(" ");
for (int i = 0; i < G.vexNum; i++) {
printf("---");
}
printf("\n");
for (int i = 0; i < G.vexNum; i++) {
printf(" %c | ", G.vexs[i]);
for (int j = 0; j < G.vexNum; j++) {
printf(" %d ", G.arcs[i][j]);
}
printf("\n");
}
printf("========================================\n");
}
int main() {
printf("========================================\n");
MyGraph G;
CreateUDGraphFromConsole(&G);
PrintMGraph(G);
printf("\n【验证对称性】\n");
int symmetric = 1;
for (int i = 0; i < G.vexNum; i++) {
for (int j = 0; j < G.vexNum; j++) {
if (G.arcs[i][j] != G.arcs[j][i]) {
symmetric = 0;
break;
}
}
}
if (symmetric) {
printf("邻接矩阵是对称的,符合无向图特性!\n");
}
else {
printf("邻接矩阵不对称!\n");
}
printf("\n按任意键退出...");
getchar();
getchar();
return 0;
}
时间复杂度
O(n² + e)
空间复杂度
O(n²)
题目2:图的遍历
DFS函数相关伪代码
函数 DFS(G, v)
visited[v] = 1
输出 G.vexs[v]
for i = 0 to G.vexNum-1 do
if G.arcs[v][i] == 1 and visited[i] == 0 then
DFS(G, i)
end if
end for
BFS函数相关伪代码
函数 BFS(G, v)
创建队列Q
visited[v] = 1
输出 G.vexs[v]
v入队
while 队列非空 do
u = 出队
for i = 0 to G.vexNum-1 do
if G.arcs[u][i] == 1 and visited[i] == 0 then
visited[i] = 1
输出 G.vexs[i]
i入队
end if
end for
end while
LocateVex函数相关伪代码
函数 LocateVex(G, key)
for i = 0 to G.vexNum-1 do
if G.vexs[i] == key then return i
end for
return -1
函数代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define MAXVEXNUM 100
#define MAXQSIZE 100
typedef int ArcCell;
typedef char VexType;
typedef struct {
VexType vexs[MAXVEXNUM];
ArcCell arcs[MAXVEXNUM][MAXVEXNUM];
int vexNum;
int arcNum;
} MyGraph;
int visited[MAXVEXNUM];
int LocateVex(MyGraph G, VexType key) {
for (int i = 0; i < G.vexNum; i++) {
if (G.vexs[i] == key) {
return i;
}
}
return -1;
}
void CreateUDGraphFromConsole(MyGraph* G) {
printf("请输入顶点数和边数:");
scanf("%d %d", &(G->vexNum), &(G->arcNum));
printf("请输入 %d 个顶点:", G->vexNum);
for (int i = 0; i < G->vexNum; i++) {
scanf(" %c", &(G->vexs[i]));
}
memset(G->arcs, 0, sizeof(G->arcs));
printf("请输入 %d 条边(格式:顶点1 顶点2 权值):\n", G->arcNum);
for (int k = 0; k < G->arcNum; k++) {
char v1, v2;
int w;
scanf(" %c %c %d", &v1, &v2, &w);
int i = LocateVex(*G, v1);
int j = LocateVex(*G, v2);
if (i != -1 && j != -1) {
G->arcs[i][j] = w;
G->arcs[j][i] = w;
}
}
}
void PrintMGraph(MyGraph G) {
printf("\n========================================\n");
printf("邻接矩阵:\n");
printf(" ");
for (int i = 0; i < G.vexNum; i++) {
printf(" %c ", G.vexs[i]);
}
printf("\n");
printf(" ");
for (int i = 0; i < G.vexNum; i++) {
printf("---");
}
printf("\n");
for (int i = 0; i < G.vexNum; i++) {
printf(" %c | ", G.vexs[i]);
for (int j = 0; j < G.vexNum; j++) {
printf(" %d ", G.arcs[i][j]);
}
printf("\n");
}
printf("========================================\n");
}
void DFS(MyGraph G, int v) {
visited[v] = 1;
printf("%c ", G.vexs[v]);
for (int i = 0; i < G.vexNum; i++) {
if (G.arcs[v][i] == 1 && visited[i] == 0) {
DFS(G, i);
}
}
}
void DFSFromVex(MyGraph G, VexType start) {
memset(visited, 0, sizeof(visited));
int startPos = LocateVex(G, start);
if (startPos != -1) {
DFS(G, startPos);
}
}
void BFS(MyGraph G, int v) {
int queue[MAXQSIZE];
int front = 0, rear = 0;
visited[v] = 1;
printf("%c ", G.vexs[v]);
queue[rear++] = v;
while (front < rear) {
int u = queue[front++];
for (int i = 0; i < G.vexNum; i++) {
if (G.arcs[u][i] == 1 && visited[i] == 0) {
visited[i] = 1;
printf("%c ", G.vexs[i]);
queue[rear++] = i;
}
}
}
}
void BFSFromVex(MyGraph G, VexType start) {
memset(visited, 0, sizeof(visited));
int startPos = LocateVex(G, start);
if (startPos != -1) {
BFS(G, startPos);
}
}
int main() {
printf("========================================\n");
MyGraph G;
CreateUDGraphFromConsole(&G);
PrintMGraph(G);
printf("\n【从A节点DFS遍历】\n");
printf("遍历结果:");
DFSFromVex(G, 'A');
printf("\n");
printf("\n【从F节点DFS遍历】\n");
printf("遍历结果:");
DFSFromVex(G, 'F');
printf("\n");
printf("\n【从F节点BFS遍历】\n");
printf("遍历结果:");
BFSFromVex(G, 'F');
printf("\n");
printf("\n按任意键退出...");
getchar();
getchar();
return 0;
}
时间复杂度
O(n²)
空间复杂度
O(n)
题目3:图的着色
AddEdge函数相关伪代码
函数 AddEdge(G, u, v)
将v加入u的邻接表
将u加入v的邻接表
CheckOne函数相关伪代码
函数 CheckOne(V, K)
// 输入颜色
for i = 1 to V do
输入 color[i]
// 检查颜色种数
colorCount = 0
memset(used, 0, sizeof(used))
for i = 1 to V do
if used[color[i]] == 0 then
used[color[i]] = 1
colorCount++
if colorCount != K then
return false
// 检查相邻顶点
for i = 1 to V do
for 每个邻接点 j in 邻接表[i] do
if color[i] == color[j] then
return false
return true
main函数相关伪代码
函数 main()
输入 V, E, K
建图
输入 N
for i = 1 to N do
if CheckOne(V, K) then
输出 "Yes"
else
输出 "No"
函数代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXV 505
typedef struct EdgeNode {
int adjvex;
struct EdgeNode* next;
} EdgeNode;
typedef struct {
EdgeNode* adjList[MAXV];
int vexNum;
} Graph;
void AddEdge(Graph* G, int u, int v) {
EdgeNode* e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = v;
e->next = G->adjList[u];
G->adjList[u] = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = u;
e->next = G->adjList[v];
G->adjList[v] = e;
}
int main() {
printf("========================================\n\n");
Graph G;
int V, E, K;
scanf("%d %d %d", &V, &E, &K);
G.vexNum = V;
for (int i = 1; i <= V; i++) {
G.adjList[i] = NULL;
}
for (int i = 0; i < E; i++) {
int u, v;
scanf("%d %d", &u, &v);
AddEdge(&G, u, v);
}
int N;
scanf("%d", &N);
int color[MAXV];
int used[MAXV];
for (int s = 0; s < N; s++) {
for (int i = 1; i <= V; i++) {
scanf("%d", &color[i]);
}
memset(used, 0, sizeof(used));
int colorCount = 0;
for (int i = 1; i <= V; i++) {
if (used[color[i]] == 0) {
used[color[i]] = 1;
colorCount++;
}
}
if (colorCount != K) {
printf("No\n");
continue;
}
int valid = 1;
for (int i = 1; i <= V && valid; i++) {
EdgeNode* p = G.adjList[i];
while (p) {
if (color[i] == color[p->adjvex]) {
valid = 0;
break;
}
p = p->next;
}
}
printf("%s\n", valid ? "Yes" : "No");
}
return 0;
}
时间复杂度
O(N × (n + e))
n = 顶点数,e = 边数,N = 着色方案数
空间复杂度
O(n + e)
n = 顶点数,e = 边数,
题目4:公路村村通
函数相关伪代码
#include <limits.h>
#define MAX_VERTICES 100
typedef struct {
int edges[MAX_VERTICES][MAX_VERTICES];
int n; // 顶点数(城市数)
int m; // 边数(路数)
} Graph;
int Prim(Graph g) {
int dist[MAX_VERTICES]; // 到当前树的最小距离
int visited[MAX_VERTICES]; // 是否已加入树
int totalCost = 0;
// 1. 初始化
for (int i = 0; i < g.n; i++) {
dist[i] = INT_MAX; // 无穷大
visited[i] = 0;
}
// 2. 从第一个顶点(下标0)开始
dist[0] = 0;
// 3. 主循环:每次加入一个顶点,共 n 次
for (int count = 0; count < g.n; count++) {
// 3.1 找未加入且 dist 最小的顶点 u
int u = -1;
for (int i = 0; i < g.n; i++) {
if (!visited[i] && (u == -1 || dist[i] < dist[u])) {
u = i;
}
}
// 3.2 判断不连通
if (dist[u] == INT_MAX) {
return -1; // 剩下的顶点都不可达,图不连通
}
// 3.3 加入 u
visited[u] = 1;
totalCost += dist[u];
// 3.4 更新其他顶点的距离
for (int v = 0; v < g.n; v++) {
// 如果 v 未加入,且 u-v 有边,且这条边比当前 dist[v] 更小
if (!visited[v] && g.edges[u][v] < dist[v]) {
dist[v] = g.edges[u][v];
}
}
}
return totalCost;
}
与ai互动过程
请点击此链接观看与deep seek的互动过程
https://chat.deepseek.com/share/uy7luol5yyw0lkoakm
函数代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <limits.h>
#define MAX_VERTICES 100
typedef struct {
int edges[MAX_VERTICES][MAX_VERTICES];
int n;
int m;
} Graph;
void initGraph(Graph* g, int n, int m) {
int i, j;
g->n = n;
g->m = m;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (i == j) {
g->edges[i][j] = 0;
}
else {
g->edges[i][j] = INT_MAX;
}
}
}
}
void addEdge(Graph* g, int u, int v, int cost) {
if (u >= 0 && u < g->n && v >= 0 && v < g->n) {
g->edges[u][v] = cost;
g->edges[v][u] = cost;
}
}
int Prim(Graph g) {
int dist[MAX_VERTICES];
int visited[MAX_VERTICES];
int totalCost = 0;
int i, count, u, v;
for (i = 0; i < g.n; i++) {
dist[i] = INT_MAX;
visited[i] = 0;
}
dist[0] = 0;
for (count = 0; count < g.n; count++) {
u = -1;
for (i = 0; i < g.n; i++) {
if (!visited[i] && (u == -1 || dist[i] < dist[u])) {
u = i;
}
}
if (dist[u] == INT_MAX) {
return -1;
}
visited[u] = 1;
totalCost += dist[u];
for (v = 0; v < g.n; v++) {
if (!visited[v] && g.edges[u][v] < dist[v]) {
dist[v] = g.edges[u][v];
}
}
}
return totalCost;
}
void printGraph(Graph g) {
int i, j;
printf("图的邻接矩阵(%d个顶点):\n", g.n);
printf(" ");
for (i = 0; i < g.n; i++) {
printf("%4d ", i);
}
printf("\n");
for (i = 0; i < g.n; i++) {
printf("%4d ", i);
for (j = 0; j < g.n; j++) {
if (g.edges[i][j] == INT_MAX) {
printf(" ∞ ");
}
else {
printf("%4d ", g.edges[i][j]);
}
}
printf("\n");
}
}
int main() {
printf("========== 测试用例1:连通图 ==========\n");
Graph g1;
initGraph(&g1, 4, 5);
addEdge(&g1, 0, 1, 5);
addEdge(&g1, 0, 2, 8);
addEdge(&g1, 0, 3, 3);
addEdge(&g1, 1, 2, 6);
addEdge(&g1, 2, 3, 7);
printGraph(g1);
int result1 = Prim(g1);
printf("最小生成树总花费: %d\n", result1);
printf("\n");
printf("========== 测试用例2:不连通图 ==========\n");
Graph g2;
initGraph(&g2, 4, 3);
addEdge(&g2, 0, 1, 5);
addEdge(&g2, 1, 2, 6);
printGraph(g2);
int result2 = Prim(g2);
printf("最小生成树总花费: %d (返回-1表示不连通)\n", result2);
printf("\n");
printf("========== 测试用例3:手动输入 ==========\n");
printf("请输入城市数量 n 和道路数量 m:");
int n, m;
scanf("%d %d", &n, &m);
Graph g3;
initGraph(&g3, n, m);
printf("请输入 %d 条道路,格式:城市1 城市2 花费(城市编号从0到%d)\n", m, n - 1);
for (int i = 0; i < m; i++) {
int u, v, cost;
scanf("%d %d %d", &u, &v, &cost);
addEdge(&g3, u, v, cost);
}
printGraph(g3);
int result3 = Prim(g3);
if (result3 == -1) {
printf("图不连通,无法实现村村通!\n");
}
else {
printf("最小生成树总花费:%d\n", result3);
}
printf("\n按任意键退出...");
getchar();
getchar();
return 0;
}
时间复杂度
O(n²)
空间复杂度
O(n²)
三、实验使用环境(本次实验所使用的平台和相关软件)
- 操作系统:Windows 11
- 编程语言:C++
- 开发工具:[Visual Studio Insiders]
- 编译器:MSVC
四、实验步骤和调试过程(实验步骤、测试数据设计、测试结果分析)
以下请根据实际情况编写
题目1:图的创建
本机运行截图

题目2:图的遍历
本机运行截图

题目3:图着色问题
本机运行截图

PTA提交截图

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

PTA提交截图

五、实验小结(实验中遇到的问题及解决过程、实验体会和收获)
以下请根据实际情况编写
遇到的问题及解决方法:
- 问题:邻接矩阵初始化时忘记对称赋值,导致输出矩阵不对称
- 解决方法:添加 G->arcs[j][i] = w,确保无向图邻接矩阵对称
- 问题:BFS遍历结果与预期不符
- 解决方法:使用打断点调试,发现是队列操作顺序问题,修正后结果正确
实验体会和收获:
- 学会了使用邻接表存储图,理解了邻接矩阵和邻接表的适用场景。
- 理解了Prim算法求解最小生成树的核心思想。
- 掌握了邻接矩阵存储图的方法,理解了无向图矩阵的对称性。
六、附件(参考文献和相关资料)
无
浙公网安备 33010602011771号