
图(一):基本概念、图的存储结构
发布日期:2021-05-07 06:30:32
浏览次数:23
分类:精选文章
本文共 6294 字,大约阅读时间需要 20 分钟。
作为数据结构的课程笔记,以便查阅。如有出错的地方,还请多多指正!
目录
基本概念
- 图 (Graph): G = { V , E } G=\{V,E\} G={ V,E}, V ( G ) V(G) V(G) 为顶点 (Vertex) 的非空有限集, E ( G ) E(G) E(G) 为边 ( v , w ) (v,w) (v,w) / 弧 < v , w > <v,w> <v,w> 的有限集合
- 有向图 (Digraph)、无向图 (Undigraph)
- 有向完全图—— n n n 个顶点的有向图最大边数是 n ( n − 1 ) n(n-1) n(n−1)
- 无向完全图—— n n n 个顶点的无向图最大边数是 n ( n − 1 ) / 2 n(n-1)/2 n(n−1)/2
- 权——与图的边或弧相关的数
- 网——带权的图
- 子图——图 G ( V , V R ) G(V,VR) G(V,VR) 和图 G ′ ( V ′ , V R ′ ) G'(V',VR') G′(V′,VR′), 满足: V ′ ⊆ V V'\subseteq V V′⊆V 并且 V R ′ ⊆ V R VR'\subseteq VR VR′⊆VR
- 邻接点
- 顶点的度
- 无向图中,顶点的度为与每个顶点相连的边数
- 有向图中,顶点的度分成入度与出度;入度:以该顶点为头的弧的数目;出度:以该顶点为尾的弧的数目
- 路径——路径是顶点的序列 V = { V i 0 , V i 1 , … … V i n } V=\{V_{i_0},V_{i_1},……V_{i_n}\} V={ Vi0,Vi1,……Vin}
- 路径长度——沿路径边的数目或沿路径各边权值之和
- 回路——第一个顶点和最后一个顶点相同的路径
- 简单路径——序列中顶点不重复出现的路径
- 简单回路——除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路
- 连通——从顶点 V V V 到顶点 W W W 有一条路径,则说 V V V 和 W W W 是连通的
- 连通图——图中任意两个顶点都是连通的图
- 连通分量——无向图的极大连通子图
- 强连通图——有向图中,每一对 V i , V j ∈ V V_i,V_j\in V Vi,Vj∈V, V i ≠ V j V_i\neq V_j Vi=Vj, 从 V i V_i Vi 到 V j V_j Vj 和从 V j V_j Vj 到 V i V_i Vi 都存在路径
- 强连通分量
图的存储
邻接矩阵
- 适合于稠密图
- 无权图: AdjMatrix[i][j] = { 1 ( v i , v j ) 或 < v i , v j > ∈ E 0 e l s e \textrm{AdjMatrix[i][j]}=\left\{ \begin{aligned} 1\ \ \ \ \ \ &(v_i,v_j)\ 或\ <v_i,v_j>\in E\\ 0 \ \ \ \ \ \ &else \end{aligned} \right. AdjMatrix[i][j]={ 1 0 (vi,vj) 或 <vi,vj>∈Eelse
- 有权图: AdjMatrix[i][j] = { w i j ( v i , v j ) 或 < v i , v j > ∈ E ∞ e l s e \textrm{AdjMatrix[i][j]}=\left\{ \begin{aligned} w_{ij}\ \ \ \ \ \ &(v_i,v_j)\ 或\ <v_i,v_j>\in E\\ \infty \ \ \ \ \ \ &else \end{aligned} \right. AdjMatrix[i][j]={ wij ∞ (vi,vj) 或 <vi,vj>∈Eelse
无向图的邻接矩阵对称,可压缩存储 (对称矩阵可以只存上/下三角元素)
#define MAX_VERTEX_NUM 50#define INFINITY 10000typedef enum { unDirectedGraph, directedGraph,}GraphType_e;typedef int AdjacentMatrixWeightType_t;typedef int AdjacentMatrixDataType_t;typedef struct { int vexNum; int arcNum; GraphType_e type; AdjacentMatrixDataType_t vex[MAX_VERTEX_NUM]; AdjacentMatrixWeightType_t arc[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//邻接矩阵}AdjacentMatrix_t, *pAdjacentMatrix_t;//typedef struct { int head; int tail; AdjacentMatrixWeightType_t weight;}Edge_t, *pEdge_t;
Status_e Create_graph(pAdjacentMatrix_t pgraph, int vex_num, GraphType_e type){ pgraph->vexNum = vex_num; pgraph->arcNum = 0; pgraph->type = type; for (int i = 0; i < pgraph->vexNum; ++i) { for (int j = 0; j < pgraph->vexNum; ++j) { pgraph->arc[i][j] = (i == j) ? 0 : INFINITY; } } return ok;}Status_e Insert_edge(pAdjacentMatrix_t pgraph, pEdge_t edge){ (pgraph->arcNum)++; pgraph->arc[edge->tail][edge->head] = edge->weight; if (pgraph->type == unDirectedGraph) { pgraph->arc[edge->head][edge->tail] = edge->weight; } return ok;}int Locate_vex(pAdjacentMatrix_t pgraph, AdjacentMatrixDataType_t data){ for (int i = 0; i < pgraph->vexNum; ++i) { if (pgraph->vex[i] == data) { return i; } } return -1;}/*Input format:Nv Nedata1data2...tail head weight...*/Status_e Build_graph(pAdjacentMatrix_t pgraph, GraphType_e type){ int vex_num; int arc_num; Edge_t edge; scanf_s("%d %d", &vex_num, &arc_num); Create_graph(pgraph, vex_num, type); for (int i = 0; i < vex_num; ++i) { scanf_s("%d", &(pgraph->vex[i])); } for (int i = 0; i < arc_num; ++i) { AdjacentMatrixDataType_t data_tail, data_head; scanf_s("%d %d %d", &(data_tail), &(data_head), &(edge.weight)); //scanf_s("%d %d %d", &(edge.tail), &(edge.head), &(edge.weight)); edge.tail = Locate_vex(pgraph, data_tail); edge.head = Locate_vex(pgraph, data_head); if (-1 == edge.tail || -1 == edge.head) { return err; } Insert_edge(pgraph, &edge); } return ok;}
邻接表
- 适用于稀疏图
- 找邻接点容易,找逆邻接点难;求出度容易,求入度难
#define MAX_VERTEX_NUM 50#define INFINITY 10000typedef enum { unDirectedGraph, directedGraph,}GraphType_e;typedef int AdjacentListWeightType_t;typedef int AdjacentListDataType_t;typedef struct { AdjacentListDataType_t data; pArcNode_t firstEdge;}VexNode_t, *pVexNode_t;typedef struct ArcNode{ //弧结点 struct ArcNode* nextEdge; int head;//邻接点下标 AdjacentListWeightType_t weight;}ArcNode_t, *pArcNode_t;typedef struct { VexNode_t vex[MAX_VERTEX_NUM]; int vexNum; int arcNum; GraphType_e type;}AdjacentList_t, *pAdjacentList_t;//typedef struct { int head; int tail; AdjacentListWeightType_t weight;}Edge_t, * pEdge_t;
Status_e Create_graph(pAdjacentList_t pgraph, int vex_num, GraphType_e type){ pgraph->vexNum = vex_num; pgraph->arcNum = 0; pgraph->type = type; for (int i = 0; i < vex_num; ++i) { pgraph->vex[i].firstEdge = NULL;//要先初始化为NULL } return ok;}Status_e Insert_edge(pAdjacentList_t pgraph, pEdge_t edge){ pArcNode_t parc_node = (pArcNode_t)malloc(sizeof(ArcNode_t)); parc_node->nextEdge = pgraph->vex[edge->tail].firstEdge; pgraph->vex[edge->tail].firstEdge = parc_node; parc_node->weight = edge->weight; parc_node->head = edge->head; (pgraph->arcNum)++; if (pgraph->type == unDirectedGraph) { parc_node = (pArcNode_t)malloc(sizeof(ArcNode_t)); parc_node->nextEdge = pgraph->vex[edge->head].firstEdge; pgraph->vex[edge->head].firstEdge = parc_node; parc_node->weight = edge->weight; parc_node->head = edge->tail; } return ok;}int Locate_vex(pAdjacentList_t pgraph, AdjacentListDataType_t data){ for (int i = 0; i < pgraph->vexNum; ++i) { if (pgraph->vex[i].data == data) { return i; } } return -1;}/*Input format:Nv Nedata1data2...tail head weight...*/Status_e Build_graph(pAdjacentList_t pgraph, GraphType_e type){ int vex_num, arc_num; Edge_t edge; scanf_s("%d %d", &vex_num, &arc_num); Create_graph(pgraph, vex_num, type); for (int i = 0; i < vex_num; ++i) { scanf_s("%d", &(pgraph->vex[i].data)); } for (int i = 0; i < arc_num; ++i) { AdjacentListDataType_t data_tail, data_head; scanf_s("%d %d %d", &(data_tail), &(data_head), &(edge.weight)); //scanf_s("%d %d %d", &(edge.tail), &(edge.head), &(edge.weight)); edge.tail = Locate_vex(pgraph, data_tail); edge.head = Locate_vex(pgraph, data_head); if (-1 == edge.tail || -1 == edge.head) { return err; } Insert_edge(pgraph, &edge); } return ok;}
逆邻接表
- 找邻接点难,找逆邻接点容易
- 求出度难,求入度容易
十字链表
- 结合了邻接表和逆邻接表
- 顶点结点:
firstIn
表示指向以该顶点为弧头的第一个弧节点。而firstOut
则表示指向以该顶点为弧尾的第一个弧节点 - 弧结点
tailVex
表示弧尾,headVex
表示弧头。hLink
指向弧头相同的下一条弧,tLink
指向弧尾相同的下一条弧弧头相同的弧都在同一链表上,弧尾相同的弧也都在同一链表上
T ( n ) T(n) T(n)
- 在涉及全图的问题中, O ( n + e ) O(n+e) O(n+e) 为最优;如果是稠密图, O ( n 2 ) O(n^2) O(n2) 也为最优
发表评论
最新留言
初次前来,多多关照!
[***.217.46.12]2025年04月03日 13时01分34秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Jupyter Notebook 暗色自定义主题
2021-05-09
[Python学习笔记]组织文件
2021-05-09
基于Redo Log和Undo Log的MySQL崩溃恢复流程
2021-05-09
从RocketMQ的Broker源码层面验证一下这两个点
2021-05-09
如何正确的在项目中接入微信JS-SDK
2021-05-09
纵览全局的框框——智慧搜索
2021-05-09
快服务流量之争:如何在快服务中占领一席之地
2021-05-09
【活动】直播揭秘<如何从0开发HarmonyOS硬件>
2021-05-09
Unity平台 | 快速集成华为性能管理服务
2021-05-09
详细实例教程!集成华为虚假用户检测,防范虚假恶意流量
2021-05-09
对模拟器虚假设备识别能力提升15%!每日清理大师App集成系统完整性检测
2021-05-09
使用Power BI构建数据仓库与BI方案
2021-05-09
pytest封神之路第二步 132个命令行参数用法
2021-05-09
Django认证系统并不鸡肋反而很重要
2021-05-09
快用Django REST framework写写API吧
2021-05-09
tep用户手册帮你从unittest过渡到pytest
2021-05-09
12张图打开JMeter体系结构全局视角
2021-05-09
Spring Boot 2.x基础教程:构建RESTful API与单元测试
2021-05-09
[UWP 自定义控件]了解模板化控件(1):基础知识
2021-05-09
UWP 自定义控件:了解模板化控件 系列文章
2021-05-09