C 语言中如何实现图结构?

news2024/9/21 18:33:00

C语言

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
📙C 语言百万年薪修炼课程 【https://dwz.mosong.cc/cyyjc】通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。

分割线

文章目录

  • C 语言中如何实现图结构
  • 一、图的基本概念
  • 二、图的表示方法
    • (一)邻接矩阵
    • (二)邻接表
  • 三、图的遍历
    • (一)深度优先搜索(DFS)
    • (二)广度优先搜索(BFS)
  • 四、图的应用
    • (一)网络路由
    • (二)社交网络分析
    • (三)任务调度
    • (四)地图导航
  • 五、总结

分割线


C 语言中如何实现图结构

在 C 语言中,实现图结构是一项重要且具有挑战性的任务。图是一种复杂的数据结构,用于表示对象之间的关系。它由顶点(Vertex)和边(Edge)组成,可以分为有向图和无向图两种类型。

一、图的基本概念

  1. 顶点(Vertex):图中的基本元素,表示一个独立的对象。
  2. 边(Edge):连接两个顶点的线段,表示顶点之间的关系。
  3. 有向图(Directed Graph):边具有方向,从一个顶点指向另一个顶点。
  4. 无向图(Undirected Graph):边没有方向,两个顶点之间的关系是相互的。

二、图的表示方法

在 C 语言中,常见的图表示方法有邻接矩阵(Adjacency Matrix)和邻接表(Adjacency List)。

(一)邻接矩阵

邻接矩阵是一个二维数组,用于表示图中顶点之间的连接关系。如果顶点 i 和顶点 j 之间有边相连,则矩阵中的 [i][j] 元素为 1(或边的权值);否则为 0。

以下是使用邻接矩阵表示无向图的 C 语言示例代码:

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

#define V 5  // 顶点数量

// 打印邻接矩阵
void printAdjMatrix(int adjMatrix[V][V]) {
    for (int i = 0; i < V; i++) {
        for (int j = 0; j < V; j++) {
            printf("%d ", adjMatrix[i][j]);
        }
        printf("\n");
    }
}

int main() {
    int adjMatrix[V][V] = {
        {0, 1, 0, 1, 0},
        {1, 0, 1, 0, 1},
        {0, 1, 0, 1, 0},
        {1, 0, 1, 0, 1},
        {0, 1, 0, 1, 0}
    };

    printf("邻接矩阵表示的无向图:\n");
    printAdjMatrix(adjMatrix);

    return 0;
}

邻接矩阵的优点是直观、简单,判断两个顶点之间是否有边的时间复杂度为 O(1)。但对于稀疏图(边的数量相对较少),会浪费大量的存储空间。

(二)邻接表

邻接表是一种链表数组,每个数组元素是一个链表,链表中存储与该顶点相连的其他顶点。

以下是使用邻接表表示无向图的 C 语言示例代码:

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

// 图的顶点结构体
typedef struct Vertex {
    int data;
    struct Vertex* next;
} Vertex;

// 创建新的顶点
Vertex* createVertex(int data) {
    Vertex* newVertex = (Vertex*)malloc(sizeof(Vertex));
    newVertex->data = data;
    newVertex->next = NULL;
    return newVertex;
}

// 向邻接表中添加边
void addEdge(Vertex* adjList[], int src, int dest) {
    Vertex* newNode = createVertex(dest);
    newNode->next = adjList[src];
    adjList[src] = newNode;

    newNode = createVertex(src);
    newNode->next = adjList[dest];
    adjList[dest] = newNode;
}

// 打印邻接表
void printAdjList(Vertex* adjList[], int V) {
    for (int i = 0; i < V; i++) {
        Vertex* temp = adjList[i];
        printf("顶点 %d: ", i);
        while (temp) {
            printf("%d -> ", temp->data);
            temp = temp->next;
        }
        printf("NULL\n");
    }
}

int main() {
    int V = 5;  // 顶点数量
    Vertex* adjList[V];

    for (int i = 0; i < V; i++) {
        adjList[i] = NULL;
    }

    addEdge(adjList, 0, 1);
    addEdge(adjList, 0, 4);
    addEdge(adjList, 1, 2);
    addEdge(adjList, 1, 3);
    addEdge(adjList, 1, 4);
    addEdge(adjList, 2, 3);
    addEdge(adjList, 3, 4);

    printf("邻接表表示的无向图:\n");
    printAdjList(adjList, V);

    return 0;
}

邻接表的优点是节省存储空间,适用于稀疏图。但查找两个顶点之间是否有边的时间复杂度相对较高。

三、图的遍历

图的遍历是指按照一定的顺序访问图中的所有顶点。常见的图遍历算法有深度优先搜索(Depth-First Search,DFS)和广度优先搜索(Breadth-First Search,BFS)。

(一)深度优先搜索(DFS)

深度优先搜索从起始顶点开始,沿着一条路径尽可能深地访问顶点,直到无法继续,然后回溯到上一个未完全探索的顶点,继续探索其他路径。

以下是使用递归方式实现深度优先搜索的 C 语言示例代码:

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

#define V 5  // 顶点数量

// 邻接矩阵
int adjMatrix[V][V] = {
    {0, 1, 0, 1, 0},
    {1, 0, 1, 0, 1},
    {0, 1, 0, 1, 0},
    {1, 0, 1, 0, 1},
    {0, 1, 0, 1, 0}
};

// 用于标记顶点是否已被访问
int visited[V] = {0};

// 深度优先搜索递归函数
void DFS(int v) {
    visited[v] = 1;
    printf("%d ", v);

    for (int i = 0; i < V; i++) {
        if (adjMatrix[v][i] == 1 && visited[i] == 0) {
            DFS(i);
        }
    }
}

int main() {
    printf("深度优先搜索的结果: ");
    DFS(0);

    return 0;
}

(二)广度优先搜索(BFS)

广度优先搜索从起始顶点开始,先访问其所有相邻顶点,然后依次访问这些相邻顶点的相邻顶点,依此类推。

以下是使用队列实现广度优先搜索的 C 语言示例代码:

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

#define V 5  // 顶点数量

// 邻接矩阵
int adjMatrix[V][V] = {
    {0, 1, 0, 1, 0},
    {1, 0, 1, 0, 1},
    {0, 1, 0, 1, 0},
    {1, 0, 1, 0, 1},
    {0, 1, 0, 1, 0}
};

// 用于标记顶点是否已被访问
int visited[V] = {0};

// 队列结构体
typedef struct Queue {
    int* items;
    int front;
    int rear;
} Queue;

// 创建队列
Queue* createQueue(int size) {
    Queue* queue = (Queue*)malloc(sizeof(Queue));
    queue->items = (int*)malloc(size * sizeof(int));
    queue->front = -1;
    queue->rear = -1;
    return queue;
}

// 判断队列是否为空
int isEmpty(Queue* queue) {
    return queue->front == -1;
}

// 判断队列是否已满
int isFull(Queue* queue, int size) {
    return (queue->rear + 1) % size == queue->front;
}

// 入队
void enqueue(Queue* queue, int item) {
    if (isFull(queue, V)) {
        printf("队列已满\n");
        return;
    }

    if (isEmpty(queue)) {
        queue->front = 0;
    }

    queue->rear = (queue->rear + 1) % V;
    queue->items[queue->rear] = item;
}

// 出队
int dequeue(Queue* queue) {
    int item;
    if (isEmpty(queue)) {
        printf("队列为空\n");
        return -1;
    }

    item = queue->items[queue->front];
    if (queue->front == queue->rear) {
        queue->front = -1;
        queue->rear = -1;
    } else {
        queue->front = (queue->front + 1) % V;
    }
    return item;
}

// 广度优先搜索函数
void BFS(int start) {
    Queue* queue = createQueue(V);

    visited[start] = 1;
    printf("%d ", start);
    enqueue(queue, start);

    while (!isEmpty(queue)) {
        int current = dequeue(queue);

        for (int i = 0; i < V; i++) {
            if (adjMatrix[current][i] == 1 && visited[i] == 0) {
                visited[i] = 1;
                printf("%d ", i);
                enqueue(queue, i);
            }
        }
    }

    free(queue->items);
    free(queue);
}

int main() {
    printf("广度优先搜索的结果: ");
    BFS(0);

    return 0;
}

四、图的应用

图在计算机科学中有广泛的应用,以下是一些常见的应用场景:

(一)网络路由

在计算机网络中,图可以用于表示网络拓扑结构,通过图算法找到最优的路由路径。

(二)社交网络分析

分析社交网络中人与人之间的关系,例如找出朋友关系中的社群结构。

(三)任务调度

在操作系统中,安排任务的执行顺序和资源分配。

(四)地图导航

地图可以被看作是一个图,通过图算法找到最短路径或最优路径。

五、总结

在 C 语言中实现图结构需要对图的基本概念有清晰的理解,选择合适的表示方法(邻接矩阵或邻接表),并掌握图的遍历算法(深度优先搜索和广度优先搜索)。根据具体的应用场景和图的特点,选择最优的实现方式和算法,以提高程序的效率和性能。


分割线

🎉相关推荐

  • 📙C 语言百万年薪修炼课程 【https://dwz.mosong.cc/cyyjc】 通俗易懂,深入浅出,匠心打磨,死磕细节,6年迭代,看过的人都说好。
  • 🍅博客首页-关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会!
  • 📙CSDN专栏-C语言修炼
  • 📙技术社区-墨松科技

分割线



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

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

相关文章

基于docker-compose部署zabbix7.0

1.安装docker和docker-compose 已有可跳过&#xff0c;没有参照我的docker一件安装脚本连接放在下方 一键安装dockerv24.0.6以及docker-compose可离线_docker 24对应docker-compose-CSDN博客 2.运行zabbix-server 1.创建zabbix工作目录 mkdir /zabbix 2.编写docker-compos…

【人工智能】Transformers之Pipeline(一):音频分类(audio-classification)

​​​​​​​ 目录 一、引言 二、音频分类&#xff08;audio-classification&#xff09; 2.1 概述 2.2 技术原理 2.2.1 Wav2vec 2.0模型 2.2.1 HuBERT模型 2.3 pipeline参数 2.3.1 pipeline对象实例化参数 2.3.2 pipeline对象使用参数 2.4 pipeline实战 2.4.1 …

【python】Python中常见的KeyError报错分析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

ESP32FreeRTOS开发笔记:1.双核并行

ESP32 的 Arduino 框架内部集成了 FreeRTOS&#xff0c;允许开发者利用其多任务处理功能。在代码中&#xff0c;xTaskCreatePinnedToCore 函数是 FreeRTOS 提供的 API&#xff0c;用于创建任务并指定任务在哪个核心上运行。 FreeRTOS 是一个流行的实时操作系统内核&#xff0c;…

信息打点web篇--语言开发框架,组件识别

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本章节主要整理 识别语言开发框的打点内容 框架简介 高效理解:把用于做某些事的代码封装起来&#xff0c;使用者无需自己写代码直接一个函数就能完成本该很多行才能完成的功能。 例子:我们要写网站&#xff0c;…

Open3D 点云Kmeans聚类算法

目录 一、概述 1.1算法介绍 1.2实现步骤 二、代码实现 三、实现效果 3.1原始点云 3.2聚类后点云 前期试读&#xff0c;后续会将博客加入该专栏&#xff0c;欢迎订阅Open3D与点云深度学习的应用_白葵新的博客-CSDN博客 一、概述 1.1算法介绍 聚类是一种将数据集分组的方…

Qml 图片和加载器操作

学习目标&#xff1a;Qml 图片和加载器编程 学习前置 Qt Qml编程 基础部分 认识qml-CSDN博客 实现效果 对图片的基本操作 加载器 核心代码 加载器 思路&#xff1a; 创建一个加载器 默认是几个圆点&#xff0c;我们重写加载器元素&#xff08;contentItem&#xff09;&…

文献阅读:高效和稳健的 π-FISH rainbow 用于多种生物分子的多重原位检测

文献介绍 文献题目&#xff1a; Highly efficient and robust π-FISH rainbow for multiplexed in situ detection of diverse biomolecules 研究团队&#xff1a; 曹罡&#xff08;华中农业大学&#xff09;、戴金霞&#xff08;华中农业大学&#xff09; 发表时间&#xff…

RSA算法(C++)

RSA加解密过程 RSA为非对称加密算法&#xff0c;由一对公钥和一对私钥构成&#xff0c;私钥加密公钥解密&#xff0c;公钥加密私钥解密 如下图,D为私密的&#xff0c;假设传输英文字母&#xff0c;我们给英文字母编号A1,B2,C3… RSA加解密过程 两对密钥产生方法如下 C Op…

网络通信基本知识

网络通信 什么是网络通信&#xff1f; 通信网络是指将各个孤立的设备进行物理连接&#xff0c;实现人与人&#xff0c;人与计算机&#xff0c;计算机与计算机之间进行信息交换的链路&#xff0c;从而达到资源共享和通信的目的。 什么是网络协议&#xff1f; 网络协议是计算机…

Python函数 之 参数

1.参数的简单介绍 参数 形式参数(形参)&#xff1a;在函数定义的时候,在括号中写⼊变量,这个变量就称为是函数的参数。实际参数(实参)&#xff1a;在函数调⽤的时候,可以给定义时候的形参传递具体的数据值,供其使⽤。注&#xff1a; 在函数调⽤的时候&#xff0c;会将函数的实…

wps 将列的内容转换为一个单元格内容,并以逗号分隔

wps 将列的内容转换为一个单元格内容&#xff0c;并以逗号分隔 1.首先在一个空白单元格输入 2.输入函数TEXTJOIN 这个函数有三个参数&#xff0c;第一个&#xff1a;以什么分隔符分隔&#xff0c;第二个&#xff1a;是否忽略空白格&#xff0c;true:忽略 false:不忽略 第三个&…

怎么使用代理IP?如何检测代理IP是否有效?

代理IP是一种网络代理技术&#xff0c;它是通过中间服务器来转发网络请求的IP地址。当我们使用代理IP时&#xff0c;我们的真实IP地址会被隐藏起来&#xff0c;而代理服务器的IP地址会被用作我们的身份标识。使用代理IP的步骤如下&#xff1a; 1.选择合适的代理服务器 考虑服务…

【微信小程序知识点】转发功能的实现

转发功能&#xff0c;主要帮助用户更流畅地与好友分享内容与服务。 想实现转发功能&#xff0c;有两种方式&#xff1a; 1.页面js文件必须声明onShareAppMessage事件监听函数&#xff0c;并自定义转发内容。只有定义了此事件处理函数&#xff0c;右上角菜单才会显示“转发”按…

WebStorm 使用 ESLint 自动格式化代码

WebStorm 不能像 VSCode 那样在保存的时候自动 Fix-ESLint&#xff0c;不能自动格式化代码&#xff0c;需要安装一个插件 安装 ESLint 插件 进入设置快捷键 win&#xff1a;CtrlAltS mac: command, 找到 Plugins&#xff0c;搜索eslint 在这里插入图片描述 安装后配置一下 …

【通信协议-RTCM】MSM语句(1) - 多信号GNSS观测数据消息格式

注释&#xff1a; RTCM响应消息1020为GLONASS星历信息&#xff0c;暂不介绍&#xff0c;前公司暂未研发RTCM消息类型版本的DR/RTK模块&#xff0c;DR/RTK模块仅NMEA消息类型使用 注释&#xff1a; 公司使用的多信号语句类型为MSM4&MSM7&#xff0c;也应该是运用最广泛的语句…

从新手到进阶:高效设计 Tableau 可视化的 5 种技巧 | 数据可视化分析

让我们一起跟着大神学习五个超实用的技巧&#xff0c;加速你的可视化分析之旅&#xff01; 在日常分析中&#xff0c;人人都想实现可视化最佳实践。然而&#xff0c;对于很多初学者来说&#xff0c;在还未熟练掌握 Tableau 的情况下&#xff0c;这种愿望貌似不太符合实际。 为…

【想心静?】红尘中修炼的功夫,才是真正的功夫

刘君亮想要去山中静坐&#xff0c;先生说&#xff1a; 你若是以厌弃身外事物的心去静中寻求天理&#xff0c;反而只会养出骄傲怠惰的习气。你若能不厌弃身外事物&#xff0c;然后再到静处涵养天理&#xff0c;却是好的。 去一个安静的地方&#xff0c;去沉静一下自己的内心也…

电子画册制作流程技巧大揭秘

​随着科技的发展&#xff0c;电子画册已经逐渐取代传统纸质画册&#xff0c;成为展示企业形象、传播信息的重要工具。一份精美的电子画册&#xff0c;不仅能提升企业品牌形象&#xff0c;还能吸引更多潜在客户。那么&#xff0c;如何制作一份既精美又实用的电子画册呢&#xf…

YOLOv8损失函数改进-增加MPDIoU提升边界框回归精度【附代码】

文章目录 前言文章概述必要环境一、修改方法1.修改配置文件2. 增加 MPDIoU3. 修改 BboxLoss类4. 修改 v8DetectionLoss 类的 init 方法 二、训练代码三、训练过程总结 前言 本篇博客我们将详细介绍如何在 YOLOv8项目中增加 MPDIoULoss&#xff0c;包括如何修改配置文件、增加新…