• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

yzx46

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

图

集美大学课程实验报告-实验3:栈、队列与递归

项目名称 内容
课程名称 数据结构
班级 网安2512
实验项目名称 图
上机实践日期 5月28日
上机实践时间 2学时

一、目的(本次实验所涉及并要求掌握的知识点)

以下内容请根据实际情况编写

  1. 学会创建图(邻接矩阵),掌握在图上的基本操作。
  2. 掌握图遍历算法:DFS与BFS。
  3. 掌握编写最小生成树算法。

二、实验内容与设计思想

  1. 任务书:题目1—图的创建
  2. 任务书:题目2—图的遍历(DFS、BFS)
  3. PTA:图着色问题
  4. AI任务:公路村村通(最小生成树)

题目1:图的创建

函数相关伪代码

vex[]  //点集合
arcs[][]  //边集合
LocateVex()  //先输入点
然后进行点与边的输入

函数代码

#include<iostream>
#include<string>

using namespace std;

#define MAXVEXNUM 100

//点,边
typedef int ArcCell;
typedef char VexType;

typedef struct {
    VexType vexs[MAXVEXNUM];  
    ArcCell arcs[MAXVEXNUM][MAXVEXNUM];  
    int vexNum, arcNum;
} MyGraph;

void CreateDGraphFromConsole(MyGraph& G, int vexNum, int arcNum);

int LocateVex(MyGraph* G, int value)
 {
    for (int i = 0; i < G->vexNum; i++) 
    {
        if (value == G->vexs[i])
            return i;
    }
    return -1;
}

void CreateDGraphFromConsole(MyGraph& G, int vexNum, int arcNum)
 {
    G.vexNum = vexNum;
    G.arcNum = arcNum;

    memset(G.vexs, 0, sizeof(G.vexs));
    memset(G.arcs, 0, sizeof(G.arcs));

    for (size_t i = 0; i < G.vexNum; i++)
     {
        cin >> G.vexs[i];
    }

    char x, y;
    ArcCell value;

    for (size_t i = 0; i < G.arcNum; i++)
     {
        cin >> x >> y >> value;
        int x1 = LocateVex(&G, x);
        int y1 = LocateVex(&G, y);
        G.arcs[x1][y1] = value;
        G.arcs[y1][x1] = value;
    }
}

int main()
 {
    MyGraph G;
    int vexNum, arcNum;

    cout << "请输入顶点数和边数:";
    cin >> vexNum >> arcNum;

    cout << "请输入 " << vexNum << " 个顶点值(字符,连续输入或空格分隔):" << endl;
    CreateDGraphFromConsole(G, vexNum, arcNum);

    // 打印邻接矩阵
    cout << "\n邻接矩阵如下:" << endl;
    cout << "  ";
    for (int i = 0; i < G.vexNum; i++) 
    {
        cout << G.vexs[i] << " ";
    }
    cout << endl;

    for (int i = 0; i < G.vexNum; i++) 
    {
        cout << G.vexs[i] << " ";
        for (int j = 0; j < G.vexNum; j++) 
        {
            cout << G.arcs[i][j] << " ";
        }
        cout << endl;
    }

    return 0;
}

题目2:图的遍历(DFS、BFS)

函数相关伪代码

DFS:先访问邻接点,等到头或是访问过,就用递归来返回上一个节点,然后找到未访问的节点,直到所有节点都被访问
BFS:先处理顶点,然后与顶点相连的邻接节点入队列,然后访问这些邻接点的邻接点,直到所有节点都被访问

函数代码

#include <iostream>
#include <string>
#include <cstdio>
#include <queue>
using namespace std;

#define INTMAX 32767
#define MAXVEXNUM 100

//点,边
typedef char VexType;
typedef int ArcCell;

typedef struct 
{
    VexType vexs[MAXVEXNUM];  // 点的集合
    ArcCell arcs[MAXVEXNUM][MAXVEXNUM];  // 边的集合
    int vexNum, arcNum;
} MyGraph;

MyGraph* CreateDefaultGraph1()  // 创建无向图
{
    MyGraph* G = new MyGraph;

    // 初始化邻接矩阵
    memset(G->arcs, 0, sizeof(G->arcs));
    memset(G->vexs, 0, sizeof(G->vexs));

    G->vexNum = 6;
    G->arcNum = 7;

    G->vexs[0] = 'a';
    G->vexs[1] = 'b';
    G->vexs[2] = 'c';
    G->vexs[3] = 'd';
    G->vexs[4] = 'e';
    G->vexs[5] = 'f';

    G->arcs[0][1] = G->arcs[1][0] = 1;
    G->arcs[0][4] = G->arcs[4][0] = 1;
    G->arcs[1][4] = G->arcs[4][1] = 1;
    G->arcs[1][5] = G->arcs[5][1] = 1;
    G->arcs[2][3] = G->arcs[3][2] = 1;
    G->arcs[2][5] = G->arcs[5][2] = 1;
    G->arcs[3][5] = G->arcs[5][3] = 1;

    return G;
}

MyGraph* CreateDefaultGraph2()  // 创建有向图
{
    MyGraph* G = new MyGraph;

    // 初始化邻接矩阵
    memset(G->arcs, 0, sizeof(G->arcs));
    memset(G->vexs, 0, sizeof(G->vexs));

    G->vexNum = 5;
    G->arcNum = 7;

    G->vexs[0] = '1';
    G->vexs[1] = '2';
    G->vexs[2] = '3';
    G->vexs[3] = '4';
    G->vexs[4] = '5';

    G->arcs[0][1] = 10;
    G->arcs[0][3] = 30;
    G->arcs[0][4] = 100;
    G->arcs[1][2] = 50;
    G->arcs[2][4] = 10;
    G->arcs[3][2] = 20;
    G->arcs[3][4] = 60;

    return G;
}

// 根据value节点值返回节点位置,没找到则返回-1
int LocateVex(MyGraph* G, VexType value) 
{
    for (int i = 0; i < G->vexNum; i++) 
    {
        if (value == G->vexs[i])
            return i;
    }
    return -1;
}

void printGraph(MyGraph* G) 
{
    // 输出图的基本信息(几个点、几条边)
    cout << "图中的点数:" << G->vexNum << ", 边数:" << G->arcNum << endl;

    // 输出图的信息(每行先输出点名称,再输出该行所有值)
    for (int i = 0; i < G->vexNum; i++) 
    {
        // 打印点
        cout << G->vexs[i] << " ";
        for (int j = 0; j < G->vexNum; j++) 
        {
            cout << G->arcs[i][j] << "\t";
        }
        cout << endl;
    }
}

void BFS(MyGraph* G, VexType v, bool* visited) 
{
    queue<int> q;
    int startIdx = LocateVex(G, v);

    q.push(startIdx);
    visited[startIdx] = true;

    while (!q.empty()) 
    {
        int currentIdx = q.front();
        q.pop();
        cout << G->vexs[currentIdx] << " ";

        // 遍历所有邻接点
        for (int i = 0; i < G->vexNum; i++)
        {
            if (G->arcs[currentIdx][i] != 0 && !visited[i])
            {
                visited[i] = true;
                q.push(i);
            }
        }
    }
}

void BFSTravse(MyGraph* G) {
    bool* visited = new bool[G->vexNum]();  // 初始化为 false

    cout << "BFS遍历结果(非连通图):";
    for (int i = 0; i < G->vexNum; i++) {
        if (!visited[i]) {
            BFS(G, G->vexs[i], visited);
        }
    }
    cout << endl;

    delete[] visited;
}

void DFS(MyGraph* G, VexType v, bool* visited) 
{
    int index = LocateVex(G, v);
    cout << G->vexs[index] << " ";
    visited[index] = true;

    for (int i = 0; i < G->vexNum; i++) 
    {
        if (G->arcs[index][i] != 0)
        {
            if (!visited[i]) 
            {
                DFS(G, G->vexs[i], visited);
            }
        }
    }
}

void DFSTravse(MyGraph* G) {
    bool* visited = new bool[G->vexNum]();  // 初始化为 false

    cout << "DFS遍历结果(非连通图):";
    for (int i = 0; i < G->vexNum; i++) {
        if (!visited[i]) {
            DFS(G, G->vexs[i], visited);  // 修正:传入顶点值,而不是索引 i
        }
    }
    cout << endl;

    delete[] visited;
}


int main()
{
    // 测试无向图
    cout << "========== 测试无向图 ==========" << endl;
    MyGraph* myGraph = CreateDefaultGraph1();
    printGraph(myGraph);

    // DFS 遍历连通图(从 a 开始)
    cout << "\nDFS遍历(从a开始):";
    bool* visited = new bool[myGraph->vexNum]();
    DFS(myGraph, 'a', visited);
    cout << endl;

    // DFS 遍历非连通图
    DFSTravse(myGraph);

    // BFS 遍历非连通图
    BFSTravse(myGraph);

    delete[] visited;

    // 测试有向图
    cout << "\n========== 测试有向图 ==========" << endl;
    MyGraph* myGraph2 = CreateDefaultGraph2();
    printGraph(myGraph2);

    // BFS 遍历有向图
    BFSTravse(myGraph2);

    // DFS 遍历有向图
    DFSTravse(myGraph2);

    return 0;
}

题目3:图的着色问题

函数相关伪代码

先用数组储存所有边
用给定数据中相同颜色的节点创建另一个数组
然后比较俩数组的边是否有相同边
如果有相同边则输出NO

函数代码

#include <iostream>
#include <set>
using namespace std;

#define MAXV 510  // 最大顶点数
#define MAXE 250000  // 最大边数(完全图)

int main() {
    int V, E, K;
    cin >> V >> E >> K;
    
    // 用数组存储边
    int u[MAXE], v[MAXE];  // 每条边的两个端点
    
    for (int i = 0; i < E; i++) {
        cin >> u[i] >> v[i];
    }
    
    int N;
    cin >> N;
    
    for (int i = 0; i < N; i++) {
        int colors[MAXV];  // 存储每个顶点的颜色
        set<int> colorSet;
        
        // 读入着色方案
        for (int j = 1; j <= V; j++) {
            cin >> colors[j];
            colorSet.insert(colors[j]);
        }
        
        // 条件1:颜色数必须等于K
        if (colorSet.size() != K) {
            cout << "No" << endl;
            continue;
        }
        
        // 条件2:检查每条边的两个端点颜色是否相同
        bool valid = true;
        for (int j = 0; j < E; j++) {
            if (colors[u[j]] == colors[v[j]]) {
                valid = false;
                break;
            }
        }
        
        cout << (valid ? "Yes" : "No") << endl;
    }
    
    return 0;
}

题目4:公路村村通(最小生成树)

函数相关伪代码

typedef struct 
{
    int vex[];          // 顶点列表(存储顶点编号 1..n)
    int edges[][];  // 邻接矩阵,存储边权
} MyGraph;
CreateGraph9()//创建一个图
Prim()
{
   从1开始构建
   初始化 lowcost:顶点 1 到其他顶点的距离
   再加入 n-1 个顶点
   选择当前树到未加入顶点中最小的边
   若找不到最小边,返回 -1
   将顶点 u 加入生成树,累加
   更新 lowcost
}

函数代码

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define MAXN 1005
#define INF INT_MAX

typedef struct {
    int vex[MAXN];          // 顶点编号(实际就是 1..n)
    int edges[MAXN][MAXN];  // 邻接矩阵,存储边权
    int n, m;               // 顶点数,边数
} MyGraph;

// 创建并初始化图
void CreateGraph(MyGraph *G, int n, int m) {
    G->n = n;
    G->m = m;
    
    // 初始化顶点编号
    for (int i = 1; i <= n; i++) {
        G->vex[i] = i;
    }
    
    // 初始化邻接矩阵
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i == j)
                G->edges[i][j] = 0;
            else
                G->edges[i][j] = INF;
        }
    }
    
    // 读入 m 条边
    int u, v, cost;
    for (int i = 0; i < m; i++) {
        scanf("%d %d %d", &u, &v, &cost);
        G->edges[u][v] = cost;
        G->edges[v][u] = cost;  // 无向图
    }
}

// Prim 算法求最小生成树总权值,若不连通返回 -1
int Prim(MyGraph *G) {
    int n = G->n;
    int lowcost[MAXN];  // 记录当前生成树到每个顶点的最小边权
    int visited[MAXN];  // 标记顶点是否已在生成树中
    int sum = 0;
    
    // 初始化
    for (int i = 1; i <= n; i++) {
        lowcost[i] = G->edges[1][i];   // 从顶点 1 出发
        visited[i] = 0;
    }
    visited[1] = 1;  // 顶点 1 加入生成树
    
    // 还需要加入 n-1 个顶点
    for (int count = 1; count < n; count++) {
        int minCost = INF;
        int u = -1;
        
        // 选择最小边
        for (int i = 1; i <= n; i++) {
            if (!visited[i] && lowcost[i] < minCost) {
                minCost = lowcost[i];
                u = i;
            }
        }
        
        if (u == -1) {  // 找不到最小边,说明图不连通
            return -1;
        }
        
        // 将 u 加入生成树
        visited[u] = 1;
        sum += minCost;
        
        // 更新 lowcost
        for (int v = 1; v <= n; v++) {
            if (!visited[v] && G->edges[u][v] < lowcost[v]) {
                lowcost[v] = G->edges[u][v];
            }
        }
    }
    
    return sum;
}

int main() {
    int n, m;
    scanf("%d %d", &n, &m);
    
    MyGraph G;
    CreateGraph(&G, n, m);
    
    int result = Prim(&G);
    printf("%d\n", result);
    
    return 0;
}

三、实验使用环境(本次实验所使用的平台和相关软件)

以下请根据实际情况编写

  • 操作系统:Windows 11专业版
  • 编程语言:C++
  • 开发工具:[Visual Studio 2025]

四、实验步骤和调试过程(实验步骤、测试数据设计、测试结果分析)

题目1:题目1—图的创建

本机运行截图
image

PTA提交截图
无

题目2:题目2—图的遍历(DFS、BFS)

本机运行截图
image

PTA提交截图
无

题目3:图着色问题

本机运行截图
image

PTA提交截图
image

题目4:公路村村通(最小生成树)

本机运行截图
image

PTA提交截图
image


五、实验小结(实验中遇到的问题及解决过程、实验体会和收获)

以下请根据实际情况编写

遇到的问题及解决方法:

  1. 问题:程序崩溃找不到原因,
    • 解决方法:使用打断点进行调试的方法。
  2. 问题:代码缩进不规范。
    • 解决方法:使用IDE的格式化工具修复代码。

实验体会和收获:

  • 学会了如何搭建C++开发环境。
  • 掌握了基本的代码调试方法。
  • 掌握了Visual Studio调试功能的基本使用

六、附件(参考文献和相关资料)

https://chat.deepseek.com/share/bfv3dca8to2boggo8j

posted on 2026-06-06 20:12  隋鑫46  阅读(10)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3