拓扑排序
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
ຫໍສະໝຸດ Baidu
入度
02 10 21 30 42 50
入度
02 1 -1
21 31 top=5 4 2 53
{ g[i].inDegree = top; top = i; //结点i进栈
} p=p->next; } //while (p!=… } return cnt; }
U 我们这里是为了方便才使用栈。但使用栈不能识别并行成分。事 实上,拓扑排序可以使用队列,这样也可以方便地识别并行成分。
A 如果入度域是做为公用的数据成员,则它的值应该一直保持正确。但 该程序运行后,入度域的值被改变了,故该程序有副作用!避免的方法 是设立临时结构存放入度值。
long top, cnt, i;
TGraphEdgeAL<TEdgeElem> *p;
top=0;
cnt=0;
for (i=0; i<=n; i++)
if (g[i].inDegree == 0) { g[i].inDegree = top; top = i; } //结点i进栈。用g的入度
域做为栈。
};
(三) 算法实现
根据上面的讨论,可给出拓扑排序算法的粗略描述:
long TopoSort(图 g)
{ long cnt=0; for (每个结点v) if (v入度为0) v进栈; while (栈不空) { 从栈中弹出一个元素送v; 输出v; cnt++; 求出v的第1个直接可达邻接点w; while (w存在) { 将w的入度域减1; if (w的入度域为0) w进栈; 求出v的下个直接可达邻接点w; } //while } //whilereturn cnt; }
此方法的正确性是显然的。
通过对此方法做适当扩充,就可在求拓扑序列的过 程中标识出可并行活动(结点)。具体做法是,初始 时将所有无前趋结点标为一组可并行结点。然后,每 次执行步骤[3]后,将新产生的无前趋结点标为新的一 组可并行结点。为了将同组并行结点连续排列,在步 骤[1]中应优先选取并行组号与上次选择结点的并行组 号相同的结点(若有的话)。
从前面给出的拓扑排序基本方法看,拓扑排序涉及的基 本操作有:
n 判别某结点是否有前趋;
n 删除一个无前趋结点及其关联的边。
为此,我们为每个结点设一个入度域。结点入度大于0时 表示有前趋,否则无前趋。对于删除,其真正目的也不是删 除,而是为了通知出点:对应的一个前驱已处理完。因此, 删除某结点时,只需对该结点的各直接可达邻接点(出点) 的入度分别减1。
struct TGraphNodeAL : public TGraphNode0 <TElem>
{//邻接表结点
public: GraphEdgeAL<TEdgeElem> * firstOutEdge; //本 结点的第一条出边的指针 long inDegree; //入度 //面是其他成员的声明,同TGraphNode0,此处不重 载,故不给出
从代数结构角度来看,拓扑排序是由某集合上的一个偏序关 系得到一个全序关系的操作。若将集合中结点作为图结点, 将它上的偏序关系作为图的边,则任一偏序关系均可表示为 一个有向图。
显然,某一图的拓扑序列可能不唯一。
拓扑排序主要用在一类称为 AOV网(Activity on Vertex networks)的有向图中。AOV网是给有向图的结点与边赋予 一定的语义的图,具体地:
l
65
∧
m 78
n
n
7 11
∧
o
9 11
∧
1
a0
1
2
c0
2
3
f0
3
4
h2
4
5
j2
5
6
l1
6
7
m1
7
8
∧2
8
9
o2
9
10
∧3
10
11
∧2
11
增加一列,表示 各点的入度
a0 c0 f0 h0 j2 l0 m1 ∧2 o1 ∧0 ∧2
先扫描入度为0的结 点,将其取出,然后 删除与其有链接的边。 同时减少对应边终点 的入度。例中删除1、 2、3点后结点4的入 度减2为0,结点6的 入度减1为0,结点9 的入度减1,节电10 的入度减3。结点4、 6、10 成为新的入度 为0的结点
课程编号 1 2 3 4 5 6 7 8 9 10 11
课程名称 高等数学 离散数学 高级语言 数据结构 操作系统 计算机组成原理 数据库原理 编译原理 计算机网络 人工智能原理 软件工程
先行课
3,2 4,6 2 5 4,7 5,1 1,2,3 7.9
10 123
964 58
11 7
图 21-1 课程表(左)对应的AOV网(右)
具体实施方法是,对入度为0的结点,令它的入度域 的值为下一个入度为0的结点在头指针数组中的序号(下 标),最后一个入度为0 的结点的入度域置特殊标志(如1)(充当栈底),最先一个入度为0的结点的位置(在数 组中的下标)用一个指示器指示(如top),充当栈顶指示 器。
U 这种栈实质上是一种静态链式栈。这里给出的方法,不仅 对拓扑排序本身有意义,更重要的是,它代表着一种方法。
图 21-1(右)可有多个拓扑序列,下面给出了 它的两个不同的拓扑序列:
1 2 3 4 6 10 5 9 7 8 11
1 2 3 4 6 10 5 7 9 8 11 如果图中两个结点之间均没有通路,那么称它
们是可并行的。在一个拓扑序列中,如果某子串 (序列中某一段)中的各结点之间均是可并行的, 则称该段为一个并行段(组)。一个可并行组包含 了所有的可并行结点,则称该组为最大并行段 (组)。找出最大并行组的工作称为并行识别。
(四) 静态链栈的使用
在上面给出的程序中,为了节省空间,我们没有单独 设立栈,而利用图结点(其存放在称为头数组的数组中) 中的入度域构造一个链式栈。在拓扑排序程序中,逻辑上 栈存放当前入度为0且尚未输出的结点,而这些结点的入 度域此时对该程序已无用,所以可用它们形成一个链,将 它们链接在一条链中,从而起到栈的作用。
并不是所有的有向图都可以进行拓扑排序。显然, 若图中每个结点都有前驱,或者每个几点都有后继, 则该图是不可拓扑排序的。
21.1.2拓扑排序算法与实现
(一) 基本方法
这里,我们给出一种拓扑排序算法。该算法是简单而直 观的,实质上属于广度优先遍历,因此称为广度优先拓扑 排序算法。该算法包含下列几个步骤:
while (top>0) {
i = top; top = g[top].inDegree; //出栈,栈顶元素送i resu[cnt]=i; k++; p=g[i].firstOutEdge; while ( p!=NULL ) {
i=p->endNo; g[i].inDegree--; if (g[i].inDegree==0)
并行组具有重要的实际意义。位于同一组的各结点 代表的活动可以同时进行,以缩短整个事务的完成时 间。例如,对选课问题,如果采用串行修课方式,则 可完全按拓扑序列进行,但若要在一段时间内同时修 多门课,这就需识别出哪些课可同时修,这是一个并 行识别问题。同一并行组内的课程可以同时修学。例 如,在图 21-1中,可并行的课程组有(1,2,3)、(4,6,10)、 (5) 、 (9,7) 、 (8,11) 。 但 注 意 , 这 些 组 之 间 还 是 有 序 的 (这几个组的次序为它们的出现次序)。
下面是具体的C++程序。在该程序中,没有单独设置栈, 而是利用结点数组g的入度域做栈。
template <class TElem, class TEdgeElem>
long TopoSort(TGraphNodeAL<TElem, TEdgeElem>
*g, long n, long *resu) { //对图g求拓朴序列,存入resu(结点编号),n为图结点数目。 //返回所求得的结点数。若返回值小于n,则表示未能完全拓 扑排序。
[1] 从有向图中找一个没有前趋的结点v,若v不存在, 则表明不可进行拓扑排序(图中有环路),结束(不完全 成功);
[2] 将v输出; [3] 将v从图中删除,同时删除关联于v的所有的边 [4] 若图中全部结点均已输出,则结束(成功),否则 转[1]继续进行。
10 123
964 58
11 7
10
964 58
为了方便找到尚未输出的无前趋结点,将它们统一存放 在一个栈中。每次执行入度减1(即删除一边)操作后,若有 结点入度变为0,则将它放入栈中。每次选择无前趋结点时, 也是从栈中提取。
为此,邻接表的图结点的定义中需设置入度域,我 们将前面给出的TGraphNodeAL定义修改为:
template <class TElem, class TEdgeElem>
拓扑排序的概念以及算法实现
数据结构与算法
---第二十一讲
北方民族大学 计算机科学与工程学院
王伦津 研究员
21、拓扑排序的概念以及拓扑排序 的算法实现
掌握拓扑排序的概念,拓扑排序的 算法与实现,学会在AOV和AOE网 上的应用
目录
21.1拓扑排序 21.1.1拓扑序列与AOV网 21.1.2拓扑排序算法与实现
11 7
9
58 11
7
9
8 11
7
图21-2
逐次去掉没有前趋的结点 的过程
11
8
0
11
011
1
01
1
01
1
011
10
01
1
0
01
0
0
课程表AOE网的邻接矩 阵,它的列全为0的点, 就是无前趋的点,取出 该点
0
11
011
1
01
1
01
1
011
10
01
1
0
01
0
0
删除该点对应的列和行,矩 阵的阶数减1,再发现新的 全为0的列,同样办法处理, 直至所有结点输出
U 对拓扑排序,还有一种算法,称为深度优先 拓扑排序。它的基本思想是先输出无后继的结点,即 对每个结点v,检查先一次递归地求出v的每个后继的 拓扑序列(各序列连接在一起),然后将v插入到该 拓扑序列的最前面。关于具体的程序实现,留作练习。
(二) 数据结构的选取
为了方便拓扑排序的实现,需对前面介绍过的图的存贮 结构做些扩充。单纯从进行拓扑排序来讲,图采用邻接表较 为方便,所以这里只考虑邻接表的情况。
结点──代表活动。如工程中的工序/子任务、状态等 边 ──代表活动之间的进行次序。边<i,j>表示活动i先于j 进行。
AOV网常用来表达流程图,如一个工程中各子任务间的流程 图、产品生产加工流程图、程序流程图、信息(数据)流程 图、活动安排流程图等。
例 21-1 学生的选课次序就是一个AOV网应用问题。 假定某计算机专业的主要课程如图 21-1(左)所示, 则对应的AOV网如图 21-1(右)所示。
21.2 AOE网与关键路径 21.2.1 AOE网与关键路径的概念 21.2.2 关键路径的识别
21.1拓扑排序
拓扑排序是定义在有向图上的一种操作,目的是 根据结点间的关系求得结点的一个线性排列(这点 与遍历操作的目的类似)。这种操作在有关工程进 度/次序规划之类问题中,有着大量应用。一般的 大型工程,都可以划分为多个工序/步骤/子工程, 这些工序有的可独立进行,但大多数和其他工序关 联,即某工序的进行,要等到其他一些工序的完成 才能开始。这类问题都可归结到拓扑排序。
21.1.1拓扑序列与AOV网
对有向图G,若它的一个结点序列 LS:v1, v2,..., vn
满足这样的条件:<vi, vj>是G的边时,在LS中vi 位于vj之前,否则(不是边时)在LS中vi与vj的前 后次序任意, 则称LS为图G的一个拓扑序列, 求拓扑序列的操作称为拓扑排序(Topological Sorting)。
分析此算法的时间复杂度。假定图的结点数与边数分别为n与 m。初始化操作是扫描n个结点,将入度为0者进栈,时间复杂度 为O(n) ,此后是两个嵌套着的while循环,直接根据循环条件分析 循环体进行的次数比较困难,故换个角度进行分析。首先看进栈 操作(及输出操作),因在无环情况下每个结点恰好进栈一次, 故此操作有时间复杂度O(n)。其次分析入度减1操作。在无环情况 下,当排序结束时,每个边恰好被逻辑删除一次,故入度减1操作 的时间复杂度为O(m)。 因这几种操作是拓扑排序算法的主体。故 整个算法的时间复杂度为O(n+m)。
地址 起 终 权 信 链
1
a 9 b 10 ^
息
2
c 4 d 6 e 10 ^ a
19
b
1 10
b ∧
3
f 4 g 10 ^
c
24
d
4
h 5i 8^
d
26
e
5
j 7k 9^
e
2 10
∧
6
l 5^
f
34
g
g
3 10
∧
7
m 8 n 11 ^
h
45
i
8
^
i
48
∧
9
o 11 ^
10
^
11
^
j
57
k
k
59
∧
入度
02 10 21 30 42 50
入度
02 1 -1
21 31 top=5 4 2 53
{ g[i].inDegree = top; top = i; //结点i进栈
} p=p->next; } //while (p!=… } return cnt; }
U 我们这里是为了方便才使用栈。但使用栈不能识别并行成分。事 实上,拓扑排序可以使用队列,这样也可以方便地识别并行成分。
A 如果入度域是做为公用的数据成员,则它的值应该一直保持正确。但 该程序运行后,入度域的值被改变了,故该程序有副作用!避免的方法 是设立临时结构存放入度值。
long top, cnt, i;
TGraphEdgeAL<TEdgeElem> *p;
top=0;
cnt=0;
for (i=0; i<=n; i++)
if (g[i].inDegree == 0) { g[i].inDegree = top; top = i; } //结点i进栈。用g的入度
域做为栈。
};
(三) 算法实现
根据上面的讨论,可给出拓扑排序算法的粗略描述:
long TopoSort(图 g)
{ long cnt=0; for (每个结点v) if (v入度为0) v进栈; while (栈不空) { 从栈中弹出一个元素送v; 输出v; cnt++; 求出v的第1个直接可达邻接点w; while (w存在) { 将w的入度域减1; if (w的入度域为0) w进栈; 求出v的下个直接可达邻接点w; } //while } //whilereturn cnt; }
此方法的正确性是显然的。
通过对此方法做适当扩充,就可在求拓扑序列的过 程中标识出可并行活动(结点)。具体做法是,初始 时将所有无前趋结点标为一组可并行结点。然后,每 次执行步骤[3]后,将新产生的无前趋结点标为新的一 组可并行结点。为了将同组并行结点连续排列,在步 骤[1]中应优先选取并行组号与上次选择结点的并行组 号相同的结点(若有的话)。
从前面给出的拓扑排序基本方法看,拓扑排序涉及的基 本操作有:
n 判别某结点是否有前趋;
n 删除一个无前趋结点及其关联的边。
为此,我们为每个结点设一个入度域。结点入度大于0时 表示有前趋,否则无前趋。对于删除,其真正目的也不是删 除,而是为了通知出点:对应的一个前驱已处理完。因此, 删除某结点时,只需对该结点的各直接可达邻接点(出点) 的入度分别减1。
struct TGraphNodeAL : public TGraphNode0 <TElem>
{//邻接表结点
public: GraphEdgeAL<TEdgeElem> * firstOutEdge; //本 结点的第一条出边的指针 long inDegree; //入度 //面是其他成员的声明,同TGraphNode0,此处不重 载,故不给出
从代数结构角度来看,拓扑排序是由某集合上的一个偏序关 系得到一个全序关系的操作。若将集合中结点作为图结点, 将它上的偏序关系作为图的边,则任一偏序关系均可表示为 一个有向图。
显然,某一图的拓扑序列可能不唯一。
拓扑排序主要用在一类称为 AOV网(Activity on Vertex networks)的有向图中。AOV网是给有向图的结点与边赋予 一定的语义的图,具体地:
l
65
∧
m 78
n
n
7 11
∧
o
9 11
∧
1
a0
1
2
c0
2
3
f0
3
4
h2
4
5
j2
5
6
l1
6
7
m1
7
8
∧2
8
9
o2
9
10
∧3
10
11
∧2
11
增加一列,表示 各点的入度
a0 c0 f0 h0 j2 l0 m1 ∧2 o1 ∧0 ∧2
先扫描入度为0的结 点,将其取出,然后 删除与其有链接的边。 同时减少对应边终点 的入度。例中删除1、 2、3点后结点4的入 度减2为0,结点6的 入度减1为0,结点9 的入度减1,节电10 的入度减3。结点4、 6、10 成为新的入度 为0的结点
课程编号 1 2 3 4 5 6 7 8 9 10 11
课程名称 高等数学 离散数学 高级语言 数据结构 操作系统 计算机组成原理 数据库原理 编译原理 计算机网络 人工智能原理 软件工程
先行课
3,2 4,6 2 5 4,7 5,1 1,2,3 7.9
10 123
964 58
11 7
图 21-1 课程表(左)对应的AOV网(右)
具体实施方法是,对入度为0的结点,令它的入度域 的值为下一个入度为0的结点在头指针数组中的序号(下 标),最后一个入度为0 的结点的入度域置特殊标志(如1)(充当栈底),最先一个入度为0的结点的位置(在数 组中的下标)用一个指示器指示(如top),充当栈顶指示 器。
U 这种栈实质上是一种静态链式栈。这里给出的方法,不仅 对拓扑排序本身有意义,更重要的是,它代表着一种方法。
图 21-1(右)可有多个拓扑序列,下面给出了 它的两个不同的拓扑序列:
1 2 3 4 6 10 5 9 7 8 11
1 2 3 4 6 10 5 7 9 8 11 如果图中两个结点之间均没有通路,那么称它
们是可并行的。在一个拓扑序列中,如果某子串 (序列中某一段)中的各结点之间均是可并行的, 则称该段为一个并行段(组)。一个可并行组包含 了所有的可并行结点,则称该组为最大并行段 (组)。找出最大并行组的工作称为并行识别。
(四) 静态链栈的使用
在上面给出的程序中,为了节省空间,我们没有单独 设立栈,而利用图结点(其存放在称为头数组的数组中) 中的入度域构造一个链式栈。在拓扑排序程序中,逻辑上 栈存放当前入度为0且尚未输出的结点,而这些结点的入 度域此时对该程序已无用,所以可用它们形成一个链,将 它们链接在一条链中,从而起到栈的作用。
并不是所有的有向图都可以进行拓扑排序。显然, 若图中每个结点都有前驱,或者每个几点都有后继, 则该图是不可拓扑排序的。
21.1.2拓扑排序算法与实现
(一) 基本方法
这里,我们给出一种拓扑排序算法。该算法是简单而直 观的,实质上属于广度优先遍历,因此称为广度优先拓扑 排序算法。该算法包含下列几个步骤:
while (top>0) {
i = top; top = g[top].inDegree; //出栈,栈顶元素送i resu[cnt]=i; k++; p=g[i].firstOutEdge; while ( p!=NULL ) {
i=p->endNo; g[i].inDegree--; if (g[i].inDegree==0)
并行组具有重要的实际意义。位于同一组的各结点 代表的活动可以同时进行,以缩短整个事务的完成时 间。例如,对选课问题,如果采用串行修课方式,则 可完全按拓扑序列进行,但若要在一段时间内同时修 多门课,这就需识别出哪些课可同时修,这是一个并 行识别问题。同一并行组内的课程可以同时修学。例 如,在图 21-1中,可并行的课程组有(1,2,3)、(4,6,10)、 (5) 、 (9,7) 、 (8,11) 。 但 注 意 , 这 些 组 之 间 还 是 有 序 的 (这几个组的次序为它们的出现次序)。
下面是具体的C++程序。在该程序中,没有单独设置栈, 而是利用结点数组g的入度域做栈。
template <class TElem, class TEdgeElem>
long TopoSort(TGraphNodeAL<TElem, TEdgeElem>
*g, long n, long *resu) { //对图g求拓朴序列,存入resu(结点编号),n为图结点数目。 //返回所求得的结点数。若返回值小于n,则表示未能完全拓 扑排序。
[1] 从有向图中找一个没有前趋的结点v,若v不存在, 则表明不可进行拓扑排序(图中有环路),结束(不完全 成功);
[2] 将v输出; [3] 将v从图中删除,同时删除关联于v的所有的边 [4] 若图中全部结点均已输出,则结束(成功),否则 转[1]继续进行。
10 123
964 58
11 7
10
964 58
为了方便找到尚未输出的无前趋结点,将它们统一存放 在一个栈中。每次执行入度减1(即删除一边)操作后,若有 结点入度变为0,则将它放入栈中。每次选择无前趋结点时, 也是从栈中提取。
为此,邻接表的图结点的定义中需设置入度域,我 们将前面给出的TGraphNodeAL定义修改为:
template <class TElem, class TEdgeElem>
拓扑排序的概念以及算法实现
数据结构与算法
---第二十一讲
北方民族大学 计算机科学与工程学院
王伦津 研究员
21、拓扑排序的概念以及拓扑排序 的算法实现
掌握拓扑排序的概念,拓扑排序的 算法与实现,学会在AOV和AOE网 上的应用
目录
21.1拓扑排序 21.1.1拓扑序列与AOV网 21.1.2拓扑排序算法与实现
11 7
9
58 11
7
9
8 11
7
图21-2
逐次去掉没有前趋的结点 的过程
11
8
0
11
011
1
01
1
01
1
011
10
01
1
0
01
0
0
课程表AOE网的邻接矩 阵,它的列全为0的点, 就是无前趋的点,取出 该点
0
11
011
1
01
1
01
1
011
10
01
1
0
01
0
0
删除该点对应的列和行,矩 阵的阶数减1,再发现新的 全为0的列,同样办法处理, 直至所有结点输出
U 对拓扑排序,还有一种算法,称为深度优先 拓扑排序。它的基本思想是先输出无后继的结点,即 对每个结点v,检查先一次递归地求出v的每个后继的 拓扑序列(各序列连接在一起),然后将v插入到该 拓扑序列的最前面。关于具体的程序实现,留作练习。
(二) 数据结构的选取
为了方便拓扑排序的实现,需对前面介绍过的图的存贮 结构做些扩充。单纯从进行拓扑排序来讲,图采用邻接表较 为方便,所以这里只考虑邻接表的情况。
结点──代表活动。如工程中的工序/子任务、状态等 边 ──代表活动之间的进行次序。边<i,j>表示活动i先于j 进行。
AOV网常用来表达流程图,如一个工程中各子任务间的流程 图、产品生产加工流程图、程序流程图、信息(数据)流程 图、活动安排流程图等。
例 21-1 学生的选课次序就是一个AOV网应用问题。 假定某计算机专业的主要课程如图 21-1(左)所示, 则对应的AOV网如图 21-1(右)所示。
21.2 AOE网与关键路径 21.2.1 AOE网与关键路径的概念 21.2.2 关键路径的识别
21.1拓扑排序
拓扑排序是定义在有向图上的一种操作,目的是 根据结点间的关系求得结点的一个线性排列(这点 与遍历操作的目的类似)。这种操作在有关工程进 度/次序规划之类问题中,有着大量应用。一般的 大型工程,都可以划分为多个工序/步骤/子工程, 这些工序有的可独立进行,但大多数和其他工序关 联,即某工序的进行,要等到其他一些工序的完成 才能开始。这类问题都可归结到拓扑排序。
21.1.1拓扑序列与AOV网
对有向图G,若它的一个结点序列 LS:v1, v2,..., vn
满足这样的条件:<vi, vj>是G的边时,在LS中vi 位于vj之前,否则(不是边时)在LS中vi与vj的前 后次序任意, 则称LS为图G的一个拓扑序列, 求拓扑序列的操作称为拓扑排序(Topological Sorting)。
分析此算法的时间复杂度。假定图的结点数与边数分别为n与 m。初始化操作是扫描n个结点,将入度为0者进栈,时间复杂度 为O(n) ,此后是两个嵌套着的while循环,直接根据循环条件分析 循环体进行的次数比较困难,故换个角度进行分析。首先看进栈 操作(及输出操作),因在无环情况下每个结点恰好进栈一次, 故此操作有时间复杂度O(n)。其次分析入度减1操作。在无环情况 下,当排序结束时,每个边恰好被逻辑删除一次,故入度减1操作 的时间复杂度为O(m)。 因这几种操作是拓扑排序算法的主体。故 整个算法的时间复杂度为O(n+m)。
地址 起 终 权 信 链
1
a 9 b 10 ^
息
2
c 4 d 6 e 10 ^ a
19
b
1 10
b ∧
3
f 4 g 10 ^
c
24
d
4
h 5i 8^
d
26
e
5
j 7k 9^
e
2 10
∧
6
l 5^
f
34
g
g
3 10
∧
7
m 8 n 11 ^
h
45
i
8
^
i
48
∧
9
o 11 ^
10
^
11
^
j
57
k
k
59
∧