拓扑排序

经典算法之拓扑排序 定义: 把AOV网(用定点表示活动,用弧表示活动间优先关系的有向图)络中各个顶点按照它们互相之间的优先关系排列成一个线性序列的过程叫做拓扑排序。 方法: 在有向图中选一个没有前驱的顶点并且输出 从图中删除该顶点和所有以它为尾的弧,即删除所有与它有关的边。 重复上述两步,直至全部顶点均已输出;或者当图中不存在无前驱的顶点为止。 例题: 首先我们找到无前驱顶点C1和C9,我们删除掉C1... 阅读详情

拓扑排序是对有向无环图的一种排序。表示了顶点按边的方向出现的先后顺序。如果有环,则无法表示两个顶点的先后顺序。

在现实生活中,也会有不少应用例子,比如学校课程布置图,要先修完一些基础课,才可以继续修专业课。
一个简单的求拓扑排序的算法:首先要找到任意入度为0的一个顶点,删除它及所有相邻的边,再找入度为0的顶点,以此类推,直到删除所有顶点。顶点的删除顺序即为拓扑排序。
    很容易得到拓扑排序的伪代码:
    void TopSort(Graph g)
    {
        for (int i=0; i<vertexnum; i++)
        {
            vertex v = FindZeroIndegree(g);
            if (v is not vertex)        
                cout <<"the graph has cycle"<<endl;
            cout << v ;
            foreach vertex w adjacent to v
                w.indegree--;
        }
    }
   
    同样以上图为例,对于该图进行拓扑排序会得到:v1 v2 v5 v4 v3 v7 v6 或者v1 v2 v5 v4 v7 v3 v6 。
    仍然利用上一贴图的构建方法,进行验证。
    代码实现:
 
 
#include <iostream>
using namespace std;

#define MAX_VERTEX_NUM    20
struct adjVertexNode
{
    int adjVertexPosition;
    adjVertexNode * next;
};
struct VertexNode
{
    char data [ 2 ];
    adjVertexNode * list;
    int indegree;
};
struct Graph
{
    VertexNode VertexNode [ MAX_VERTEX_NUM ];
    int vertexNum;
    int edgeNum;
};

void CreateGraph ( Graph & g)
{
     int i , j , edgeStart , edgeEnd;
     adjVertexNode * adjNode;
     cout << "Please input vertex and edge num (vnum enum):" << endl;
     cin >> g . vertexNum >> g . edgeNum;
     cout << "Please input vertex information (v1) /n note: every vertex info end with Enter" << endl;
     for ( i = 0; i < g . vertexNum; i ++)
     {
         cin >> g . VertexNode [ i ]. data; // vertex data info.
         g . VertexNode [ i ]. list = NULL;
         g . VertexNode [ i ]. indegree = 0;
     }
     cout << "input edge information(start end):" << endl;
     for ( j = 0; j < g . edgeNum; j ++)
     {
         cin >> edgeStart >> edgeEnd;
         adjNode = new adjVertexNode;
         adjNode -> adjVertexPosition = edgeEnd - 1; // because array begin from 0, so it is j-1
         adjNode -> next = g . VertexNode [ edgeStart - 1 ]. list;
         g . VertexNode [ edgeStart - 1 ]. list = adjNode;
         //每增加一条边,则边的End顶点的入度加1
         g . VertexNode [ edgeEnd - 1 ]. indegree ++;
     }
}

void PrintAdjList( const Graph & g)
{
    cout << "The adjacent list for graph is:" << endl;
    for ( int i = 0; i < g . vertexNum; i ++)
    {
        cout << g . VertexNode [ i ]. data << "->";
        adjVertexNode * head = g . VertexNode [ i ]. list;
        if ( head == NULL)
            cout << "NULL";
        while ( head != NULL)
        {
            cout << head -> adjVertexPosition + 1 << " ";
            head = head -> next;
        }
        cout << endl;
    }
}

VertexNode & FindZeroIndegree( Graph & g)
{
    for ( int i = 0; i < g . vertexNum; i ++)
    {
        if ( g . VertexNode [ i ]. indegree == 0)
            return g . VertexNode [ i ];
    }
    return g . VertexNode [ 0 ];
}
void TopSort( Graph & g)
{
    cout << "The topsort is:" << endl;
    for ( int i = 0; i < g . vertexNum; i ++)
    {
        VertexNode & v = FindZeroIndegree( g);
        if ( v . indegree != NULL)
            cout << "The graph has cycle, can not do topsort" << endl;
        // print graph as topsort.
        cout << v . data << " ";
        // for each vertex w adjacent to v, --indegree
        adjVertexNode * padjv = v . list;
        while ( padjv != NULL)
        { //!!这个算法这里破坏了原图中的入度信息。最后入度均为1
            g . VertexNode [ padjv -> adjVertexPosition ]. indegree --;
            padjv = padjv -> next;
        }
        //避免入度信息均为零FindZeroIndegree找到删除的顶点,将删除的顶点入度置为1
        v . indegree ++;
    }
    cout << endl;
}

void DeleteGraph( Graph & g)
{
    for ( int i = 0; i < g . vertexNum; i ++)
    {
        adjVertexNode * tmp = NULL;
        while( g . VertexNode [ i ]. list != NULL)
        {
            tmp = g . VertexNode [ i ]. list;
            g . VertexNode [ i ]. list = g . VertexNode [ i ]. list -> next;
            delete tmp;
            tmp = NULL;
        }
    }
}
int main( int argc , const char ** argv)
{
    Graph g;
    CreateGraph( g);
    PrintAdjList( g);
    TopSort( g);
    DeleteGraph( g);

    return 0;
}
 运行结果:
 
     从上面的代码能发现 FindZeroIndegree的时间复杂度为O(|V|),TopSort的时间复杂度为O(|V|2)
     原因在于,每次删除顶点,只有邻接点需要调整入度,但 FindZeroIndegree却是遍历了所有顶点,甚至已经删除的顶点。
     更为合理的方法是将每次遍历得出的入度为0的顶点放入一个队列。
void TopSort2( Graph & g)
{
    queue < VertexNode > q;
    for ( int i = 0; i < g . vertexNum; i ++)
    {
        if ( g . VertexNode [ i ]. indegree == 0)
            q . push( g . VertexNode [ i ]);
    }
    int count = 0;
    cout << "The topsort is:" << endl;
    while ( ! q . empty())
    {
        VertexNode v = q . front();
        q . pop();
        cout << v . data << " ";
        count ++;
        adjVertexNode * padjv = v . list;
        while ( padjv != NULL)
        { //!!这个算法这里破坏了原图中的入度信息。最后入度均为1
            if ( --( g . VertexNode [ padjv -> adjVertexPosition ]. indegree) == 0)
                q . push( g . VertexNode [ padjv -> adjVertexPosition ]);
            padjv = padjv -> next;
        }
    }
    if ( count != g . vertexNum)
        cout << "The graph has cycle, can not do topsort" << endl;
}
     内部的while循环最多执行|E|次,即每条边执行一次。队列对每个顶点最多执行一次操作,所以新算法的时间复杂度为O(|E|+|V|). 优于O(|V|2)因为拓扑图边数最多有n(n-1)/2,即O(|E|+|V|)<=O(|V|2)
【算法】拓扑排序   今天学习拓扑排序。如果一个有向图的任意顶点都无法通过一些有向边回到自身,那么称这个有向图为有向无环图(Directed Acyclic Graph,DAG)。拓扑排序就是将有向无环图的所有顶点排序,使得图中任意两个点 u、v,只要存在边 u → v,那么拓扑排序中 u 一定在 v 前面。例如,高等数学、线性代数都可以直接开始学习,复变函数要学习完前两门课才能学习,所以,拓扑排序可以是:高等数学→线性代数→复变函数,或者线性代数→高等数学→复变函数。下面讲解具体算法的思路。 1.拓扑排序算法 基本思想如下 阅读详情

相关推荐

拓扑排序例题

不懂的看这里 拓扑排序 以下是例题: 拓扑排序·一 简单拓扑判环 #include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 7; vector<int> G[maxn]; int inDeg[maxn]; int n,m; queue<int>q; int sum; bool top(...

Victor的博客 1439

拓扑排序及算法实现

一、拓扑排序概念 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。 简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。 二、理解 在一个有向图中,对所有的节点进行排序,要求没有一个节点指向它前面的节点。...

ShyTan的博客 1万+

【数据结构】什么是拓扑排序—关于图的拓扑排序

​对一个有向无环图G进行拓扑排序,是将G中所有顶点排成一个线性序列。拓扑排序:对一个有向图构建拓扑序列的过程。 ​

四季轮换叶,一路招摇胜 8717

排序算法——拓扑排序(卡恩算法(广度优先)、dfs+深度搜索算法)

文章目录前言一、拓扑排序规则二、卡恩算法实现1.卡恩算法思想2.代码实现三、dfs+深度优先1.算法思想2.代码实现总结 前言 本篇博客主要记录拓扑排序的实现。包括卡恩算法实现和dfs+深度搜索算法实现。其实这两个算法本质分别是广度优先搜索和深度优先搜索。 一、拓扑排序规则 首先知道入度和出度的概念,箭头指向本顶点,则本顶点的入度就+1,箭头指出。则出度+1。 拓扑排序即把出度为0的结点一个一个找出来,看下例子就知道了: 上图中1入度为0,所以1排在前面,此时拓扑排序为{1},将1指出去的箭头都擦去,.

yi_chengyu的博客 8944

电子工程师日记:用STM32F4的DCMI接口驱动OV2640时,那些数据同步的坑我都踩过了

本文分享了使用STM32F4的DCMI接口驱动OV2640摄像头时,在数据同步方面遇到的典型问题与解决方案。作者通过示波器分析PCLK相位、纠正DCMI_CR寄存器中同步信号极性的配置误区,并排查DMA传输瓶颈与FIFO溢出,最终实现了稳定的图像采集。文章为嵌入式工程师提供了宝贵的硬件调试经验与配置清单。

weixin_29189377的博客 156

STM32驱动HC-SR04超声波模块:两种精准测距方案详解

本文详解STM32驱动HC-SR04超声波模块的两种精准测距方案:定时器中断计数法和外部中断边沿检测法。涵盖硬件连接、代码实现与优化技巧,帮助开发者根据精度和复杂度需求选择合适方案,提升超声波测距在嵌入式项目中的稳定性和准确性。

g5h6i的博客 684

java 拓扑运算_拓扑排序(三)之 Java详解

拓扑排序介绍拓扑排序(Topological Order)是指,将一个有向无环图(Directed Acyclic Graph简称DAG)进行排序进而得到一个有序的线性序列。这样说,可能理解起来比较抽象。下面通过简单的例子进行说明!例如,一个项目包括A、B、C、D四个子部分来完成,并且A依赖于B和D,C依赖于D。现在要制定一个计划,写出A、B、C、D的执行顺序。这时,就可以利用到拓扑排序,它就是用...

weixin_42551967的博客 1371

FPGA实现Gardner环定时同步:Verilog代码与Testbench实战解析

本文深入解析了在FPGA上实现Gardner环定时同步的完整过程,详细阐述了其非数据辅助的定时误差检测原理。通过Verilog代码实战,展示了内插滤波器、定时误差检测器、环路滤波器和数控振荡器等核心模块的设计,并提供了完整的Testbench验证方法,帮助开发者解决数字通信系统中的时钟同步难题。

gpt4scribbler的博客 576

拓扑排序的原理及其实现

本文将从以下几个方面介绍拓扑排序: 拓扑排序的定义和前置条件和离散数学中偏序/全序概念的联系典型实现算法 Kahn算法基于DFS的算法 解的唯一性问题实际例子 取材自以下材料: http://en.wikipedia.org/wiki/Topological_sorting http://en.wikipedia.org/wiki/Hamiltonian_pat

不忘初心,好好沉淀 21万+

Fortran环境配置:VS2022+Intel oneAPI安装全流程指南

Fortran环境配置:VS2022+Intel oneAPI安装全流程指南

shuyisuisuinian的博客 2万+

未来智能家居解决方案:AI应用架构师的前沿探索

当你加班到深夜回家时,门锁自动识别你的脚步声解锁,玄关灯渐亮成你最爱的暖光,空调早已调到25℃(你夏天的习惯温度),音箱播放着最近循环的爵士乐,茶几上的智能水壶烧好了温水——这不是科幻电影,而是未来智能家居的日常。如何让“冰冷的设备”变成“懂你的伙伴”。我们将深入探讨五大前沿技术(边缘AI、多模态融合、联邦学习、数字孪生、个性化推荐)的底层原理,用“家里的小管家”“邻居互相学习”等生活化比喻简化复杂概念,结合代码示例与架构图还原实现流程,并通过智能卧室、智能厨房等真实案例展示落地路径。

AI天才研究院 1411

拓扑排序详解

拓扑排序是一种用于有向无环图(DAG)的排序算法,它按照节点之间的依赖关系对节点进行排序,确保任何一个节点在排在其依赖节点之后。这种排序常用于任务调度、编译顺序等场景。今天就让我们来深入理解一下。

2301_80035594的博客 2350

避坑指南:DeepSeek Function calling流式输出中的常见问题与解决方案

本文深入探讨了在DeepSeek Function Calling中实现流式输出时常见的参数拼接、函数依赖管理和错误处理等核心挑战。针对流式响应中参数碎片化的问题,提供了健壮的参数拼接方案与状态管理策略。同时,文章详细阐述了如何管理函数调用顺序、处理条件性执行,并构建了分阶段的错误处理与重试机制,旨在帮助开发者构建稳定、高效的流式AI应用。

weixin_29062671的博客 203

拓扑排序详解及C++实现

介绍拓扑排序的定义、逻辑,包含完整的模拟过程和C++代码实现,及拓扑排序判环。拓扑序列:对于一个有向无环图将图中的顶点排成一个序列,其中每个边的起点在序列中一定在终点之前;通俗解释为:将一张图“压扁”,使顶点从左到右排成序列,且压扁后每条边的方向只能朝右,那么这个序列是这张图的拓扑序列。 拓扑排序就是求解一张有向无环图拓扑序列的过程。

一直爱算法的猫的博客 5984

C#中通过Mapster实现轻量级高效对象映射器:从零到精通

本文介绍了.NET生态中高性能对象映射库Mapster的完整使用指南。从基础安装(通过NuGet包)到快速入门示例,展示了如何实现简单对象映射。进一步讲解了自定义映射规则、命名不一致属性的处理方式,以及如何在ASP.NET Core中集成Mapster服务。针对复杂场景,详细解析了嵌套对象映射的配置技巧,并提供了性能优化方案(如预编译映射器)和调试技巧(启用调试模式、捕获映射异常)。通过完整的代码实践,帮助开发者高效解决从基础到高级的对象映射需求。

墨夶的博客 742

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

有向图拓扑排序

有向图拓扑排序 前言 本文介绍有向图拓扑排序算法的思路及代码实现,首先讲解什么是拓扑排序,其次介绍实现拓扑排序需要的检测有向图是否有环的算法及顶点排序算法,最终实现有向图的拓扑排序。 一、什么是拓扑排序? 给定一副有向图,将所有的顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素,此时就可以明 确的表示出每个顶点的优先级。如对下图进行拓扑排序: 拓扑排序结果为: 根据拓扑排序的概念,如果对有向图进行拓扑排序,那么图中必须没有环,否则,就不能进行拓扑排序,然后在图中无环的情况下,再进行顶点排

Mekeater的博客 1万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

什么是拓扑排序

一、什么是拓扑排序 在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件: 每个顶点出现且只出现一次。 若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。 有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。 例如,下面这个图: 它是一个 DAG 图,那么如何写出它的拓扑排序呢?这里说一种比较常用的方法:..

哦,原来你也在这里。 8253

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

拓扑排序算法

用unordered_map就比较万能了,完全像刚才想象出来的邻接表结构,我们这里是一个int的数后面挂了一个int数组,那不就和一个节点挂着一个节点的效果一样的吗。我们可以把给的信息抽象称一张有向图,题目问能否完成所有课程学习意思就是能不能把这个课程排个序,说白了就是能否拓扑排序,能否拓扑排序也就是是否这个图是否是有向无环图 —> 有向图中是否有环?,有向图就是边都是有方向的。直接对图来一次拓扑排序,当拓扑排序过程中发现没有入度为0的点的时候,但是图中还有剩余点的时候,此时这个图中一定会有环形结构。

2301_80224556的博客 1750

图的拓扑排序

算法思想 按照有向图给出的次序关系,将图中顶点排成一个线性序列,对于有向图中没有限定次序关系的顶点,则可以人为加上任意的次序关系,由此所得顶点的线性序列称之为拓扑有序序列。显然对于有回路的有向图得不到拓扑有序序列,因为有回路的话,顶点的先后次序就不确定了。 例如,下图,我们可以人为限定次序:A B C D 或 A C B D 如何进行拓扑排序? 从有向图中选取一个没有前驱(没有在它之前活动)的顶点,输出之; 从有向图中删去此顶点以及所有以它为尾的弧; 重复上述两步,直至图空,或者图不空但找不到无前驱的顶

ChanCherry的博客 3255

拓扑排序概念

拓扑排序,顾名思义,就是一种排序方法。这是一种什么排序?这种排序的作用?然后怎么去实现这种排序算法?现在就让我们仔细研究下。 1、什么是拓扑排序,也就是拓扑排序的概念 实际上,拓扑排序是一种图论算法,该算法在《数据结构与算法》一书中有涉猎。引用维基百科的定义: 在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序(英语:Topological sorti...

MinisterZ的博客 8192

【Java】拓扑排序

java实现拓扑排序

rellvera的博客 3570

拓扑排序基础

拓扑排序:对图中所有节点进行排序,保证每个节点的前置节点都在这个节点之前。【使用要求】:有向图,无环拓扑排序的顺序可能不只一种。拓扑排序也可以用来判断图中有没有环存在。在图中找到所有入度为0的点 (入度为0说明此节点没有前置节点,那它只能是其他节点的前置节点,所以先提出来放在拓扑排序前面)把所有入度为0的节点在图中删掉,重点是把与其他邻居节点的关联删除。之后继续找到入度为0的节点并删掉关联。直到所有的节点被删除,依次删除的顺序就是正确的拓扑排序结果如果无法删除所有点,说明有向图中有环存在。

2302_76853832的博客 1494

有向图的拓扑排序

若排序后满足,图中的任意一条有向边(u, v),u的位置都在v的前面,则称为拓扑排序该图的拓扑排序为A B C D,AC 边A在C的前面,BC边BZ在C的前面.......所有边都满足定义。

shallrelow的博客 1038
上一篇: 构建一个图
下一篇: 无权最短路径-广度优先搜索
midgard
博客等级 码龄21年 88粉丝 21原创
评论 18
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值