拓扑排序(Topological Sorting)

一、什么是拓扑排序

在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:

  1. 每个顶点出现且只出现一次。
  2. 若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。

有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。

例如,下面这个图:

它是一个 DAG 图,那么如何写出它的拓扑排序呢?这里说一种比较常用的方法:

  1. 从 DAG 图中选择一个 没有前驱(即入度为0)的顶点并输出。
  2. 从图中删除该顶点和所有以它为起点的有向边。
  3. 重复 1 和 2 直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。

于是,得到拓扑排序后的结果是 { 1, 2, 4, 3, 5 }。

通常,一个有向无环图可以有一个或多个拓扑排序序列。

二、拓扑排序的应用

拓扑排序通常用来“排序”具有依赖关系的任务。

比如,如果用一个DAG图来表示一个工程,其中每个顶点表示工程中的一个任务,用有向边

三、拓扑排序的实现

根据上面讲的方法,我们关键是要维护一个入度为0的顶点的集合

图的存储方式有两种:邻接矩阵和邻接表。这里我们采用邻接表来存储图,C++代码如下:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
#include<iostream>#include <list>#include <queue>using namespace std;

/************************类声明************************/class Graph{	int V;             // 顶点个数	list<int> *adj;    // 邻接表	queue<int> q;      // 维护一个入度为0的顶点的集合	int* indegree;     // 记录每个顶点的入度public:	Graph(int V);                   // 构造函数	~Graph();                       // 析构函数	void addEdge(int v, int w);     // 添加边	bool topological_sort();        // 拓扑排序};

/************************类定义************************/Graph::Graph(int V){	this->V = V;	adj = new list<int>[V];

indegree = new int[V];  // 入度全部初始化为0	for(int i=0; i<V; ++i)		indegree[i] = 0;}

Graph::~Graph(){	delete [] adj;	delete [] indegree;}

void Graph::addEdge(int v, int w){	adj[v].push_back(w); 	++indegree[w];}

bool Graph::topological_sort(){	for(int i=0; i<V; ++i)		if(indegree[i] == 0)			q.push(i);         // 将所有入度为0的顶点入队

int count = 0;             // 计数,记录当前已经输出的顶点数 	while(!q.empty())	{		int v = q.front();      // 从队列中取出一个顶点		q.pop();

cout << v << " ";      // 输出该顶点		++count;		// 将所有v指向的顶点的入度减1,并将入度减为0的顶点入栈		list<int>::iterator beg = adj[v].begin();		for( ; beg!=adj[v].end(); ++beg)			if(!(--indegree[*beg]))				q.push(*beg);   // 若入度为0,则入栈	}

if(count < V)		return false;           // 没有输出全部顶点,有向图中有回路	else		return true;            // 拓扑排序成功}

测试如下DAG图:

12345678910111213
int main(){	Graph g(6);   // 创建图	g.addEdge(5, 2);	g.addEdge(5, 0);	g.addEdge(4, 0);	g.addEdge(4, 1);	g.addEdge(2, 3);	g.addEdge(3, 1);

g.topological_sort();	return 0;}

输出结果是 4, 5, 2, 0, 3, 1。这是该图的拓扑排序序列之一。

每次在入度为0的集合中取顶点,并没有特殊的取出规则,随机取出也行,这里使用的queue。取顶点的顺序不同会得到不同的拓扑排序序列,当然前提是该图存在多个拓扑排序序列。

由于输出每个顶点的同时还要删除以它为起点的边,故上述拓扑排序的时间复杂度为O(V+E)O(V+E)。

(详情http://www.kuqin.com/shuoit/20160111/349954.html)

另外,拓扑排序还可以采用深度优先搜索(DFS)的思想来实现,详见《topological sorting via DFS》。

时间: 2024-08-03 05:31:03

拓扑排序(Topological Sorting)的相关文章

LeetCode编程训练 - 拓扑排序(Topological Sort)

拓扑排序基础 拓扑排序用于解决有向无环图(DAG,Directed Acyclic Graph)按依赖关系排线性序列问题,直白地说解决这样的问题:有一组数据,其中一些数据依赖其他,问能否按依赖关系排序(被依赖的排在前面),或给出排序结果. 最常用解决拓扑排序问题的方法是Kahn算法,步骤可以概括为: 1. 根据依赖关系,构建邻接矩阵或邻接表.入度数组 2. 取入度为0的数据(即不依赖其他数据的数据),根据邻接矩阵/邻接表依次减小依赖其的数据的入度 3. 判断减小后是否有新的入度为0的数据,继续进

python多重继承之拓扑排序

在python3中,所有类都是新式类(默认继承obj,具有super,mro方法),采用广度优先,即拓扑排序算法 在python2.7中,新式类和经典类并存,经典类采用深度优先算法,即纵向 super方法本质,不是单纯找父类,而是根据调用者的节点位置进行广度优先顺序来的 一.什么是拓扑排序 在图论中,拓扑排序(Topological Sorting) 是一个 有向无环图(DAG,Directed Acyclic Graph) 的所有顶点的线性序列.且该序列必须满足下面两个条件: 每个顶点出现且只

有向图算法之拓扑排序

拓扑排序的意思: 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前.通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列. 一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动(activity).在整个工程中,有些子工程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的

[知识点]拓扑排序

// 此博文为迁移而来,写于2015年2月24日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vspe.html 1.前言 在了解拓扑排序之前,我们先来看一道题目以更好的理解: 一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动(activity).在整个工程中,有些子工程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的结束为先决条件的,但有些子工程没有先决

拓扑排序算法原理以及完整的C代码实现

拓扑排序定义 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前.通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列.简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序. 基础知识 一个较大的工程往往被划分成许多子工程,我们把这些子工程称作活动(activity).在整个

白书 - 拓扑排序 及 关于递归、coding的一些思考

题目:有n个变量,m个二元组(u,v),表示变量u小于变量v.将所有变量从小到大排列,给出满足条件的一个. 思路:把"小于"关系看成有向边,得到一个有向图.任务就是把一个图的所有结点排序,使得每一条有向边(u,v)对应的 u 都排在 v 的前面.在图论中,这个问题称为拓扑排序topological sort.  不难发现:如果图中存在有向环,则不存在拓扑排序的解,反之则存在.我们把不包含有向环的有向图称为有向无环图(Directed Acyclic Graph,DAG). 以下是补充了

拓扑排序介绍

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

转:【拓扑排序详解】+【模板】

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

图论-拓扑排序

拓扑排序(Topological sort) 拓扑排序是对有向无环图(DAG)顶点的一种排序,它使得如果存在u, v的有向路径,那么满足序中u在v前.拓扑排序就是由一种偏序(partical order)得到的一个全序(称为拓扑有序).偏序满足自反性,反对称性,传递性的序. 拓扑排序的思路很简单,就是每次任意找一个入度为0的点输出,并把这个点以及与这个点相关的边删除,实际算法中,用一个队列实现. 算法: 1.把所有入度为0的点入队Q; 2.若队Q非空,则点u出队,输出u,否则转4; 3.把所有与

[LeetCode] 207. 课程表(拓扑排序,BFS)

题目 现在你总共有 n 门课需要选,记为?0?到?n-1. 在选修某些课程之前需要一些先修课程.?例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1] 给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习? 示例 1: 输入: 2, [[1,0]] 输出: true 解释:?总共有 2 门课程.学习课程 1 之前,你需要完成课程 0.所以这是可能的. 示例 2: 输入: 2, [[1,0],[0,1]] 输出: false 解释:?总共有 2 门课程