拓扑排序的应用
programtopsort;typenode=^link;link=recordprocedureaddd(x,y:longint);varp:node;beginnew(p);p^.g:=y;p^.next:=nd[x];nd[x]:=p;inc(ru[y]);end;beginreadln(n,m);fora:=1tomdobeginreadln(x,y);addd(x,y);end;fora:=1tondoifru[a]=0thenbegininc(stk);stack[stk]:=a;end;be:=0;repeatinc(be);x:=stack[be];p:=nd[x];write(x,'');whilepnildobegindec(ru[p^.g]);ifru[p^.g]=0thenbegininc(stk);stack[stk]:=p^.g;end;p:=p^.next;end;untilbe=stk;readln;end.这里主要是将入度为零的点加入队列stack,直接在队列内扩展即可,效率为O(n+m)
拓扑排序常用来确定一个依赖关系集中,事物发生的顺序。例如,在日常工作中,可能会将项目拆分成A、B、C、D四个子部分来完成,但A依赖于B和D,C依赖于D。为了计算这个项目进行的顺序,可对这个关系集进行拓扑排序,得出一个线性的序列,则排在前面的任务就是需要先完成的任务。注意:这里得到的排序并不是唯一的!就好像你早上穿衣服可以先穿上衣也可以先穿裤子,只要里面的衣服在外面的衣服之前穿就行。
在很多条件下,任务的执行是连续进行的,例如汽车装配问题或平时购买的标有“需要装配”的消费品(自行车、小孩的秋千装置,割草机等等)。我们可根据所建议的顺序来装配。在由任务建立的有向图中,边( i, j)表示在装配序列中任务i 在任务j 的前面,具有这种性质的序列称为拓扑序列(topological orders或topological sequences)。根据任务的有向图建立拓扑序列的过程称为拓扑排序(topological sorting)。图1 - 4的任务有向图有多种拓扑序列,其中的三种为1 2 3 4 5 6,1 3 2 4 5 6和2 1 5 3 4 6,序列1 4 2 3 5 6就不是拓扑序列,因为在这个序列中任务4在3的前面,而任务有向图中的边为( 3 , 4),这种序列与边( 3 , 4)及其他边所指示的序列相矛盾。可用贪婪算法来建立拓扑序列。算法按从左到右的步骤构造拓扑序列,每一步在排好的序列中加入一个顶点。利用如下贪婪准则来选择顶点:从剩下的顶点中,选择顶点w,使得w 不存在这样的入边( v,w),其中顶点v 不在已排好的序列结构中出现。注意到如果加入的顶点w违背了这个准则(即有向图中存在边( v,w)且v 不在已构造的序列中),则无法完成拓扑排序,因为顶点v 必须跟随在顶点w 之后。贪婪算法的伪代码如图1 3 - 5所示。while 循环的每次迭代代表贪婪算法的一个步骤。
现在用贪婪算法来求解图1 - 4的有向图。首先从一个空序列V开始,第一步选择V的第一个顶点。此时,在有向图中有两个候选顶点1和2,若选择顶点2,则序列V = 2,第一步完成。第二步选择V的第二个顶点,根据贪婪准则可知候选顶点为1和5,若选择5,则V = 2 5。下一步,顶点1是唯一的候选,因此V = 2 5 1。第四步,顶点3是唯一的候选,因此把顶点3加入V
得到V = 2 5 1 3。在最后两步分别加入顶点4和6 ,得V = 2 5 1 3 4 6。
1. 贪婪算法的正确性
为保证贪婪算法算的正确性,需要证明: 1) 当算法失败时,有向图没有拓扑序列; 2) 若
算法没有失败,V即是拓扑序列。2) 即是用贪婪准则来选取下一个顶点的直接结果, 1) 的证明见定理1 3 - 2,它证明了若算法失败,则有向图中有环路。若有向图中包含环qj qj + 1.qk qj , 则它没有拓扑序列,因为该序列暗示了qj 一定要在qj 开始前完成。
定理1-2 如果图1 3 - 5算法失败,则有向图含有环路。
证明注意到当失败时| V |<n, 且没有候选顶点能加入V中,因此至少有一个顶点q1 不在V中,有向图中必包含边( q2 , q1)且q2 不在V中,否则, q1 是可加入V的候选顶点。同样,必有边(q3 , q2)使得q3 不在V中,若q3 = q1 则q1 q2 q3 是有向图中的一个环路;若q3 ≠q1,则必存在q4 使(q4 , q3)是有向图的边且q4 不在V中,否则,q3 便是V的一个候选顶点。若q4 为q1 , q2 , q3 中的任何一个,则又可知有向图含有环,因为有向图具有有限个顶点数n,继续利用上述方法,最后总能找到一个环路。
2. 数据结构的选择
为将图1 - 5用C + +代码来实现,必须考虑序列V的描述方法,以及如何找出可加入V的候选顶点。一种高效的实现方法是将序列V用一维数组v 来描述的,用一个栈来保存可加入V的候选顶点。另有一个一维数组I n D e g r e e,I n D e g r e e[ j ]表示与顶点j相连的节点i 的数目,其中顶点i不是V中的成员,它们之间的有向图的边表示为( i, j)。当I n D e g r e e[ j ]变为0时表示j 成为一个候选节点。序列V初始时为空。I n D e g r e e[ j ]为顶点j 的入度。每次向V中加入一个顶点时,所有与新加入顶点邻接的顶点j,其I n D e g r e e[ j ]减1。对于有向图1 - 4,开始时I n D e g r e e [ 1 : 6 ] = [ 0 , 0 , 1 , 3 , 1 , 3 ]。由于顶点1和2的I n D e g r e e值为0,因此它们是可加入V的候选顶点,由此,顶点1和2首先入栈。每一步,从栈中取出一个顶点将其加入V,同时减去与其邻接的顶点的I n D e g r e e值。若在第一步时从栈中取出顶点2并将其加入V,便得到了v [ 0 ] = 2,和I n D e g r e e [ 1 : 6 ] = [ 0 , 0 , 1 , 2 , 0 , 3 ]。由于I n D e g r e e [ 5 ]刚刚变为0,因此将顶点5入栈。
程序1 3 - 2给出了相应的C + +代码,这个代码被定义为N e t w o r k的一个成员函数。而且,它对于有无加权的有向图均适用。但若用于无向图(不论其有无加权)将会得到错误的结果,因为拓扑排序是针对有向图来定义的。为解决这个问题,利用同样的模板来定义成员函数AdjacencyGraph, AdjacencyWGraph,L i n k e d G r a p h和L i n k e d W G r a p h。这些函数可重载N e t w o r k中的函数并可输出错误信息。如果找到拓扑序列,则Topological 函数返回t r u e;若输入的有向图无拓扑序列则返回f a l s e。当找到拓扑序列时,将其返回到v [ 0 :n- 1 ]中。
3. Network:Topological 的复杂性
第一和第三个f o r循环的时间开销为(n )。若使用(耗费)邻接矩阵,则第二个for 循环所用的时间为(n2 );若使用邻接链表,则所用时间为(n+e)。在两个嵌套的while 循环中,外层循环需执行n次,每次将顶点w 加入到v 中,并初始化内层while 循环。使用邻接矩阵时,内层w h i l e循环对于每个顶点w 需花费(n)的时间;若利用邻接链表,则这个循环需花费dwout 的时间,因此,内层while 循环的时间开销为(n2 )或(n+e)。所以,若利用邻接矩阵,程序1 3 - 2的时间复杂性为(n2 ),若利用邻接链表则为(n+e)。
程序13-2 拓扑排序
bool Network::Topological(int v[])
{// 计算有向图中顶点的拓扑次序
// 如果找到了一个拓扑次序,则返回t r u e,此时,在v [ 0 : n - 1 ]中记录拓扑次序
// 如果不存在拓扑次序,则返回f a l s e
int n = Ve r t i c e s ( ) ;
// 计算入度
int *InDegree = new int [n+1];
InitializePos(); // 图遍历器数组
for (int i = 1; i <= n; i++) // 初始化
InDegree[i] = 0;
for (i = 1; i <= n; i++) {// 从i 出发的边
int u = Begin(i);
while (u) {
I n D e g r e e [ u ] + + ;
u = NextVe r t e x ( i ) ; }
}
// 把入度为0的顶点压入堆栈
LinkedStack<int> S;
for (i = 1; i <= n; i++)
if (!InDegree[i]) S.Add(i);
// 产生拓扑次序
i = 0; // 数组v 的游标
while (!S.IsEmpty()) {// 从堆栈中选择
int w; // 下一个顶点
S . D e l e t e ( w ) ;
v[i++] = w;
int u = Begin(w);
while (u) {// 修改入度
I n D e g r e e [ u ] - - ;
if (!InDegree[u]) S.Add(u);
u = NextVe r t e x ( w ) ; }
}
D e a c t i v a t e P o s ( ) ;
delete [] InDegree;
return (i == n);
}
PASCAL拓扑排序~~
拓扑排序是图论的基本算法之一;做一件事情,比如盖新房子,会分成很多工作:买地,买砖,打桩,砌砖,粉刷,放家具...但是这些工作是有一定顺序的,比如说不可能砖都没砌好就开始粉刷,盖房必须在买地买砖都完成后才能开始..所以对于一件事我们总要确定工作顺序,确定这个顺序的过程就是拓扑排序。算法...
有向图的拓扑排序
输入格式 第一行包含两个整数n和m 接下来m行,每行包含两个整数x和y,表示存在一条从点x到点y的有向边(x, y)。输出格式 共一行,如果存在拓扑序列,则输出拓扑序列。 否则输出-1。数据范围 1≤n,m≤105 拓扑排序:找到没有前驱的结点,删除。重复这个步骤。最后按照删除结点的...
有个图的顶点的排序问题,怎么做?
拓扑排序对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。所以上图可以变成这样 上面的是正确答案,即所有的边都是向后的。而下面的1432则有一个向前的边2->3.
大学要学会这8种算法程序员
算法三: 归并排序 归并排序(Mergesort,台湾译作: 合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(DivideandConquer)的一个非常典型的应用。算法步骤:1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 2.设定两个指针,最初位置分别为两个已经排序序列的...
拓扑排序时间复杂度o(n+e)怎么算的?
对有n个顶点和e条弧的有向图而言,建立求各顶点的入度的时间复杂度为O(e);建零入度顶点栈的时间复杂度为O(n);在拓扑排序过程中,若有向图无环,则每个顶点进一次栈、出一次栈,入度减1的操作在while语句中总共执行e次,所以总的时间复杂度为O(n+e)。对一个有向无环图(Directed Acyclic ...
算法的种类有哪些
算法的种类有很多,主要包括以下几种:1. 排序算法 排序算法是计算机科学中最为基础和常用的算法之一。这类算法的主要目的是将一组数据按照特定的顺序进行排列。常见的排序算法包括冒泡排序、选择排序、插入排序、快速排序等。2. 图算法 图算法是用于处理图形数据的算法,主要应用于图论和计算机科学中的相关...
有关拓扑排序的问题
由AOV网构造拓扑序列的拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止。(1)选择一个入度为0的顶点并输出之;(2)从网中删除此顶点及所有出边。循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,否则输出的顶点序列就是一种拓扑序列。
已知图G=(V,E),其中V={a,b,c,d,e}E={,,,<d,c>,,<c,e>,<d.e>}画出图...
已知有向图G=(V,E),其中V={a,b,c,d,e,f,g},E={,,,,<c,e>,<c,f>,<d,f>,<e,g>,<f,g>}G的拓扑序列是a,c,d,f,b,e,g。对一个有向无环图G进行拓扑排序,将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边∈E(G),则u在线性序...
数据结构 java开发中常用的排序算法有哪些
for(int i=L+incr;i<n;i+=incr)\/\/对每个子列表应用插入排序 { int temp=arr[i]; int j=i-incr; while(j>=0&&arr[j]>temp) { arr[j+incr]=arr[j]; j-=incr; } arr[j+incr]=temp; } } } } ---Code--- 适用于排序小列表。 效率估计O(nlog2^n)~O(n^1.5),取决于增...
关键路径怎么求?求详解。
关键路径的算法是建立在拓扑排序的基础之上的,这个算法中用到了拓扑排序。1.什么是拓扑排序?举个例子先:一个软件专业的学生学习一系列的课程,其中一些课程必须再学完它的基础的先修课程才能开始。如:在《程序设计基础》和《离散数学》学完之前就不能开始学习《数据结构》。这些先决条件定义了课程之间...
莱宜铿锵: 拓扑排序在aov网中为了更好地完成工程,必须满足活动之间先后关系,需要将各活动排一个先后次序即为拓扑排序.如上图的拓扑排序基础知识;pascal;数据结构;离散数学.或基础知识;离散数学pascal;数据结构.拓扑排序的方法...
茌平县13781366670: 如何利用拓扑排序将一个有向无环图的邻接矩阵中的非零元素集中到对角线以上 - ?
莱宜铿锵: 二者的区别: 邻接矩阵(Adjacency Matrix):是表示顶点之间相邻关系的矩阵.设G=(V,E)是一个图,其中V={v1,v2,…,vn}.G的邻接矩阵是一个具有下列性质的n阶方阵: ①对无向图而言,邻接矩阵一定是对称的,而且主对角线一定为零(在此仅讨论无向简单图),副对角线不一定为0,有向图则不一定如此. ②在无向图中,任一顶点i的度为第i列所有元素的和,在有向图中顶点i的出度为第i行所有元素的和,而入度为第i列所有元素的和. ③用邻接矩阵法表示图共需要n^2个空间,由于无向图的邻接矩阵一定具有对称关系,所以扣除对角线为零外,仅需要存储上三角形或下三角形的数据即可,因此仅需要n(n-1)/2个空间.
茌平县13781366670: 请问拓补排序的作用是什么 - ?
莱宜铿锵: 1.q->next=s;//p是否也行? 不行,他们是不同的节点,换成了p,你就别想执行正确的操作了!2.void display( person *head)//不用const是否可以? 可以,不过那样人家可以在这个成员函数中修改你的数据了,会导致不必要的错误!所以在成员函...
茌平县13781366670: 拓扑排序的作用 - ?
莱宜铿锵: 一些大的工程可能用到,先后顺序,多道工序
茌平县13781366670: 拓扑排序 - ?
莱宜铿锵: 通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列.简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序.离散数学中关于偏序和全序的定义: 若集合X上的关系是R是自...
茌平县13781366670: 怎样利用拓扑排序把邻接矩阵的非零全都变到对角线之上 - ?
莱宜铿锵: 利用拓扑结构 将环形拓扑改造成星型拓扑结构即可.进行一下线路调整,再增加一个网络连接设备(交换机等)3
茌平县13781366670: 有向图中怎么用拓扑排序判断环 - ?
莱宜铿锵:[答案] 发现只要一个点在排序时多于一次符合入队条件
茌平县13781366670: 怎么样进行拓扑排序? - ?
莱宜铿锵: 每次找到图中入度为0的点,将这个点加入队列中,并从图中删去这个点(删去由这个点所发出的边并将这些边所能到达的点的入度-1),重复这个操作,若在队列长度小于图中点的个数的情况下找不到入度为0的点的话,就代表图中有环,无法进行拓扑排序,否则在结束后输出这个队列,就是对这个图的一种(注意,一个图可能存在多种可能的拓扑排序的方案)拓扑排序的方案.