首页 > 其他分享 >拓扑排序

拓扑排序

时间:2023-06-13 15:35:31浏览次数:39  
标签:res 拓扑 入度 in0 排序 节点

定义

拓扑排序(Topological sorting)要解决的问题是给一个有向图的所有节点排序。

这里直接使用OI-Wiki中举的例子来说明:

我们可以拿大学选课的例子来描述这个过程,比如学习大学课程中有:单变量微积分,线性代数,离散数学概述,概率论与统计学概述,语言基础,算法导论,机器学习。当我们想要学习 算法导论 的时候,就必须先学会 离散数学概述 和 概率论与统计学概述,不然在课堂就会听的一脸懵逼。当然还有一个更加前的课程 单变量微积分。

这些课程就相当于几个顶点$u$, 顶点之间的有向边$(u,v)$就相当于学习课程的顺序。显然拓扑排序不是那么的麻烦,不然你是如何选出合适的学习顺序。下面将介绍如何将这个过程抽象出来,用算法来实现。

但是如果某一天排课的老师打瞌睡了,说想要学习 算法导论,还得先学 机器学习,而 机器学习 的前置课程又是 算法导论,然后你就一万脸懵逼了,我到底应该先学哪一个?当然我们在这里不考虑什么同时学几个课程的情况。在这里,算法导论 和 机器学习 间就出现了一个环,显然你现在没办法弄清楚你需要学什么了,于是你也没办法进行拓扑排序了。因而如果有向图中存在环路,那么我们就没办法进行拓扑排序了。

因此我们可以说在一个[[DAG(有向无环图)]]中,我们将图中顶点以线性方式排序,使得对于任意顶点$u$到$v$的有向边$(u, v)$,都有$u$在$v$的前面。

或者说给定一个DAG,如果$i$到$j$有边,则认为$j$依赖于$i$,如果$i$到$j$有路径,则称$j$间接依赖于$i$; 拓扑排序的目标是将所有节点排序,使得在前面的节点不能依赖于排在后面的节点。

bfs

拓扑排序有广度优先搜索(bfs)和深度优先搜索(dfs)两种实现方式,这里我们先讨论bfs。

利用bfs实现拓扑排序需要根据节点的入度

入度:有多少条边直接指向该节点

思路

  1. 起始时,将所有入度为$0$的点放入队列q_in0
  2. 将队首元素出队,出队序列就是我们要求的拓扑序,对当前弹出的节点ures.push_back(u),遍历u的所有出度,即遍历所有由u直接指向的节点v,递减节点v的入度;
  3. 如果节点v的入度变为0,将节点v入队;
  4. 循环2、3流程直到队列为空;

如果res最后恰好有$n$个节点,说明原图为DAGres中的节点序列即要求的拓扑序;否则说明图中存在环

代码实现

vector<vector<int>> graph;
int n = graph.size();
int in[n]; // 存储每个节点的入度

bool toposrot() {
    vector<int> res;
    queue<int> q_in0;
    for (int i = 0; i < n; ++i) {
        if (in[i] == 0) {
            q_in0.push(i);
        }
    }
    while (!q_in0.empty()) {
        int u = q_in0.front();
        q_in0.pop();
        res.push_back(u);
        for (auto v : graph[u]) {
            if (--in[v] == 0) {
                q_in0.push(v);
            }
        }
    }
    if (res.size() == n) {
        for (auto i : res) {
            cout << i << " ";
        }
        return true;
    }
    return false;
}

dfs

todo

标签:res,拓扑,入度,in0,排序,节点
From: https://www.cnblogs.com/zwyyy456/p/17477658.html

相关文章

  • 算法题:冒泡排序
    functionbubbleSort($arr){$len=count($arr);//获取要排序数组的长度for($i=0;$i<$len;$i++){//外层循环遍历整个数组for($j=0;$j<$len-$i-1;$j++){//内层循环用于比较相邻元素,次数随外层循环进行而减少if(......
  • 快速排序
    #include<stdio.h>#include<stdlib.h>#defineMAX1000intn=0;voidprintList(intlist[]){ inti; for(i=0;i<n;i++){ printf("%d",list[i]); } printf("\n");}intPartition(intlist[],int......
  • Educational Codeforces Round 9-C. The Smallest String Concatenation(字符串排序)
    原题链接C.TheSmallestStringConcatenationtimelimitpertestmemorylimitpertestinputoutputn strings a1, a2, ..., an.You'dliketoconcatenatethemtogetherinsomeordersuchthattheresultings......
  • 【算法基础】:(二)希尔排序
    java基础算法算法基础:开始回顾下基础算法中的经典排序算法希尔排序是插入排序的一种算法思想:希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至一时,整个文件恰被分成一组,算法便终止。重点是分组,然后排序......
  • 【算法基础】:(三)插入排序
    java基础算法算法基础:开始回顾下基础算法中的经典排序算法插入排序算法思想:一般也被称为直接插入排序。对于少量元素的排序,它是一个有效的算法。插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。在其实现过......
  • 【算法基础】:(四)选择排序
    java基础算法算法基础:开始回顾下基础算法中的经典排序算法选择排序是插入排序的一种算法思想:选择排序在开始的时候,先扫描整个列表,以找到列表中的最小元素,然后将这个元素与第一个元素进行交换。这样最小元素就放到它的最终位置上。然后,从第二个元素开始扫描,找到n-1个元素中的最小......
  • Oracle的分组排序功能实现最大值一列数据获取
    需求:按某列的最大值取整行数据。 select<includerefid="ALL_COLUMNS"/>from(select<includerefid="ALL_COLUMNS"/>,ROW_NUMBER()OVER(ORDERBYTOKEN_RATEDESC)ASrnfrom<includerefid="......
  • 排序
    1、基本概念1、稳定排序:a==b,a本来在b前面,排序结束a仍然在b前面2、非稳定排序:a==b,a原本在b前面,排序结束b在a前面3、原地排序:排序过程中不申请新的空间4、非原地排序:需要利用额外的数组来辅助排序2、排序算法1、选择排序voidSelectsort(inta[],int......
  • 排序
    #include<stdio.h>#include<stdlib.h>#defineMAX1000voidprintList(intlist[],intn){ inti; for(i=0;i<n;i++){ printf("%d",list[i]); } printf("\n");}voidheapAdjust(intlist[],intu,intv){......
  • 根据已有链表中的元素进行排序
    思想为先将链表中的每一个节点映射到一个链表节点为变量的数组里,在根据节点的元素进行排序,本程序为ave,过程中将数组变量排序,最后重新生成链voidpaixu(LinkListhead)//从大到小{intlength=len(head),i=0,j=0,sum1[length],n1;LinkListsum[length];LinkListpa=hea......