C数据结构——无向图(邻接矩阵方式) 创建与基本使用

news2024/11/24 16:19:34

源码+注释

//
// Created by Lenovo on 2022-05-13-上午 9:06.
// 作者:小象
// 版本:1.0
//

#include <stdio.h>
#include <malloc.h>

#define MAXSIZE 1000 // BFS队列可能达到的最大长度
#define MAX_AMVNUMS 100 // 最大顶点数

typedef enum {
    FALSE,
    TRUE
} Boolean;

typedef struct { // 定义队列
    int *base; // 存储空间的基地址
    int front; // 头指针
    int rear; // 尾指针
} SqQueue;

typedef struct { // 定义图
    char verxs[MAX_AMVNUMS]; // 顶点表
    int arcs[MAX_AMVNUMS][MAX_AMVNUMS]; // 邻接矩阵
    int numVertexes, numEdges; // 图的当前顶点数和边数
} AMGraph;

Boolean visited[MAX_AMVNUMS]; // 访问标志数组,其初值为"false"

void CreateAMGraph(AMGraph *G); // 用邻接矩阵表示法创建无向图
void PrintAMatrix(AMGraph G); // 打印邻接矩阵
void DFSTraverse(AMGraph G, int v); // 非连通图 深度优先搜索遍历
void DFS_AM(AMGraph G, int v); // 邻接矩阵 深度优先搜索遍历(连通图)
void BFSTraverse(AMGraph G, int v); // 非连通图 广度优先搜索遍历
void BFS_AM(AMGraph G, int v); // 邻接矩阵 广度优先搜索遍历(连通图)
Boolean InitQueue(SqQueue *queue); // BFS队列初始化
Boolean EnQueue(SqQueue *queue, int elem); // BFS队列入队列
Boolean DeQueue(SqQueue *queue, int *elem); // 循环队列出队列
Boolean IsFull(SqQueue *queue); // 判队满
Boolean IsEmpty(SqQueue *queue); // 判队空

/**
 * <h2>无向图的创建和遍历(无向网同理)</h2>
 * <h3>无向图邻接矩阵特点: <br>
 * 1.边值对称 <br>
 * 2.若有相邻点,一定在矩阵同一行里</h3>
 * @return 0
 */
int main() {

    AMGraph *G;
    G = (AMGraph *) malloc(sizeof(AMGraph)); // 为图G生成内存空间

    CreateAMGraph(G); // 创建
    PrintAMatrix(*G); // 打印
    DFSTraverse(*G, 1); // 深度遍历
    printf("\n");
    BFSTraverse(*G, 3); // 广度搜索

    getchar();
}

// 使用邻接矩阵表示法,创建无向图
void CreateAMGraph(AMGraph *G) {

    // 输入总顶点数和边数
    printf("输入无向图的顶点数和边数,用空格分开:");
    scanf("%d %d", &(G->numVertexes), &(G->numEdges));
    getchar();

    // 依次输入顶点的信息
    for (int i = 0; i < G->numVertexes; i++) {
/*        printf("输入第%d个顶点信息:", (i + 1));
        scanf("%c", &G->verxs[i]);
        getchar();*/
        G->verxs[i] = i;
    }

    // 初始化邻接矩阵
    for (int i = 0; i < G->numVertexes; i++) {
        for (int j = 0; j < G->numVertexes; j++) {
            G->arcs[i][j] = 0;
        }
    }

    // 构造邻接矩阵
//    int sub1, sub2;
    int arrSub1[] = {0, 0, 1, 1, 2, 2, 3, 4, 5};
    int arrSub2[] = {1, 2, 3, 4, 5, 6, 7, 7, 6};
    for (int i = 0; i < G->numEdges; i++) {
/*        printf("请输入第%d条边(v1,v2)上的下标i和下标j:", (i + 1)); // 输入一条边依附的顶点
        scanf("%d %d", &sub1, &sub2); // 确定v1和v2在G中的位置,即顶点数组的下标
        getchar();*/
        G->arcs[arrSub1[i]][arrSub2[i]] = G->arcs[arrSub2[i]][arrSub1[i]] = 1; // 边 <v1, v2>的顶点值为 1
        // 因为无向图是对称边,所以边<v2, v1>的顶点值也为 1
    }
}

// 打印邻接矩阵
void PrintAMatrix(AMGraph G) {
    for (int i = 0; i < G.numVertexes; i++) {
        for (int j = 0; j < G.numVertexes; j++) {
            printf("%d ", G.arcs[i][j]);
        }
        printf("\n");
    }
}

// 对非连通图G做 深度优先遍历
void DFSTraverse(AMGraph G, int v) {
    // 注意:对于以下所有循环次数解析,最多有numVertexes顶点个连通图,所以循环numVertexes次就足够保证整个非连通图都被遍历到
    for (int i = 0; i < G.numVertexes; i++) {
        visited[i] = FALSE; // 访问标志数组初始化
    }
    for (int i = 0; i < G.numVertexes; i++) { // 循环调用遍历连通图的算法函数
        if (!visited[i]) {
            DFS_AM(G, v); // 对尚未访问的顶点调用DFS_AM()
        }
    }
}

// 图G为邻接矩阵类型,从第v个顶点出发 深度优先搜索遍历 图G
void DFS_AM(AMGraph G, int v) {
    printf("V%d ", v);
    visited[v] = TRUE; // 访问第v个顶点,并置访问标志数组相应分量值为true
    for (int i = 0; i < G.numVertexes; i++) { // 依次检查邻接矩阵 v 所在的行
        // G.arcs[v][i]!=0 表示i是v的邻接点。如果i未访问,则递归调用DFS_AM
        if ((G.arcs[v][i] != 0) && (!visited[i])) {
            DFS_AM(G, i); // 相邻点放入,递归遍历
        }
    }
}

// 对非连通图G做 广度优先遍历
void BFSTraverse(AMGraph G, int v) {
    // 注意:对于以下所有循环次数解析,最多有numVertexes顶点个连通图,所以循环numVertexes次就足够保证整个非连通图都被遍历到
    for (int i = 0; i < G.numVertexes; i++) {
        visited[i] = FALSE; // 访问标志数组初始化
    }
    for (int i = 0; i < G.numVertexes; i++) { // 循环调用遍历连通图的算法函数
        if (!visited[i]) {
            BFS_AM(G, v); // 对尚未访问的顶点调用BFS_AM()
        }
    }
}

// 图G为邻接矩阵类型,从第v个顶点出发 广度优先搜索遍历 图G
void BFS_AM(AMGraph G, int v) {
    printf("V%d ", v);
    visited[v] = TRUE; // 访问第v个顶点,并置访问标志数组相应分量值为 true
    SqQueue queue;
    InitQueue(&queue); // 辅助队列queue初始化,置空
    EnQueue(&queue, v); // v 进队
    int u;
    while (!IsEmpty(&queue)) {
        DeQueue(&queue, &u); // 队头元素出队并置为 u
        for (int i = 0; i < G.numVertexes; i++) { // 依次检查邻接矩阵 u 所在的行
            // G.arcs[u][i]!=0 表示i是u的邻接点。如果i未访问,则递归调用BFS_AM
            if ((G.arcs[u][i] != 0) && (!visited[i])) {
                printf("V%d ", i);
                visited[i] = TRUE; // 访问第i个顶点,并置访问标志数组相应分量值为true
                EnQueue(&queue, i);  // i 进队
            }
        }
    }
}

// 构造一个空队列 queue
Boolean InitQueue(SqQueue *queue) {
    queue->base = (int *) malloc(sizeof(int) * MAXSIZE); // 为队列分配一个最大容量为 MAXSIZE 的数组空间
    if (!(queue->base)) {
        return FALSE; // 存储分配失败
    }
    queue->front = queue->rear = 0; // 头指针和尾指针置为0 , 队列为空
    return TRUE;
}

// 插入元素 elem 为 queue 的新的队尾元素
Boolean EnQueue(SqQueue *queue, int elem) {
    if (IsFull(queue)) {
        return FALSE;
    }
    queue->base[queue->rear] = elem; // 新元素插入队尾
    queue->rear = (queue->rear + 1) % MAXSIZE; // 队尾指针加 1
    return TRUE;
}

// 删除 queue 的队头元素,用 elem 返回其值
Boolean DeQueue(SqQueue *queue, int *elem) {
    if (IsEmpty(queue)) {
        return FALSE;
    }
    *elem = queue->base[queue->front]; // 保存队头元素
    queue->front = (queue->front + 1) % MAXSIZE; // 队头指针加 1
    return TRUE;
}

// 尾指针在循环意义上加1 后等于头指针,表明队满
Boolean IsFull(SqQueue *queue) {
    return (queue->rear + 1) % MAXSIZE == queue->front; // 循环
}

// 队空
Boolean IsEmpty(SqQueue *queue) {
    return queue->front == queue->rear;
}

运行结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/820068.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用SpringBoot实现post和get请求(多图)

用SpringBoot实现post和get请求&#xff08;多图&#xff09; 用SpringBoot实现post和get请求创建SpringBoot工程创建controller验证FAQ创建项目后依赖报错Project org.springframework.boot:spring-boot-starter-parent:3.1.2.RELEASE not found more 用SpringBoot实现post和g…

AQS构建锁和同步器的框架

1.概述 AQS全称AbstractQueuedSynchronizer&#xff0c;此类在java.util.concurrent.locks包下面&#xff0c;是一个构建锁和同步器的框架&#xff0c;比如ReentrantLock就是基于AQS来实现的。 2.AQS实现原理 AQS内部有一个由volatile修饰(保证其可见性)的变量state&#xf…

PDF文件忘记密码,怎么办?

PDF文件设置密码分为打开密码和限制密码&#xff0c;忘记了密码分别如何解密PDF密码&#xff1f; 如果是限制编辑密码忘记了&#xff0c;我们可以试着将PDF文件转换成其他格式来避开限制编辑&#xff0c;然后重新将文件转换回PDF格式就可以了。 如果因为转换之后导致文件格式…

Tuxera NTFS2023Mac强大的Mac读写工具

Mac用户在使用NTFS格式移动硬盘时&#xff0c;会遇到无法写入硬盘的情况。要想解决无法写入的问题&#xff0c;很多人选择使用Mac读写软件。面对市面上“众多”的读写硬盘软件&#xff0c;用户应该怎么选择呢&#xff1f;初次接触移动硬盘的伙伴可能不知道移动硬盘怎么和电脑连…

RabbitMQ 教程 | 第6章 RabbitMQ 配置

&#x1f468;&#x1f3fb;‍&#x1f4bb; 热爱摄影的程序员 &#x1f468;&#x1f3fb;‍&#x1f3a8; 喜欢编码的设计师 &#x1f9d5;&#x1f3fb; 擅长设计的剪辑师 &#x1f9d1;&#x1f3fb;‍&#x1f3eb; 一位高冷无情的编码爱好者 大家好&#xff0c;我是 DevO…

科大讯飞 - 基于论文摘要的文本分类与关键词抽取挑战赛(DataWhale-Camp)

文章目录 1、赛题信息2、解决方案2.1 飞桨Baseline&#xff08;提供代码&#xff09;2.2 Bert和调参2.3 chatGLMlora大模型 3、关于DataWhale-NLP 1、赛题信息 提交地址&#xff1a;https://challenge.xfyun.cn/topic/info?typeabstract-of-the-paper&chymfk4uU 项目题目…

我的会议(会议通知)

前言: 我们在实现了发布会议功能&#xff0c;我的会议功能的基础上&#xff0c;继续来实现会议通知的功能。 4.1实现的特色功能&#xff1a; 当有会议要参加时&#xff0c;通过查询会议通知可以知道会议的内容&#xff0c;以及当前会议状态&#xff08;未读&#xff09; 4.2思路…

在Linux中怎么查找文件

2023年8月1日&#xff0c;周二上午 目录 Linux的四种搜索命令find简要说明举例说明拓展阅读locate 简要说明举例说明whereis简要说明举例说明which简要说明举例说明 Linux的四种搜索命令 findlocate&#xff08;不一定内置有&#xff0c;可能要下载mlocate包&#xff09;wher…

【概念理解】HAL库的滴答定时器HAL_Delay()函数的实现原理

来源&#xff1a;bilibili视频 这里写目录标题 概述一、寄存器部分1. 控制和状态寄存器(STK_CTRL)2. 加载值寄存器&#xff08;STK_LOAD&#xff09;3.当前值寄存器&#xff08;STK_VAL&#xff09; 二、代码部分hal_delay()1. hal_initTick()滴答定时器的初始化2. 将七万二传…

Redis 客户端有哪些?

文章目录 JedisLettuceRedisson最佳实践 - 到底用哪个&#xff1f; Redis 最常见的 Java 客户端有两个&#xff0c;Jedis 和 Lettuce&#xff0c;高级客户端有 Redisson&#xff0c;见下图&#xff08;图源 Clients | Redis&#xff09; Jedis Github地址&#xff1a;redis/j…

Windows下安装Hive(包安装成功)

Windows下安装Hive Hive与Hadoop的版本选择很关键&#xff0c;千万不能选错&#xff0c;否则各种报错。一、Hive下载1.1、官网下载Hive1.2、网盘下载Hive 二、解压安装包&#xff0c;配置Hive环境变量2.1、环境变量新增&#xff1a;HIVE_HOME2.2、修改Path环境变量&#xff0c;…

Oracle免费在线编程:Oracle APEX

前提&#xff1a; 注意&#xff1a;你要有个梯子才能更稳定的访问。 不需要安装Oracle&#xff0c;但是需要注册。&#xff08;还算方便的&#xff09; 注册&登录过程 进入Oracle APEX官网&#xff0c;我们选择免费的APEX工作区即可&#xff0c;点击“免费注册”。在注册…

基于H5或者微信小程序开发GIS地图实战全套代码

1 下面有一定基础的可以不看 (1)第一篇请看 微信小程序开发天地图 (2)第二篇请看 http://GeoServer+PostgreSQL+PostGIS+Tomcat+QGIS一整套相关 (3)第三篇请看 有国产化需求的 (4)第四篇请看 支持国家EPSG:4490 2 vue+openlayers实例代码

ThreadLocal原理

ThreadLocal原理 ThreadLocal对象new出来存放到堆中&#xff0c;ThreadLocal引用是存放在栈里 Thread 类有个 ThreadLocalMap 成员变量&#xff0c;Map的key是Threadlocal 对象&#xff0c;value是你要存放的线程局部变量。 public void set(T value) {//获取当前线程Thread&…

SpringBoot复习:(11)SpringApplication中的listeners成员变量是怎么初始化的?

initializers成员变量定义如下&#xff1a; 在构造方法中&#xff1a; setListeners代码如下&#xff1a; 给setListeners方法传递的是getSpringFactoriesInstances(ApplicationListener.class). getSpringFactoriesInstances代码如下&#xff1a; 调用的重载的getSpringFa…

redis 高级篇4 分布式锁

一 redis架构图 1.1 redis的架构图 1.2 分布式锁满足条件 1.独占性&#xff1b;2.高可用&#xff1b;3.防死锁&#xff1b;4.不乱抢&#xff1b;5.重入性 二 分布式锁的案例情况 2.1 分布式锁1:单机分布式部署 描述&#xff1a; 使用lock锁和synchronized&#xff0c;单机…

【shell】获取ping的时延数据并分析网络情况及常用命令学习

文章目录 获取ping的时延数据并分析网络情况|、||、&、&&辨析teetailkillall 获取ping的时延数据并分析网络情况 网络情况经常让我们头疼&#xff0c;每次都需要手动在终端ping太麻烦了&#xff0c;不如写个脚本ping并将数据带上时间戳存入文件&#xff0c;然后也…

iPhone 6透明屏是什么?原理、特点、优势

iPhone 6透明屏是一种特殊的屏幕技术&#xff0c;它能够使手机屏幕变得透明&#xff0c;让用户能够透过屏幕看到手机背后的物体。 这种技术在科幻电影中经常出现&#xff0c;给人一种未来科技的感觉。下面将介绍iPhone 6透明屏的原理、特点以及可能的应用。 iPhone 6透明屏的原…

【外卖系统】新增菜品

需求分析 在后台中&#xff0c;通过新增功能来添加一个新的菜品&#xff0c;在添加菜品时需要选择当前菜品所属的菜品分类&#xff0c;并且需要上传的菜品图片。 代码开发 需要添加的类和基本接口&#xff1a;实体类DishFlavor、Mapper接口DishFlavorMapper、业务层接口Dish…

顶尖211,央企收割机!面试仅16%!超线30分,稳稳上岸!

一、学校及专业介绍 南京理工大学&#xff08;Nanjing University of Science and Technology&#xff09;&#xff0c;简称南理&#xff0c;位于南京市&#xff0c;是隶属于工业和信息化部的全国重点大学&#xff0c;是国家“双一流”建设高校&#xff0c;“211工程”。由于学…