拓扑排序

一.基础知识

1.AOV网(用顶点表示活动的网)
(Activity On Vertex NetWork)

用DAG图(有向无环图)表示⼀个工程,顶点表示活动,有向边<Vi, Vj>表示活动Vi必须先于活动Vj进行

因此:AOV网一定是有向无环图

如:番茄炒蛋的AOV网

2.拓扑排序

把顶点排成一排,且必须满足以下条件

(1) 每个顶点出现且只出现一次
(2)AOV网中A→B,表示拓扑排序中A排在B之前

这种序列成为原图的一个拓扑排序

注:
(1)有向无环图才有拓扑排序
(2)拓扑排序结果可能不唯一

二.拓扑排序的构建

首先,准备厨具和买菜任选一

如果选择准备厨具

下一个必定选买菜

然后打鸡蛋、洗番茄任选一。如果选择洗番茄

切番茄、打鸡蛋任选一。如果选择切番茄

再依次选择打鸡蛋、下锅炒、吃。完成

描述总结:

①从AOV网中选择一个没有前驱(入度为0)的顶点并输出
②从网中删除该顶点和所有以它为起点的有向边
③重复①和②直到当前的AOV网为空或当前网中不存在无前驱的顶点为止(不存在回路),即不存在回路才能将其加入拓扑序列,因此,拓扑排序可以用来判断一个有向图是否有环(回路)

如:当前所有顶点的入度>0,无法执行①

三.算法实现

indegree[]:当前顶点入度
print[]:记录拓扑序列
栈S:保存度为0的顶点(也可用队列、数组)

在此图中,indegree[]={0,1,0,2,2}
print[]={-1,-1,-1,-1,-1}

开始

for (int i = 0; i < G.vexnum; i++)if (indegree[i] == 0)push(S, i);//将所有入度为0的顶点进栈

此时0、2入栈

int count = 0;//计数,记录当前已经输出的顶点数
while (!IsEmpty(S)){Pop(S, i);//栈S中弹出2,剩0print[count++] = i;//输出顶点i=2}

回顾:print[]:记录拓扑序列

2出栈,此时count=0,指向0号位的2
print[count++]表示先print[count](记录2为拓扑序列),再count++(count指向下一个,如图)


然后
通过邻接矩阵,找到2指向的结点(3和4),把这些弧去掉

目的:将所有i=2指向的顶点的入度-1,并且将入度为0的顶点压入栈S

ArcNode* firstarc;//指向第一条依附于该顶点的弧的指针,即2→3的弧
struct ArcNode* nextarc;//指向下一条弧的指针,即2→4的弧
int adjvex;//该弧所指向的顶点位置,即3

当前i=2

for (p = G.vertices[i].firstarc; p; p = p->nextarc) {//第一次p=第一条依附于2的弧的指针:2→3的箭头
//第二次p=指向下一条弧的指针:2→4的箭头v = p->adjvex;
//第一次v=该弧所指向的顶点位置,即v=3
//第二次v=该弧所指向的顶点位置,即v=4if (!(--indegree[v]))push(S, v);//若该节点入度为0,则入栈
//原来顶点3和顶点4的入读均为2,-1均为1,不入栈}

if (!(- -indegree[v])) 相当于先indegree[v] - - ,再判断if
if(!x)表示:若x为假(为0),则执行后面语句
如:顶点3的入度减1,再进行判断,如果为0,则压入栈(此处顶点3的入度减1后是1,不入栈)

(因为从网中删除顶点2和所有以它为起点的有向边)

注:如果此处改为if(!(indegree[v]- -)) 则含义为先判断if,再让indegree[v]-1

更新indegree数组

然后

while (!IsEmpty(S))
{Pop(S, i);print[count++] = i;//输出顶点i
}

弹出0,0入print,count向后

此时栈空

for (p = G.vertices[i].firstarc; p; p = p->nextarc) {//将所有i指向的顶点的入度-1,并且将入度为0的顶点压入栈Sv = p->adjvex;if (!(--indegree[v]))push(S, v);//入度为0,则入栈}}

G.vertices[i].firstarc->adjvex找到1
1的入度为1≠0,入度-1,此时1的入度为0,压入栈

继续
1出栈,加入print,count++
找到3,入度-1=0,3入栈
3出栈,加入print,count++
找到4,入度-1=0,4入栈

while (!IsEmpty(S)){Pop(S, i);//4出栈print[count++] = i;//4加入print,count变为5for (p = G.vertices[i].firstarc; p; p = p->nextarc) {v = p->adjvex;if (!(--indegree[v]))push(S, v);}//跳过}//while结束
if (count < G.vexnum)return false;//排序失败,有向图中有回路elsereturn true;//count=5=顶点数,成功

结果

最终代码

#define MaxVertexNum 100//图中顶点数目的最大值
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;//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)){Pop(S, i);print[count++] = i;//输出顶点ifor (p = G.vertices[i].firstarc; p; p = p->nextarc) {//将所有i指向的顶点的入度-1,并且将入度为0的顶点压入栈Sv = p->adjvex;if (!(--indegree[v]))push(S, v);//入度为0,则入栈}}if (count < G.vexnum)return false;//排序失败,有向图中有回路elsereturn true;//拓扑排序成功
}

四.时间复杂度
在代码中,每个顶点都需要处理一次,每条边也都需要处理一次,因此对于邻接表的时间复杂度为O(|V|+|E|)
另:邻接矩阵:O(|V|2)

五.逆拓扑排序

改变:从AOV网中选择一个没有后继(出度为0)的顶点并输出






完成

六.逆拓扑排序的实现(DFS算法)
(详情DFS)

第一次走到底,依次访问0134,print4
继续执行3,print3
继续执行1,print1
继续执行0,print0
访问2,print2

完整代码

void DFSTraverse(Graph G) {//对图G进行深度优先遍历for (v = 0; v < G.vexnum; ++v)visited[v] = FALSE;//初始化已访问标记数组for (v = 0; v < G.vexnum; ++v)if (!visited[v])DFS(G, v);
}
void DFS(Graph G, int v) {//从顶点v出发,深度优先遍历图Gvisited[v] = True;//设已访问标记for(w=FirstNeigbor(G,v);w>=0;w=NextNeighbor(G,v,w))if (!visited[w]) {//w为u的尚未访问的邻接顶点DFS(G, w);}print(v);
}

6-13图-拓扑排序相关推荐

  1. LeetCode 802. 找到最终的安全状态(逆向图+拓扑排序)

    文章目录 1. 题目 2. 解题 1. 题目 在有向图中, 我们从某个节点和每个转向处开始, 沿着图的有向边走. 如果我们到达的节点是终点 (即它没有连出的有向边), 我们停止. 现在, 如果我们最后 ...

  2. 【算法数据结构体系篇class16】:图 拓扑排序

    一.图 1)由点的集合和边的集合构成 2)虽然存在有向图和无向图的概念,但实际上都可以用有向图来表达 3)边上可能带有权值 二.图结构的表达 1)邻接表法 类似哈希表, key就是当前节点.value ...

  3. pku 1691 Painting A Board DFS 抽象建图 + 拓扑排序

    http://poj.org/problem?id=1691 题意: 给定一个大矩形,然后给出n个需要染色的小矩形的左上角的坐标,右下角的坐标以及该矩形要染得颜色,每个颜色对应的一把刷子.问将这些小矩 ...

  4. 【BZOJ-2938】病毒 Trie图 + 拓扑排序

    2938: [Poi2000]病毒 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 609  Solved: 318 [Submit][Status][ ...

  5. 有向无环图拓扑排序(python实现)

    问题:有向无环图的拓扑排序 题目描述 由某个集合上的一个偏序得到该集合上的一个全序,这个操作被称为拓扑排序.偏序和全序的定义分别如下: 若集合X上的关系R是自反的.反对称的和传递的,则称R是集合X上的 ...

  6. 判断图有无环_浅谈什么是图拓扑排序

    1 引言   在工程实践中,一个工程项目往往由若干个子项目组成.这些子项目间往往有两种关系:   (1) 先后关系,即必须在某个项完成后才能开始实施另一个子项目.   (2) 子项目间无关系,即两个子 ...

  7. 邻接表储存的图拓扑排序

    拓扑排序,可以检查图中是否存在环,若图中的顶点都在他的 拓扑排序中,则它不存在环,若有的点不存在拓扑排序序列中,不在序列的结点存在环,或者它在环之中. //拓扑排序 #include<iostr ...

  8. 浅谈什么是图拓扑排序

    1 引言   在工程实践中,一个工程项目往往由若干个子项目组成.这些子项目间往往有两种关系:   (1) 先后关系,即必须在某个项完成后才能开始实施另一个子项目.   (2) 子项目间无关系,即两个子 ...

  9. 反向建图拓扑排序习题

    题目描述 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予1到N的顺序编号,预估质量最高的菜肴编号为1. 由于菜肴 ...

最新文章

  1. 语义分割--FCN 算法中的一些细节--特征怎么融合
  2. 新概念0804:潘石屹学习python
  3. 三朵云 华为_携手共进,华为云推出“Go Africa”计划
  4. 【Python-随机旋转】图像随机旋转及坐标进行旋转原理
  5. 简述java规范要注意哪些问题_JAVA学习:JAVA基础面试题(经典)
  6. 02331 数据结构 二叉树的遍历
  7. 优秀!303篇论文获2020年度“优秀博士学位论文”!
  8. 通达oa考勤可以代打吗_可完全免费使用的OA办公系统
  9. 计算机操作系统》第06章在线测试,《计算机操作系统》第06章在线测试
  10. Lambda表达式的生动理解以及Java Lambda表达式常见使用场景
  11. 转:华 为 路 由 常 用 命 令
  12. WinInet 错误代码 (12001 - 12156 )
  13. VS2019 配置OpenGL
  14. [bzoj4136][fjoi2015]带字串包含约束lcs问题
  15. 网络流量在线分析系统的设计与实现
  16. IE不兼容HTML5、CSS3解决方法
  17. UG NX 10 重新附着草图
  18. matlab中idfs,【 MATLAB 】离散傅里叶变换(DFT)以及逆变换(IDFT)的MATLAB实现
  19. Photon Socket 术语表
  20. CA基本常识:X.509标准

热门文章

  1. 高德地图自动获取当前位置可搜索可拖拽获得GPS和道路信息
  2. 編程之美﹣電梯調度算法
  3. 山东科技大学OJ题库 1011-GHacker的解谜过关游戏
  4. 呕心沥血梳理C++新标准超好用的新特性(实战必备)
  5. 推荐一款免费的SQLsever的备份软件sqlBackupAndFtp
  6. 济南电子机械工程学校计算机专业班主任,济南电子机械工程学校提升教育教学常规管理 关注每一名学生 每个环节都是德育阵地...
  7. Graphviz绘制模型树1——软件配置与XGBoost树的绘制
  8. Google Pixel手机解锁 bootloader
  9. iQunix F60机械键盘使用评价(精准踩雷)
  10. 一、机器学习实战之K-近邻算法