数据结构---设计---图论---有向无环图及其应用---【拓扑排序】

本文详细介绍了拓扑排序的概念,包括从偏序到全序的关系转换,并通过AOV(Activity On Vertex)网阐述了拓扑排序的应用。在AOV网上,拓扑排序用于判断是否存在环并生成有序序列。给出了具体算法实现,包括邻接表存储结构、栈的使用以及如何处理无环和有环的情况。此外,还展示了完整的C++代码示例,用于实现拓扑排序和检查有向图是否存在环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

了解拓补排序前,我们先回顾离散数学中关于偏序和全序的定义:
若集合X上的关系R是自反的、反对称的和传递的,则称R是集合X上的偏序关系。
设R是集合X上的偏序(Partial Order),如果对每个x,yEX必有xRy或yRx,则称R是集合X上的全序关系。
· 直观地看,偏序指集合中仅有部分成员之间可比较,而全序指集合中全体成员之间均可比较。

那么什么是拓扑排序(Topological Sort)?我们说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

我们知道,用顶点表示活动,用弧表示活动间的优先关系的有向图称作顶点表示活动的网,英文即Activity On Vertex Network ,简称AOV-网。
在这个网中,从顶点i到顶点j有一条有向路径,则i是j的前驱;j是i的后继。若<i,j>是网中的一条弧,那么i是j的直接前驱;j是i的直接后继。 可参考(b)来理解这句话。

在这里插入图片描述
在这里插入图片描述

(a)表示偏序,(b)表示全序。若在(a)的有向图上人为地加一个表示v₂≤v₃。的弧(符号“≤”表示v₂领先于v₃),则(a)表示的亦为全序,且这个全序称为拓扑有序(Topological Order),而由偏序定义得到拓扑有序的操作便是拓扑排序。

AOV-网特点:
1.AOV-网中的弧表示活动之间存在的某种制约关系。
2.AOV-网中不能出现回路。

  • 典型AOV-网例题

对程序的数据流图来说,首先要判定所给定的AOV-网中是否存在环。检测方法就是对有向图构造其顶点的拓补有序序列,若网中所有的顶点都在他的拓扑有序序列中,则该AOV-网中必定不存在环,那么这样设计出来的流程图,工程可以正常进行。

先看简单的:

  • 某a专业学生必学课程AOV-网

在这里插入图片描述
基本思想:
(1)从AOV网中选择一个没有前驱的顶点并且输出;
(2)从AOV网中删去该顶点,并且删去所有以该顶点)为尾的弧;
(3)重复上述两步,直到全部顶点都被输出,或AOV-网中不存在没有前驱的顶点。
·拓扑排序后,有向图有如下两个拓扑有序序列:

拓扑序列:C1 , C2 , C3 , C4 , C5 , C6
拓扑序列:C1 , C2 , C3 , C4 , C5 , C6 ,C7

  • 设计数据结构:
    (1).图的存储(利用邻接表存储,在顶点表中增加一个入度域in)
    在这里插入图片描述
    (2).栈M(存储所有无前驱的顶点。也可以用队列。)
    步骤:扫描顶点表,将堆栈初始化。将入度为0的顶点B,E压入堆栈。
    弹出堆栈,取出栈顶元素E;根据顶点E的firstEdge遍历所有的边,将其所指向的各个顶点的入度值-1。
    在处理时,如果发现某个顶点的入度值为0,则压入堆栈。

  • 核心代码:

拓扑排序算法—伪代码

1.栈M初始化;累加器count初始化;
2.扫描顶点表,将没有前驱的顶点压栈;
3.当栈M非空时循环
3.1 Vj=退出栈顶元素;输出Vj;累加器加1;
3.2将顶点Vj的各个邻接点的入度减1;
3.3将新的入度为0的顶点入栈;
4.if (count<vertexNum)输出有回路信息;

void ALGraph::TopologicalSort(){
   
    for(int i=0;i<vertexNum;i++){
      //in为0则压栈 
        if(adjList[i].in==0){
   
            s.push(adjList[i]);
        } 
    }
    while(!s.empty()){
                 //循环终止条件:栈为空 
        vertexNode v=s.top();       //弹栈输出 
        s.pop();
        cout<<v.vertex<<" ";
        count++;                    //计数加一 
        ArcNode *a=v.firstEdge;     
        while(a){
                      //对弹出的结点遍历,所有遍历过的结点的in-1 
            adjList[a->adjvex].in--;
            int tmp=adjList[a->adjvex].in;
            if(tmp==0){
                //如果某结点的in变为0,则将其压栈 
                s.push(adjList[a->adjvex])    ;    
            }
            a=a->next;
        }
    }
    if(count<vertexNum) cout<<"有环"<<endl; //如果计数小于顶点数则说明有环 
    else cout<<"无环,成功完成"<<endl; 
} 

  • 完整代码
#include<iostream>
#include<stack>
#include<cstring>
#define MAX 100
using namespace std;
typedef struct ArcNode{
            //边结点 
    int adjvex;                 //顶点下标 
    ArcNode *next;
}ArcNode;
typedef struct{
   
    int in;                     //in是入度 
    string vertex;              //顶点信息 
    ArcNode *firstEdge;             
}vertexNode,VertexNode[MAX];

class ALGraph{
   
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力努力在努力(奋斗版)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值