有向无环图的拓扑排序理解和算法

这篇具有很好参考价值的文章主要介绍了有向无环图的拓扑排序理解和算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

有向无环图的拓扑排序理解和算法

  1. 有向无环图(DAG)定义

引用子维基百科的DAG定义, 在数学中,尤其是图论和计算机科学中,DAG是一类不含环的有向图(In mathematics, particularly graph theory, and computer science, a directed acyclic graph (DAG) is a directed graph with no directed cycles). 对比之前的有向图的强连通分量,凡是在图中能能够找到强连通分量的有向图(单个顶点除外),都排除在DAG之外。对于有向无环图,拓扑排序是其关键的操作,通过拓扑排序,便能把有向无环图的先后遍历顺序”线性化“。

  1. DAG的应用

现实世界中,很多场合都涉及到DAG的应用,最常见的应用包括,项目管理中各个事件先后顺序排列的可行性,学校选课系统设计, 程序设计的互相依附以及事件的模拟等等。

我们以某高校的选课系统为例进行说明,如果要选择Class H, 那么选修之前需要完成Class D 和 Class E课程,如果要选择Class D课程,就需要提前学习Class A和 Class B.

有向无环,算法,图论

选择Class H的前置条件

有向无环,算法,图论

  1. 拓扑排序目标

在拓扑排序中,我们需要对有向无环图每个顶点进行检查,经过拓扑排序后,我们会形成一个类似数组的线性结构来表示各个顶点的先后顺序,Dynamic Programming就需要利用DAG形成某些节点,对这些节点进行共用,减少计算事件。值得一提的是,拓扑排序的结果不一定唯一,同一个DAG图形可能会有几个不同的拓扑排序。我们以下图为例,

有向无环,算法,图论

最后形成的线性次序关系如下:
有向无环,算法,图论

  1. 算法原理

一般实现Topological 排序方法有 Kahn’s 算法和 DFS算法,

  • Kahn’s 算法非常直观,两步循环即可

​ (1)在有向图中选一个没有前驱的顶点且输出之

​ (2)在图中删除该顶点和所有以它为尾的弧,换言之;对于图上以此点为弧头的顶点,其入度减1

​ 重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点为止(存在环)

​ 在Kahn’s 算法中:

​ (a)可以直接线性搜索 入度为0的顶点(没有前驱)

​ (b) 利用栈或队列进行保留入度为0的顶点,后面直接出栈,更新相关顶点的入度值

​ 两类算法的事件复杂度分别为O(|V|2)和O(|V|+|E|).

  • DFS 算法当有向图中无环时,也可用DFS进行拓扑排序,因为图中无环,则由图中某点出发进行深度优先搜索遍历时,最先退出DFS函数的顶点即出度为零的顶点,是拓扑有序序列中的最后一个顶点。可以利用数组进行拓扑有序序列中的序号存储。

    ​ © DFS算法实现

  1. 算法代码实现

(a)可以直接线性搜索 入度为0的顶点(没有前驱)

/**
	Use Adajacent list to go through each vertex
	Work out the indegree array based on the traversal
*/
void assign_indegree(ALGraph G, int *indegree)
{
    int i;
    int v;
    int w;

    
    for(v=0;v<G.vexnum;v++)
    {
        for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
        {
            indegree[w]++;
        }
    }    
}

/**
Linear search the indegree array and return the first new zero indegree vertex node
*/
int find_new_zero_indegree_vertex(ALGraph G, int *indegree, int *top_num)
{
    int i;

    for(i=0;i<G.vexnum;i++)
    {
        if(top_num[i]==-1 && indegree[i]==0)
        {
            return i;
        }
    }

    return NOT_A_VERTEX;  //NOT_A_VERTEX=-1;
}
/**
	Find the topological sort of directed graph
*/
Status topological_sort(ALGraph G,void (*visit)(VertexType e))
{
    int counter;
    int indegree[MAX_VERTEX_NUM];
    int top_num[MAX_VERTEX_NUM]; //top_num will store the top order vertex #No.
    int v;
    int w;

    for(counter=0;counter<G.vexnum;counter++)
    {
        *(top_num+counter)=-1;
    }

    memset(indegree,0,sizeof(int)*MAX_VERTEX_NUM);
    assign_indegree(G,indegree);

    for(counter=0;counter<G.vexnum;counter++)
    {
        v=find_new_zero_indegree_vertex(G,indegree,top_num);

        //If v equals to NOT Available VERTEX, 
        //it must contain the cycle in the graph
        //terminate the program
        if(v==NOT_A_VERTEX)
        {
            return ERROR;
        }
		
        
        *(top_num+v)=counter;

        for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
        {
            indegree[w]--;
        }
    }

    dispay_order(G,top_num,visit);
}
/**
Display the topological order based on top_num array list
*/
void dispay_order(ALGraph G, int *top_num, void (*visit)(VertexType e))
{
    int i;

    for(i=0;i<G.vexnum;i++)
    {
        visit(G.vertices[top_num[i]].data);
    }
}

(b) 利用栈或队列进行保留入度为0的顶点,后面直接出栈,更新相关顶点的入度值

void assign_indegree(ALGraph G, int *indegree)
{
    int i;
    int v;
    int w;

    
    for(v=0;v<G.vexnum;v++)
    {
        for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
        {
            indegree[w]++;
        }
    }    
}

Status topological_sort(ALGraph G,void (*visit)(VertexType e))
{
    SqStack S;
    int indegree[MAX_VERTEX_NUM];
    int i;
    int v;
    int w;
    int count;

    InitStack_Sq(&S);
    memset(indegree,0,sizeof(int)*MAX_VERTEX_NUM);
    assign_indegree(G,indegree);
    count =0;

    for(i=0;i<G.vexnum;i++)
    {
        if(!indegree[i])
        {
            Push_Sq(&S,i);
        }
    }

    while(!StackEmpty_Sq(S))
    {
        Pop_Sq(&S,&v);
        visit(G.vertices[v].data);
        count++;

        for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
        {
            if(!(--indegree[w]))
            {
                Push_Sq(&S,w);
            }
        }
    }

    if(count<G.vexnum)
    {
        return ERROR;
    }

    return OK;


}

© DFS算法实现

Status find_topological_sort(ALGraph G, int *ordering)
{
    int v;
    int w;
    count =0;
    int index;
    memset(visited,0,sizeof(int)*MAX_VERTEX_NUM);
    index=G.vexnum-1;

    for(v=0;v<G.vexnum;v++)
    {
        if(!visited[v])
        {
            dfs_topological_sort(G,v,index-count,ordering);
        }
    }

    if(count<G.vexnum)
    {
        return ERROR;
    }

    return OK;
}

//----
int dfs_topological_sort(ALGraph G, int v0, int index, int *ordering)
{
    
    int v;
    int w;
    visited[v0]=1;
    count++;

    v=v0;

    for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
    {
         if(!visited[w])
        {
            //index will be kept as the same as DFS deep dive into search
            //when the first recursive call ended, it will be decremented by 1
            //and in the next loop, index will be upated in the recursive call
            index=dfs_topological_sort(G,w,index,ordering);
        }
    }
    
    ordering[index]=v;
    return index-1;
}
//------
void dispay_ordering(int *ordering, ALGraph G, void (*visit)(VertexType e))
{
    int i;

    for(i=0;i<G.vexnum;i++)
    {
        visit(G.vertices[ordering[i]].data);
    }
}

  1. 总结

DAG的拓扑排序(全序)建立顶点或元素之间的先后关系,利用DAG的拓扑排序结果,可以有效地管理项目中不不同节点的先后顺序,可以更合理地进行选课,抑或对大型程序之间的依附关系进行罗列,做到逻辑次序先后合理,更好完成具体的应用工作。

具体来说,如果对于某个事件或节点,其没有任何前置约束,那么此事件或节点就可以作为当前的拓扑有序点。拓扑排序算法一般分为Kahn’s 和经典的DFS深度优先搜索法,Kahn’s 比较直观,DFS搜索法代码简练,各有千秋。

Reference book and video:

a)《数据结构》 严蔚敏

b) Video, Topological Sort Algorithm|Graph Theory, William Fiset文章来源地址https://www.toymoban.com/news/detail-766664.html

到了这里,关于有向无环图的拓扑排序理解和算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】有向无环图(AOE-网)的关键路径(C语言)

    把用顶点表示事件,用弧表示活动,弧的权值表示活动所需要的时间的有向无环图称为 边表示活动的网 ,简称 AOE-网 。 在AOE-网中存在唯一的、入度为0的顶点,称为 源点 ;存在唯一的、出度为0的顶点,称为 汇点 。从源点到汇点的最长路径长度即为完成整个工程任务所需的

    2024年02月07日
    浏览(33)
  • (Java)数据结构——图(第八节)有向无环图(DAG图)以及DAG描述表达式

    本博客是博主用于复习数据结构以及算法的博客,如果疏忽出现错误,还望各位指正。 昨天复习了拓扑排序,打算写个博客,一翻数据结构的书到那,发现连着概念还有DAG图以及AOV网,于是看了看,这篇博客先来介绍有向无环图DAG。 下图一个无环的有向图乘坐有向无环图,

    2024年04月12日
    浏览(27)
  • 【海量数据挖掘/数据分析】之 贝叶斯信念网络(贝叶斯信念网络、有向无环图、贝叶斯公式、贝叶斯信念网络计算实例)

    目录 【海量数据挖掘/数据分析】之 贝叶斯信念网络(贝叶斯信念网络、有向无环图、贝叶斯公式、贝叶斯信念网络计算实例) 一、贝叶斯信念网络 1 . 属性关联 : 贝叶斯信念网络 允许数据集样本属性 之间存在依赖关系 ; 2 . 贝叶斯信念网络 表示方法 : 二、概率图模型 : 马尔

    2024年02月12日
    浏览(40)
  • 【数据结构——有向图】有环无环判定、拓扑排序(DFS、BFS)

    有向图(Directed Graph),也被称为有向图形或方向图,是一种图的类型。在有向图中,图中的边具有方向,从一个顶点指向另一个顶点。 在有向图中,每个顶点表示一个实体,而有向边则表示实体之间的关系或连接。这种有方向性的边表明了连接的起点和终点之间的单向关系

    2024年02月09日
    浏览(39)
  • 【数据结构与算法】图的遍历与拓扑排序

    再上一篇中我们讲了树的两种存储方式:【数据结构与算法】图——邻接表与邻接矩阵 这一篇我们可以用数组来模拟邻接表。 假设现在我们要进行n次操作,实现无向图。 首先需要一个 保存是哪个节点 的数组 e 然后就是类似指针数组的 表 h ,每个表都会连一串单链表 e,ne

    2024年02月04日
    浏览(35)
  • 有向图的拓扑排序

    拓扑排序 。任意给定一个有向图,设计一个算法,对它进行拓扑排序。拓扑排序算法思想:a.在有向图中任选一个没有前趋的顶点输出;b.从图中删除该顶点和所有以它为尾的弧;c.重复上述a、b,直到全部顶点都已输出,此时,顶点输出序列即为一个拓朴有序序列;或者直到

    2024年02月09日
    浏览(35)
  • 2023-8-29 有向图的拓扑排序

    题目链接:有向图的拓扑排序

    2024年02月11日
    浏览(28)
  • 教学计划编制问题(数据结构 有向图 拓扑排序)

     本文对以下教学计划编制问题的解决作出实现,主要使用c语言(带一点cpp),开发环境为codeblocks 17.12,希望对各位读者有所帮助。(源码和数据文件可在主页获取,同时还有使用视频文件压缩包,数据文件需要和exe在同一目录下,结合某读者的意见同时放到github了 ) 地址如下

    2024年02月09日
    浏览(38)
  • ⌈算法进阶⌋图论::拓扑排序(Topological Sorting)——快速理解到熟练运用

    目录  一、原理 1. 引例:207.课程表  2. 应用场景 3. 代码思路 二、代码模板 三、练习 1、210.课程表Ⅱ🟢 2、2392.给定条件下构造举证🟡 3、310.最小高度树🟡 4、 2603.收集树中金币 🔴 1. 引例:207.课程表 就如大学课程安排一样,如果要学习数据结构与算法、机器学习这类课程

    2024年02月11日
    浏览(30)
  • 17.4:图的拓扑排序

    拓扑序一定是有向无环图。 拓扑排序不唯一 利用入度为零进行排序 思路:谁的入度为0,谁就是开始节点,将开始节点打印完之后,将开始节点的直接邻居的入度减1,然后重复。 利用点次进行排序。 点次越大的,排序位置越靠前。 而且我发现可以使用递归进行求点次。我

    2024年02月07日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包