前言
烂尾了
图 (Graph) 是由若干给定的顶点及连接两顶点的边所构成的图形,
这种图形通常用来描述某些事物之间的某种特定关系。
顶点用于代表事物,连接两顶点的边则用于表示两个事物间具有这种关系。
因为本人已经有离散数学的基础,过于数学的东西这里就不多赘述了
参考:
https://oi-wiki.org/graph/concept/
https://book.itheima.net/course/223/1276707762369208322/1276709341503692801
定义
图是一个二元组Graph=(V,E)
,
V是非空集,称为点集(vertex set),对于V中的每个元素,称为顶点(vertex)或节点(node)
E是V中各节点之间边(edge)/ 弧(arc)的集合,称为边集(edge set)
注:这里讨论的都是有限图,即V,E都是有限集合
无向图
E中的每个元素为一个无序二元组(u,v)
,称作无向边,简称为边,其中u,v∈V。设e=(u,v)
,则u和v称为e的端点
例:
G=(V,E),V={A, B, C, D, E, F};
E={(A,B), (A,E),(B,E),(C,D), (D,F),(B,F), (C,F)}
对于n个顶点,e条边的无向图G:
- 所有顶点的度之和=2e
- 若G是连通图,则最少有 n-1 条边(树);若e > n-1,则一定有回路
- 若G是非连通图,则最多可能有C²n-1条边
- 无向完全图共有C²n条边
有向图
E中的每个元素为一个有序二元组(u,v)
,也写作u→v
,称为有向边或弧。设e=u→v
,则u为e的起点(tail),v为e的终点(head)(尾指向头),两者也可称为端点。u是v的直接前驱,v是u的直接后继
例:
G=(V, E),V={A, B, C, D, E};
E={<A,B>,<A,E>,<B,C>,<C,D>,<D,B>,<D,A>,<E,C>}
对于n个顶点,e条弧的有向图G:
所有顶点的出度之和=入度之和=e
所有顶点的度之和=2e
若G是强连通图,则最少有 n 条边 (形成回路)
有向完全图共有2C²n条边
完全图
假设图中有n个顶点,e条边或弧
完全图:含有e=n(n-1)/2
条边的无向图
有向完全图:含有e=n(n-1)
条弧的有向图
稀疏图:有很少边或弧的图
稠密图:有较多边或弧的图
网:边/弧带权的图
度数
与一个顶点v关联的边的条数称作该顶点的度(degree),记为TD(V)
假设图中有n个顶点,e条边或弧,则:
在有向图中,顶点的度等于该顶点的入度与出度之和,所有的顶点的度之和为2e;具有n个顶点的有向图最多有n(n-1)条边
在无向图中,所有顶点的度之和为2e
注:当有向图中仅1个顶点的入度为0,其余顶点的入度均为1,此时是一颗有向树
连通图
在无向图G=(V,E)中,若其中任意两个顶点均连通,则称G是连通图
在有向图G=(V,E)中,节点两两互相可达,则称G是强连通图
连通分量:无向图G的极大连通子图
强连通分量:有向图G的极大强连通子图
生成树
包含无向图G所有顶点的极小连通子图
- 极小连通子图:该子图是G的连通子图,在该子图中删除任何一条边,子图不再连通
存储
顺序存储结构——数组表示法(邻接矩阵)
建立一个顶点表(记录各个顶点信息)和一个邻接矩阵(表示各个顶点之间关系)
即使用一个二维数组 adj[u][v]
来存边,
其中adj[u][v]
如果为1:表示存在u到v的边,如果为0:表示不存在u到v的边
那么根据这个定义创建一个图
#define MAX_VERTEX_NUM 100
typedef struct
{
int v; // 顶点数目
int e; // 边的数目
// 存储顶点
int vexs[MAX_VERTEX_NUM];
// 存储边
int edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
}Graph;
对称矩阵—>同一条边表示了两次
如果是带边权的图,可以在 adj[u][v]
中存储u到v的边的边权
n个顶点的连通图用邻接矩阵表示时,至少有2(n-1)个非零元素
链式存储结构——邻接表
对每个顶点vi建立一个单链表,把与vi有关联的边的信息链接起来,每个结点设为3个域;
每个单链表有一个头结点(设为2个域),存vi信息;每个单链表的头结点另外用顺序存储结构存储。
无向图例:
注:邻接表不唯一,因各个边结点的链入顺序是任意的
有向图例:
十字链表
遍历
Tips:BFS生成树的树高比DFS生成树的树高小或相等
DFS(深度优先搜索)
每次都尝试向更深的节点走
基本思想:仿树的先序遍历过程
特征:递归调用自身
稠密图适于在邻接矩阵上进行深度遍历;稀疏图适于在邻接表上进行深度遍历
实现——栈
使用栈作为遍历中节点的暂存容器
BFS(广度优先搜索)
基本思想:仿树的层次遍历过程
实现——队列
最小生成树
在网的多个生成树中,寻找一个各边权值之和最小的生成树
准则:
- 必须只使用该网中的边来构造最小生成树
- 必须使用且仅使用n-1条边来联结网中的n个顶点
- 不能使用产生回路的边
Prim算法
归并顶点,与边数无关,适于稠密网
从一个结点开始,不断加点
Kruskal算法
归并边,适于稀疏网
从小到大加入边,是个贪心算法
最短路径问题
Dijkstra算法
单源最短路径
Floyd算法
每一对顶点间的最短路径
拓扑排序
给一个有向无环图的所有节点排序,拓扑排序的图 <=> 有向无环图
AOV网
用顶点表示活动的网络
算法思想:
输入AOV网络,令 n 为顶点个数
在AOV网络中选一个没有直接前驱的顶点, 并输出
从图中删去该顶点, 同时删去所有它发出的有向边
重复以上 2、3 步, 直到:
全部顶点均已输出,拓扑有序序列形成,拓扑排序完成
或
图中还有未输出的顶点,但已跳出处理循环。这说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了。这时AOV网络中必定存在有向环。
关键路径——AOE网
用边表示活动的网络