当前位置: 首页 > news >正文

【数据结构】图之邻接矩阵代码实现与dfs、bfs

一、图的相关概念

图的相关概念包括顶点、边、有向图和无向图等。图是计算机科学中一个核心的数据结构,用于描述对象之间的关系。它由顶点(节点)的集合和连接这些顶点的边的集合组成。具体分析如下:

  1. 顶点:图中的基本构成单位,也称为节点或顶点
  2. :连接两个顶点的线段,可以是有向的或无向的,代表两个顶点之间的关系
  3. 有向图:边具有方向性,即从一个顶点指向另一个顶点,表示关系的非对称性
  4. 无向图:边没有方向,表示两个顶点之间的相互关系
  5. 完全图:每对不同顶点之间都恰好有一条边相连的图,分为有向完全图和无向完全图
  6. 邻接顶点:在无向图中,如果存在一条边直接连接两个顶点,则这两个顶点互为邻接顶点;在有向图中,如果存在一条边从顶点A指向顶点B,则称顶点B邻接自顶点A
  7. 顶点的度:与某个顶点相关联的边的总数,对于有向图来说,顶点的度等于其入度和出度之和
  8. 路径:一系列的顶点和边交替出现形成的序列,表示从一个顶点到另一个顶点的路线
  9. 简单路径与回路:路径上不重复访问同一个顶点的路径称为简单路径;如果起点和终点相同的路径称为回路
  10. 子图:如果一个图的顶点集和边集都是另一个图的子集,那么这个图就是另一个图的子图

除了上述基本概念外,图还有一些存储结构,如邻接矩阵和邻接表,以及遍历算法,如深度优先搜索(DFS)和广度优先搜索(BFS)。此外,图论中的一些经典问题包括最短路径问题、最小生成树问题、网络流问题等,它们都有对应的算法来解决。

综上所述,图是一种强大的数据结构,能够有效地模拟和解决现实世界中的许多问题,如社交网络分析、推荐系统、交通规划等。通过学习和掌握图的相关概念和算法,可以在多个领域内应用图的理论来优化问题解决方案。、

图的存储结构主要有邻接矩阵、邻接表、十字链表和邻接多重表。这些存储方法各有特点,适应不同类型的图和不同的操作需求。下面将具体介绍这几种存储结构:

  1. 邻接矩阵
    • 无向图的邻接矩阵:在这种表示法中,矩阵是对称的,即arcs[i][j]等于arcs[j][i],因为无向图中边没有方向
    • 有向图的邻接矩阵:在有向图的情况下,矩阵不对称,arcs[i][j]表示从顶点i到顶点j的边。
    • 网(有权图)的邻接矩阵:如果图中的边有权值,则邻接矩阵中的元素表示相应顶点之间边的权值
    • 邻接矩阵的存储表示:通常使用二维数组来实现,其中行和列代表图中的顶点,交叉点的值表示这两个顶点之间是否有边或权的值
  1. 邻接表
    • 无向图的邻接表表示:每个顶点对应一个链表,链表中包含与该顶点相邻的所有顶点。
    • 有向图的邻接表表示:在有向图中,邻接表显示为从每个顶点出发可以到达的顶点列表
    • 图的邻接表的存储定义:需要为每个顶点定义一个链表头节点,然后通过链表实现各顶点之间的连接关系
  1. 十字链表
    • 弧结点的结构:每个弧有一个结构来表示,其中包括弧的信息以及弧尾和弧头的位置信息。
    • 顶点结点的结构:每个顶点也有一个结构来表示,包括顶点信息及与该顶点相关联的弧的指针。
  1. 邻接多重表
    • 边结点的结构:在邻接多重表中,每条边使用一个结点表示[1]。
    • 图的结构定义:图的结点不仅包含顶点信息,还包括一个指向所有依附于该顶点的边的列表的头指针

针对上述分析,提出以下补充内容:

  • 邻接矩阵适合稠密图,可以快速判断两个顶点间是否有边。
  • 邻接表适合稀疏图,只存储存在的边,节省空间
  • 十字链表和邻接多重表提供了更加灵活的图表示方式
  • 对于带权图,存储结构需要扩展以保存权值信息

综上所述,图的存储结构根据图的类型和实际应用场景的不同而有所选择。在实际应用中,选择合适的存储结构对于提高算法效率和节约存储空间至关重要。

二、邻接矩阵

邻接矩阵是图的一种存储方式,适用于稠密图和小规模的图,它直接在矩阵中存储顶点间的邻接关系。具体分析如下:

  1. 存储方式
    • 创建一个二维数组(矩阵),其大小为顶点数乘以顶点数
    • 矩阵的行和列分别代表图中的所有顶点,相交的单元格表示两个顶点之间是否有边
  1. 无向图邻接矩阵
    • 邻接矩阵是对称的,如果顶点i与顶点j相连,则arcs[i][j]arcs[j][i]相等且均不为
  1. 有向图邻接矩阵
    • 邻接矩阵不对称,如果从顶点i到顶点j有一条边,那么arcs[i][j]等于1(或边的权值),而arcs[j][i]可能为0
  1. 网(有权图)的邻接矩阵
    • 邻接矩阵中的每个元素值代表对应顶点间边的权值,如果没有边则为无穷大或其他特殊值
  1. 空间复杂度
    • 空间复杂度为V^2,其中V是顶点的数量
  1. 时间复杂度
    • 判断任意两点是否相邻的时间复杂度为O(1),因为直接索引矩阵即可
  1. 优缺点
    • 优点包括容易实现,能快速判断顶点间是否存在边,易于编程
    • 缺点是占用空间大,尤其是对于稀疏图,会浪费很多存储空间
#include<iostream>
#include<algorithm>
using namespace std;const int N = 5;
const int MAX_VALUE = INT_MAX;typedef char ElemType;
typedef struct GraphMatrix {ElemType arrayV[N];  // 顶点数组int matrix[N][N];    // 邻接矩阵bool isDirect;       // 是否是有向图int size;            // 顶点个数
} GraphMatrix,* Graph;/*** 初始化* @param V 要构建的图的顶点数组* @param isDirect 是否为有向图* @param size 顶点个数* @return 这个图的地址*/
Graph initGraphMatrix(ElemType* V, bool isDirect, int size) {// 1. 创建图auto graph = (Graph) malloc(sizeof(GraphMatrix));// 2. 初始化字段graph->isDirect = isDirect;graph->size = size;for (int i = 0; i < size; i++) {graph->arrayV[i] = V[i];}// 3. 初始化邻接矩阵for (int i = 0; i < size; i++) {for (int j = 0; j < size; j++) {graph->matrix[i][j] = MAX_VALUE;}}// 4. 返回地址return graph;
}/*** 获取这个顶点的下标* @param graph* @param src*/
int getIndexOfV(Graph& graph, ElemType src) {// 1. 循环遍历,可以使用map进行优化for (int i = 0; i < graph->size; i++) {if (graph->arrayV[i] == src) {return i;}}return -1;
}/*** 添加一条变* @param graph 操作的图* @param src  起点* @param dest 终点* @param weight 权重*/
void addEdge(Graph& graph, ElemType src, ElemType dest, int weight) {// 1. 合法检验if (graph == nullptr) return;// 2. 查询两个顶点对应的邻接矩阵下标int srcIndex = getIndexOfV(graph, src);int destIndex = getIndexOfV(graph, dest);// 3. 判断下标合法if (srcIndex < 0 || destIndex < 0 || srcIndex > graph->size || destIndex > graph->size) return;// 4. 添加一条边graph->matrix[srcIndex][destIndex] = weight;// 5. 如果这是无向图则添加dest到srcif (!graph->isDirect) graph->matrix[destIndex][srcIndex] = weight;
}/*** 获取边的度* @param graph 图* @param V 边* @return*/
int getDevOfV(Graph& graph, ElemType V) {// 1. 合法判断if (graph == nullptr) return -1;// 2. 获取下标int index = getIndexOfV(graph, V);if (index < 0 || index > graph->size) return -1;// 2. 遍历邻接矩阵int cnt = 0;for (int i = 0; i < graph->size; i++) {if (graph->matrix[index][i] != MAX_VALUE) cnt++;if (!graph->isDirect && graph->matrix[i][index]) cnt++;}// 3. 返回度return cnt;
}/*** 打印矩阵* @param graph 图*/
void printGraph(Graph& graph) {for (int i = 0; i < graph->size; i++) {for (int j = 0; j < graph->size; j++) {if (graph->matrix[i][j] == MAX_VALUE) cout << "-" << "   ";else cout << graph->matrix[i][j] << "   ";}cout << "\n";}cout << "----------------------\n";
}/*** bfs* @param graph*/
void bfs(Graph& graph, ElemType src) {// 1. 合法校验if (graph == nullptr) return;// 2. 创建队列与visited数组bool visited[graph->size];int queue[graph->size << 1];int front = 0, rear = 0;// 3. 入队顶点int index = getIndexOfV(graph,src);if (index < 0 || index > graph->size) return;queue[rear++] = index;// 4. 开始bfswhile (front < rear) {int top = queue[front++];cout << graph->arrayV[top] << "->";for (int i = 0; i < graph->size; i++) {if (graph->matrix[top][i] != MAX_VALUE && !visited[i]) {queue[rear++] = i;visited[top] = true;}}}cout << "\n----------------------\n";
}/*** dfs* @param graph* @param src* @param visited*/
void dfsFun(Graph& graph, int src, bool* visited) {cout << graph->arrayV[src] << "->";visited[src] = true;for (int i = 0; i < graph->size; i++) {if (!visited[i] && graph->matrix[src][i] != MAX_VALUE) {dfsFun(graph, i, visited);}}
}/*** dfs* @param graph* @param src*/
void dfs(Graph& graph, ElemType src) {// 1. 合法校验if (graph == nullptr) return;// 2. dfs准备bool visited[graph->size];int index = getIndexOfV(graph, src);if (index < 0 || index > graph->size) return;// 3. dfsdfsFun(graph, index, visited);cout << "\n----------------------\n";
}/*** 克鲁斯卡尔算法  最小生成树* @param graph 图* @param ans graph的最小生成树* @return 最小生成树的权值和*/
int kruskal(Graph& graph, Graph& ans) {return -1;
}/*** Prim算法* @param graph 图* @param ans 最小生成树* @return 最小生成树的权值之和*/
int prim(Graph& graph, Graph& ans) {return -1;
}/*** 迪杰斯特拉算法* @param graph 图* @param src 起始顶点* @param dist 距离数组--最短路* @param path 路径数组--最短路*/
void dijkstra(Graph& graph, ElemType src, int* dist, int* path) {}/*** 贝尔曼算法* @param graph 图* @param src 起始顶点* @param dist 距离数组--最短路* @param path 路径数组--最短路* @return*/
bool bellmanFord(Graph& graph, ElemType src, int* dist, int *path) {return 0;
}/*** floyd算法* @param graph 图* @param dist 距离数组--多源最短路* @param path 距离数组--多源最短路*/
void floydWarShall(Graph& graph, int** dist, int** path) {}int main() {auto* V = (ElemType*) malloc(sizeof(ElemType) * 4);V[0] = 'A', V[1] = 'B', V[2] = 'C', V[3] = 'D';Graph graph = initGraphMatrix(V, true, 4);//    printGraph(graph);////    addEdge(graph, 'A', 'B', 1);//    addEdge(graph, 'A', 'C', 2);////    printGraph(graph);addEdge(graph, 'A', 'B', 1);addEdge(graph, 'B', 'D', 1);addEdge(graph, 'D', 'A', 1);printGraph(graph);bfs(graph, 'A');dfs(graph, 'A');return 0;
}

相关文章:

  • c语言:自定义类型(枚举、联合体)
  • 网络流媒体协议——HLS协议
  • MySQL实体类框架
  • OpenGauss数据库-7.用户及角色
  • Vue3【十五】标签的Ref属性
  • select模块
  • 微信小程序学习笔记(1)
  • linux编辑器-vim
  • vue解决跨域问题
  • Spark RDD算子
  • 代码随想录算法训练营第三十一天| 455.分发饼干,376. 摆动序列 ,53. 最大子序和
  • 10进制与二、八、十六进制的转换
  • Day25 首页待办事项及备忘录添加功能
  • MFC 使用sapi文字转换为语音
  • 跨域、JSONP、CORS、Spring、Spring Security解决方案
  • [LeetCode] Wiggle Sort
  • AHK 中 = 和 == 等比较运算符的用法
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • node-glob通配符
  • Otto开发初探——微服务依赖管理新利器
  • TiDB 源码阅读系列文章(十)Chunk 和执行框架简介
  • unity如何实现一个固定宽度的orthagraphic相机
  • Vue 2.3、2.4 知识点小结
  • vue脚手架vue-cli
  • 技术发展面试
  • 聚类分析——Kmeans
  • 强力优化Rancher k8s中国区的使用体验
  • 人脸识别最新开发经验demo
  • 如何用vue打造一个移动端音乐播放器
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 使用API自动生成工具优化前端工作流
  • 算法系列——算法入门之递归分而治之思想的实现
  • Hibernate主键生成策略及选择
  • postgresql行列转换函数
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (二)fiber的基本认识
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (生成器)yield与(迭代器)generator
  • (四)opengl函数加载和错误处理
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (转)详解PHP处理密码的几种方式
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .NET Micro Framework初体验
  • .NET 的静态构造函数是否线程安全?答案是肯定的!
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • [2]十道算法题【Java实现】
  • [4.9福建四校联考]
  • [Android学习笔记]ScrollView的使用
  • [C#][opencvsharp]opencvsharp sift和surf特征点匹配
  • [C#小技巧]如何捕捉上升沿和下降沿
  • [CareerCup] 17.8 Contiguous Sequence with Largest Sum 连续子序列之和最大
  • [Cloud Networking] Layer3 (Continue)