——本节内容为Bilibili王道考研《数据结构》P66视频内容笔记。
目录
一、基本概念
1.AOV网
(用顶点表示活动的网)用DAG图(有向无环图)表示一个工程,顶点表示活动,有向边<Vi,Vj>表示活动Vi必须先于活动Vj进行;
2.拓扑排序
拓扑排序是对有向无环图的顶点的一种排序,它使得若存在一条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。每个AOV网都有一个或多个拓扑排序序列。
3.拓扑排序实现
(1)从AOV网中选择一个没有前驱(入度为0)的顶点并输出;
(2)从网中删除该顶点和所有以它为起点的有向边;
(3)重复(1)和(2)直到当前AOV网为空或当前网中不存在无前驱的顶点为止(如果当前所有顶点入度>0,说明原图存在回路)。
二、代码实现
1.代码实现
typedef struct ArcNode { //边/弧
int adjvex; //边/弧指向哪个结点
struct ArcNode* nextarc; //指向下一条弧的指针
//InfoType info; //边权值
}ArcNode;
typedef struct VNode { //顶点
VertexType data; //顶点信息
ArcNode* firstarc; //第一条边/弧
}VNode, AdjList[MaxVertexNum];
typedef struct { //用邻接表存储的图
AdjList vertices;
int vexnum, arcnum;
}Graph;
bool TopologicalSort(Graph G)
{
InitStack(S); //初始化栈,存储入度为0的顶点
for (int i = 0; i < G.vexnum; i++)
if (indegree[i] == 0)
Push(S, i); //将所有入度为0的顶点进栈
int count = 0; //计数,记录当前已经输出的顶点数
while (!isEmpty(S)) //栈不空,则存在入度为0的顶点
{
Pop(S, i); //栈顶元素出栈
print[count++] = i; //输出顶点i
for (p = G.vertices[i].firstarc; p; p.nextarc)
{ //将所有i指向的顶点的入度减1,并且将入度减为0的顶点压入栈S
v = p.adjvex;
if (!(--indegree[v]))
Push(S, v); //入度为0,则入栈
}
}
if (count < G.vexnum)
return false; //排序失败,有向图中有回路
else
return true; //拓扑排序成功
}
2.图示
3.时间复杂度
(1)邻接表:O(|V|+|E|);
(2)邻接矩阵:;
三、逆拓扑排序
1.实现方法
(1)从AOV网中选择一个没有后继(出度为0)的顶点并输出;
(2)从网中删除该顶点和所有以它为终点的有向边;
(3)重复(1)和(2)直到当前AOV网为空。
2.DFS算法实现逆拓扑排序
void DFSTraverse(Graph G) //对图G进行深度优先遍历
{
for (v = 0; v < G.vexnum; ++v)
visited[v] = false; //初始化已访问标记数据
for (v = 0; v < G.vexnum; ++v) //本代码中是v=0开始遍历
if (!visited[v])
DFS(G, v);
}
void DFS(Graph G, int v) //从顶点v出发,深度优先遍历图G
{
visit(v); //访问顶点v
visited[v] = true; //设已访问标记
for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))
if (!visited[w]) //w为u的尚未访问的邻接顶点
{
DFS(G, w);
}
print(v); //输出顶点
}