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

源码+注释

//
// 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;
}

运行结果

在这里插入图片描述

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小丶象

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值