【算法复习】理解拓扑排序原理和应用

说明


拓扑排序,其实就是对一个有向图构造拓扑序列的过程。

如果构造的排序将全部顶点都输出了则说明是一个不存在环的AOV网,如果输出点少于顶点数,则说明存在环,则构不成拓扑排序。

在构成的排序线性顺序中,排在前面的通常都是图中的前置点,比如图中顶点的方向是从顶点4->6 那么在拓扑序列中,4一定会排在6的前面。



原理

通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。离散数学中关于偏序和全序的定义:

  若集合X上的关系是R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
  设R是集合X上的偏序(Partial Order),如果对每个x,y属于X必有xRy 或 yRx,则称R是集合X上的全序关系。
  注意:
  ①若将图中顶点按拓扑次序排成一行,则图中所有的有向边均是从左指向右的。
  ②若图中存在有向环,则不可能使顶点满足拓扑次序。

  ③一个DAG的拓扑序列通常表示某种方案切实可行。



应用

(1)在Visual Studio .NET中,一个解决方案可以包含多个项目,一个项目可以引用若干其它项目。编译的时候,VS会自动确定每个项目的编译顺序。VS究竟是如何计算出这个顺序的呢?

(2)给定字母表的前n个大些字母,以及这些字母间两两之间的大小关系(这样的关系给定m组),问由这m组关系能否确定n个字母的整体顺序,如果能输出按续排列的字母。



算法思想


简单的实现步骤如下

  (1)从有向图中选择一个入度为0的顶点并且输出它.

  (2)从网中删去该顶点,并且删去从该顶点发出的全部有向边.

  (3)重复上述两步,直到剩余的网中不再存在没有前趋的顶点为止.


对于这样的AOV网用邻接表的结构(同时为顶点添加一个入度的成员)来存储顶点比较方便来处理,

添加一个栈,初始化将所有入度为0的顶点加入到栈,添加一个输出计数;

再进行一个循环判断栈是否为空,在循环内部出栈一个顶点并输出,同时输出计数加一,删除以此顶点为尾的弧,也就是讲邻接点的入度减一,同时判断此顶点的入度是否为0,为0则添加到栈中;

循环执行完后,判断输出计数与顶点的关系,如果输出计数小于顶点,则说明有环,返回错误,拓扑排序失败。



代码实现


#define MAXVEX 20
using namespace std;
typedef struct EdgeNode  //边表结点
{
  int adjvertex;    //邻接点域,存储该顶点对应的下标
  EdgeNode* next;    
};
typedef struct Vertex
{
  int data;
  int in;    //存放顶点入度
  EdgeNode* firstVertex;   //边表头指针
}AdjList[MAXVEX];

typedef struct GraphAdjList
{
  AdjList adjList;
  int numVertexes,numEdges;
};
int TopologicalSort(GraphAdjList* GL)
{
    int *stack = (int*)malloc(sizeof(int)*GL->numVertexes);
    int count =0,top=0;
    for(int i=0; i < GL->numVertexes; ++i)
    {
         if( !(GL->adjList[i].in) )
               stack[++top]= i;
    }
    while(top)
    {
        int getTop = stack[top--];
        cout<<GL->adjList[getTop].data<<endl;
        ++count;
        for(EdgeNode* edgeNode = GL->adjList[getTop].firstVertex;
            edgeNode;
            edgeNode=edgeNode->next)
        {
           if( !(--GL->adjList[edgeNode->adjvertex].in) )
                 stack[++top]= edgeNode->adjvertex;
        } 
    }
    if(count < GL->numVertexes)
        return 1; //error
    
    return 0;// right 
}




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值