拓扑排序

一,基本的定义:

在有向图中的顶点以线性方式进行排序。即对于任何连接自顶点u到顶点v的有向边uv,在最后的排序结果中,顶点u总是在顶点v的前面。

拓扑排序必须在又向无环图中进行(即不应该带有回路,因为若带有回路,则回路上的所有活动都无法进行。如三角形是一个具有三个顶点的回路,由<A,B>边可得B活动必须在A活动之后,由<B,C>边可得C活动必须在B活动之后,所以推出C活动必然在A活动之后,但由<C,A>边可得C活动必须在A活动之前,从而出现矛盾,使每一项活动都无法进行。这种情况若在程序中出现,则称为死锁或死循环,是应该必须避免的。)
把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称AOV网。
AOV网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。

二,基本思路:

由AOV网构造拓扑序列的拓扑排序算法主要是循环执行以下两步,直到不存在入度为0的顶点为止。

    (1) 选择一个入度为0的顶点并输出之;

    (2) 从网中删除此顶点及所有出边。

    循环结束后,若输出的顶点数小于网中的顶点数,则输出“有回路”信息,否则输出的顶点序列就是一种拓扑序列。

  




图3-7 拓扑排序的图形说明

    (1) 在(a)图中v0和v1的入度都为0,不妨选择v0并输出之,接着删去顶点v0及出边<0,2>,得到的结果如(b)图所示。

    (2) 在(b)图中只有一个入度为0的顶点v1,输出v1,接着删去v1和它的三条出边<1,2>,<1,3>和<1,4>,得到的结果如(c)图所示。

    (3) 在(c)图中v2和v4的入度都为0,不妨选择v2并输出之,接着删去v2及两条出边<2,3>和<2,5>,得到的结果如(d)图所示。

    (4) 在(d)图上依次输出顶点v3,v4和v5,并在每个顶点输出后删除该顶点及出边,操作都很简单,不再赘述。

为了利用C++语言在计算机上实现拓扑排序算法,AOV网采用邻接表表示较方便。如对于图3-8(a),对应的邻接表如图3-8所示。

 

 
  


图3-8 图3-7(a)的链接表

 

在拓扑排序算法中,需要设置一个包含n个元素的一维整型数组,假定用d表示,用它来保存AOV网中每个顶点的入度值。如对于图3-8(a),得到数组d的初始值为

 

                          0    1    2    3    4    5

 0

 0

 2

 2

 1

 3

 

    在进行拓扑排序中,为了把所有入度为0的顶点都保存起来,而且又便于插入、删除以及节省存储,最好的方法是把它们链接成一个栈。另外,当一个顶点vi的入度为0时,数组d中下标为i的元素d[i]的值为0,正好可利用该元素作为链栈中的一个结点使用,保存下一个入度为0的顶点的序号,这样就可以把所有入度为0的顶点通过数组d中的对应元素静态链接成一个栈。在这个链栈中,栈顶指针top指向第一个入度为0的顶点所对应的数组d中的元素,该元素的值则指向第二个入度为0的顶点所对应的数组d中的元素,依此类推,最后一个入度为0顶点所对应的数组d中的元素保存着-1,表示为栈底。

    例如,根据图3-8所示的邻接表,建立的入度为0的初始栈的过程为:

    (1) 开始置链栈为空,即给链栈指针top赋初值为-1:

            top=-1;

    (2) 将入度为0的元素d[0]进栈,即:

            d[0]=top; top=0;    

    此时top指向d[0]元素,表示顶点v0的入度为0,而d[0]的值为-1,表明为栈底。

    (3) 将入度为0的元素d[1]进栈,即:

            d[1]=top; top=1;

    此时top指向d[1]元素,表示顶点v1的入度为0,而d[1]的值为0,表明下一个入度为0的元素为d[0],即对应下一个入度为0的顶点为v0,d[0]的值为-1,所以此栈当前有两个元素d[1]和d[0]。

    (4) 因d[2]至d[5]的值均不为0,即对应的v2到v5的入度均不为0,所以它们均不进栈,至此,初始栈建立完毕,得到的数组d为:

                          0    1    2    3    4    5

-1

 0

 2

 2

 1

 3

                                top

 

    将入度为0的顶点利用上述链栈链接起来后,拓扑算法中循环执行的第(1)步“选择一个入度为0的顶点并输出之”,可通过输出栈顶指针top所代表的顶点序号来实现;第(2)步“从AOV网中删除刚输出的顶点(假定为vj,其中j等于top的值)及所有出边”,可通过首先作退栈处理,使top指向下一个入度为0的元素,然后遍历vj的邻接点表,分别把所有邻接点的入度减1,若减1后的入度为0则令该元素进栈来实现。此外,该循环的终止条件“直到不存在入度为0的顶点为止”,可通过判断栈空来实现。

    对于图3-7(a),当删除由top值所代表的顶点v1及所有出边后,数组d变为:

                         0    1    2    3    4    5

-1

 

 1

 1

 0

 3

                                               top

    当依次删除top所表示的每个顶点及所有出边后,数组d的变化分别如图3-9(a)至(d)所示:

 

                          0    1    2    3    4    5

-1

 

 1

 1

 

 2

                          top

                             (a) 删除顶点v4及所有出边

 

                          0    1    2    3    4    5

 

 

-1

 1

 

 2

                                     top

                             (b) 删除顶点v0及所有出边

 

                          0    1    2    3    4    5

 

 

 

-1

 

 1

                                          top

                             (c) 删除顶点v2及所有出边

 

                          0    1    2    3    4    5

 

 

 

 

 

-1

                                                     top

                             (d) 删除顶点v3及所有出边

图3-9 数组d变化示意图

 

    当删除顶点v5及所有出边后,top的值为1,表示栈空,至此算法执行结束,得到的拓扑序列为:1,4,0,2,3,5。

 


 


























 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值