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

拓扑排序

时间:2023-06-16 11:47:15浏览次数:29  
标签:拓扑 入度 枚举 排序 节点 起点

先发个颠

  最近各种不好的事接踵而至,导致情绪波动很大,什么事情都专心不了,导致学业和算法上的学习都荒废了将近一周(要考试周了),还差点和班上同学吵架(已经和好了)。在休整了一段时间后,我幡然醒悟,因此,从这篇blog开始,我要重新拾起学业以及算法学习了(写完这篇就去复习大物,后天考。明天的六级应该是过不了了)。


前言

  前一个月一直在学习图论的相关知识,因此我决定在后面一段时间内慢慢介绍各种图论算法来巩固自己的图论知识(费曼学习法)。如果这些文章有幸能够帮助到你,我会很高兴的。

拓扑排序

介绍

  拓扑排序是一种对有向无环图(DAG)进行排序的算法。在拓扑排序中,图中的节点表示任务或事件,有向边表示任务间的依赖关系。拓扑排序的目标是找到一种排序方式,使得所有任务都能按照依赖关系的顺序被执行。

  拓扑排序是充要条件是有向无环图(DAG),因此我们还可以使用拓扑排序来判断图是否存在环路。

具体过程

  拓扑排序需要运用到点的入度和出度的概念。入度即为以该点作为终点的边的数量,出度即为以该点作为起始点的边的数量。当入度点为0时,即不存在以该点为终点的边,因此这个点就是起始点(注意,一张图可能同时存在多个起点和终点),枚举以这个点为起点的边,将各边终点的点的入度减一,若入度减为0,则说明不再存在以该点为终点的边,再按照刚才的方法枚举以这个点为起点的边,直到所有点的入度都为0。(若未枚举完图中所有点,则说明该图存在环路)。

如图所示,1到6每个点都有若干条有向边,每存在一条以 i 为终点的边,i 的入度就加一; 每存在一条以 i 为起点的边, i 的出度就加一。该图中点 1 与点 4 的入度均为 0,即这两个点都为起点,然后依次枚举以他们为起点的边,边的终点的入度减一, 此时发现点 2和点 3 的入度为0, 则再依次枚举以点 2 和点 3 为起点的边,直到最后枚举完所有点,按照这种方法得到的枚举顺序为1 4 2 3 5 6。

 

实现方法

 1 //存图
 2 vector<int> a[N];
 3 //入度
 4 int idn[N];
 5 //出度
 6 int out[N];
 7 vector<int> ans;
 8 void solve() {
 9     int n, m;
10     cin>>n>>m;
11     for (int i = 1; i <= m; i++) {
12         int u, v;
13         cin>>u>>v;
14         a[u].push_back(v);
15         idn[v]++;
16         out[u]++;
17     }
18     //将入度为0的点存入队列
19     queue<int> q;
20     for (int i = 1; i <= n; i++) {
21         if (idn[i] == 0) {
22             q.push(i);
23             ans.push_back(i);
24         }
25     }
26     while(!q.empty()) {
27         int u = q.front();
28         q.pop();
29         for (int i = 0; i < a[u].size(); i++) {
30             int v = a[u][i];
31             idn[v]--;
32             //入度减为零则将该点入队
33             if (idn[v] == 0) {
34                 q.push(v);
35                 ans.push_back(v);
36             }
37         }
38     }
39     //如果没有枚举完所有点,则说明存在环路
40     if (ans.size() != n) {
41         cout<<"存在环路";
42     } else {
43         for (int i = 0; i < ans.size(); i++) {
44             cout<<ans[i]<<" ";
45         }
46     }
47 }

总结

  拓扑排序的关键点是入度的概念。入度表示一个节点被其他节点所依赖的次数。在拓扑排序中,入度为0的节点表示没有任何依赖,可以作为排序的起点。通过不断删除入度为0的节点,并更新剩余节点的入度,最终可以得到一个拓扑有序的节点列表。

  需要注意的是,拓扑排序只适用于有向无环图,如果图中存在环路,则无法进行拓扑排序。因为环路表示存在循环依赖,无法确定任务的执行顺序。因此,在使用拓扑排序之前,需要先判断图是否是有向无环图。(如果是判断是否存在环路,可以直接使用拓扑排序进行判断)

 

标签:拓扑,入度,枚举,排序,节点,起点
From: https://www.cnblogs.com/tunecoming/p/17485177.html

相关文章

  • 防止Javascript重新排序JSON
    javascript中的对象为什么会按照键来自动排序?原因:javascript中的对象按照键来自动排序是浏览器造成的,经查V8的相关文档得出以下结论:Chrome浏览器下创建的js对象数组会自动按照键排序、FireFox99.0版本(最新版本)会,FireFox 4.0.1不会。 解决方法:必须将对象的键值转换为字符,......
  • C#对List的元素按属性排序
    C#对List元素排序有几种方法。方法一、使用LinqList<User>sortedList=list.OrderBy(o=>o.ID).ToList();如果按降序排序,可以使用OrderByDescending方法:List<User>sortedList=list.OrderByDescending(o=>o.ID).ToList();方法二、扩展IComparable接口示例:publiccl......
  • Kotlin 集合对象的单条件和多条件排序
    原文:Kotlin集合对象的单条件和多条件排序-Stars-One的杂货小窝本文不是太难的东西,因为sortedWith之前没怎么用过,所以就记录下平常开发经常使用到List,Map等数据集合类型,也会经常遇到排序的问题,可以直接使用sortedBy或sortedByDescending排序多条件则是使用sortedWith,......
  • mongo聚合字符串类型的数字进行排序
    设置collationCollationcollation=Collation.of(Locale.CHINESE).numericOrdering(true);设置聚合选项Aggregationaggregation=Aggregation.newAggregation(Aggregation.match(orOperator),).withOptions(AggregationO......
  • 数据结构和算法——二叉排序树
    一、二叉排序树对于无序的序列“62,58,88,47,73,99,35,51,93,29,37,49,56,36,48,50”,是否存在一种高效的查找方案,使得能够快速判断在序列中是否存在指定的数值?二叉排序树是一种简单,高效的数据结构。二叉排序树,又称为二叉查找树。二叉排序树或者是一棵空树,或者是具有以下性质的二叉树:若其左子树不为......
  • C/C++——排序
    在C/C++中的排序,使用到的函数主要有:sort()qsort()下面详细分析sort()函数和qsort()函数。1、sort()函数sort()是STL中提供的算法,头文件为:#include<algorithm>usingnamespacestd;函数原型如下:template<classRandomAccessIterator>voidsort(RandomAccessIteratorfirst,Ran......
  • JS排序:插入排序 冒泡排序 选择排序
    1.插入排序 1letarr=[30,5,7,60,22,18,29]2letfn=arr=>{3for(letj=1;j<arr.length;j++){4letcurrent=arr[j]5letpreIdx=j-16while(preIdx>=0&&arr[preIdx]>......
  • 快速排序以及 TopN 问题
    快速排序快速排序的划分函数1.firstelement划分2.medianofthreeelement划分快速排序的稳定性TopN问题Referencehttps://baobaobear.github.io/post/20191007-qsort-talk-1/......
  • C# 获取数组排序后的下标
    usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespaceConsoleApp9{classProgram{staticvoidMain(string[]args){int[]src=newint[]{2,1......
  • 算法面试:单向链表节点的奇偶排序。
    给定一个单项链表,要求实现一个算法,把链表分成两部分,前一部分全是下标为偶数的节点,后一部分全是下标为奇数的节点,例如给定链表为下图的第一个队列,要求编写一个算法,将链表转换为第二个队列:要求算法不能分配多余的内存,同时,在操作链表是,不能更改节点内部的内容,只能更改节点的next指针......