1.图的定义和术语
2.图的抽象数据类型(基本操作)和存储结构
2.1邻接矩阵
一维数组+二维数组
#define GRAPH_INFINITY 65535 /* 用65535来代表∞ */
typedef struct MGraph
{
VertexType vexs[MAXVEX];//顶点表
EdgeType arc[MAXVEX][MAXVEX];//边表
int numNodes, numEdges;//图中当前顶点和边的数量
}MGraph;
对于一个图,邻接矩阵唯一。
无向图的邻接矩阵(边表)为对称矩阵。
适合稠密图。确定图中边的总数花费的时间代价大。
邻接矩阵为A,则A^n的某个元素表示从i-j的长度为n的路径的数目。
2.2邻接表
一维数组+单链表,一个边由一个顶点结点+一个边表结点表示
邻接表关注出度,创建时使用头插法插入边表结点。.
可以创建逆邻接表关注入度,两者结合即为十字链表。
//边结点
typedef struct EdgeNode
{
int adjvex;//邻接点在顶点表中的下标
EdgeType info;//权值
struct EdgeNode* next;
}EdgeNode;
//顶点结点
typedef struct VertexNode
{
VertexType data;//顶点数据
EdgeNode* FirstEdge;//边表头指针
}VertexNode,AdjList[MAXVEX];
typedef struct
{
AdjList adjlist;//顶点表
int numNodes, numEdges;//当前顶点数和边数
}GraphAdjList;
对于一个图,邻接表不唯一。
适合稀疏图。判断两顶点是否存在边需要遍历其中一个边表,效率较低。容易寻找到某一顶点的全部边。每个顶点的单链表的边表节点次序任意。
2.3十字链表
是有向图的一种链式存储结构,是对有向图的邻接表的优化。
容易求得各个顶点点的入度出度。
整合了邻接表和逆邻接表,都由一个边表节点表示一条有向边。
顶点结点是顺序存储的。
2.4邻接多重表
对无向图的邻接表的优化。
无向图的邻接表删除一条边需要遍历两个顶点的边表。
与无向图的邻接表的区别在于邻接多重表使用一个结点表示一条边,而无向图的邻接表用两个结点。
2.5边集数组
两个一维数组。适合对边依次进行处理的操作。
3.图的遍历
基于邻接矩阵,DFS和BFS的序列(深度优先的生成树or生成森林和广度优先生成树)唯一,基于邻接表则不唯一。
v表示顶点数,e表示边数
3.1DFS
类似于树的先序遍历。
对有向无环图(DAG网)进行深度优先遍历,在退出递归的过程输出顶点信息,每一步均是先输出当前无后继的顶点,因此得到逆拓扑有序序列。王道P212
需要借助递归工作栈,空间复杂度为o(v)
邻接矩阵时间复杂度o(v^2)
邻接表时间复杂度o(v+e)
3.2BFS
过程与二叉树的层序遍历一致。
更适合用于求解一些问题的最优解。
和Dijkstra单源最短路径算法和Prim最小生成树算法思想类似。
需要借助辅助队列,存储正在访问的顶点的下一层顶点。
可用于求解非带权图的单源最短路径问题。
空间复杂度最坏为o(v)
邻接矩阵时间复杂度o(v^2)
邻接表时间复杂度o(v+e)
3.3图的遍历和图的连通性
若无向图为连通图,则仅需一次遍历。
若有向图的初始点到所有顶点都有路径,则仅需一次遍历。
4.图的基本应用
4.1最小生成树
Prim算法,从起始点出发,更新到其余点的权值,找到最小权值顶点加入生成树,循环更新找到。
基于邻接矩阵的时间复杂度o(v^2),邻接表一样
Kruskal算法,边的权值由小到大排列,逐个判断是否形成环,不形成则加入生成树中。
通过邻接矩阵或邻接表已存储的图,生成边集数组并排序后,其余的时间复杂度o(e*log2|e)
当带权连通图的任意一个环中所包含的边的权值均不相同时,其MST(最小生成树)是唯一的。
4.2最短路径
Dijkstra算法求单源最短路径问题,类似Prim算法,时间复杂度o(v^2),不适用于负权值的情况。一定是简单路径,因为如果一个最短路径中还有回路,那么去掉回路,还能更短。
这里的路径数组是0-8,0-7,0-6,告诉你从0到8要先到哪里。
Floyd算法求各顶点之间最短路径问题。基于邻接矩阵的时间复杂度o(v^3),基于邻接表...
允许负权值,不许有包含负权值的边组成的回路。。。
A^k(i,j)表示从i到j中间顶点序号不大于k的最短路径的长度,最外层循环n次,从初始都没有中间顶点,即A^-1迭代到A^n-1,中间顶点序号最大为n-1(序号从0开始计算)。
这里的路径数组类似于,0-8,1-8,2-8。告诉你从0到8下一步怎么走。
4.3DAG图描述表达式
即有向无环图,描述有公共子式的表达式,节省存储空间。
4.4拓扑排序
拓扑来源于TOP。是由有向无环图的顶点组成的序列。解决工程能否顺序进行的问题。
邻接矩阵为三角矩阵一定存在拓扑序列,反之不一定。
通常对AOV网进行拓扑排序,顶点表示活动,有向边表示活动的优先关系。
利用DFS也可以实现。
易错点:
实现中,栈和队列都可以用来存储度为0的顶点,度为0的顶点顺序任意。拓扑序列唯一,每个顶点入度出度不最多为1。
拓扑序列个数。拓扑序列唯一,可能有多种图。
基于邻接表的时间复杂度o(v+e)
基于邻接矩阵的时间复杂度o(v^2)
4.5关键路径
解决工程完成需要时间最短问题。
AOE网,顶点表示事件,有向边表示活动,权值表示活动所消耗的资源。仅有一个源点和汇点。
int* etv, * ltv; /* 事件最早发生时间和最迟发生时间数组 描述顶点(事件) ete&<e描述边(活动)*/
//etv,寻找从源点到某一顶点的最长路径,从源点出发所有路径中最晚的时间(关键路径)
//ltv,根据源点到汇点的关键路径长度,逆向推出,从汇点逆推所有路径最早的时间
//ete,根据前一个顶点的etv求得
//lte,根据后一个顶点的ltv-e活动本身所需时间求得
大致思路,
拓扑排序求得拓扑序列栈+etv
根据拓扑序列站求得ltv
求活动的ete、lte,相等即在关键路径上
基于邻接表时间复杂度o(v+e)