一、什么是拓扑排序
在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列。且该序列必须满足下面两个条件:
- 每个顶点出现且只出现一次。
- 若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说。
例如,下面这个图:
它是一个 DAG 图,那么如何写出它的拓扑排序呢?这里说一种比较常用的方法:
- 从 DAG 图中选择一个 没有前驱(即入度为0)的顶点并输出。
- 从图中删除该顶点和所有以它为起点的有向边。
- 重复 1 和 2 直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。
于是,得到拓扑排序后的结果是 { 1, 2, 4, 3, 5 }。
通常,一个有向无环图可以有一个或多个拓扑排序序列。
二、拓扑排序的应用
拓扑排序通常用来“排序”具有依赖关系的任务。
比如,如果用一个DAG图来表示一个工程,其中每个顶点表示工程中的一个任务,用有向边 <A,B> 表示在做任务 B 之前必须先完成任务 A。故在这个工程中,任意两个任务要么具有确定的先后关系,要么是没有关系,绝对不存在互相矛盾的关系(即环路)。
三、拓扑排序的实现
A、B、C、D、E 对应1、2、3、4、5
#include<iostream>
#include<vector>
#include<list>
#include<queue>
using namespace std;
typedef struct edge //边结构
{
int weight; //边权重
char adjver; //边指向的顶点
}edge;
typedef struct vertex
{
char ver; //顶点存放的元素
int rudu; //入度
list<edge> edgelis; //顶点发出边的链表
vertex() :rudu(0){}
}vertex;
typedef struct graph
{
int vertexNum; //图中顶点个数
vector<vertex> verlis; //图中顶点数组
vector<bool> vist; //辅助图的遍历
void init() //主要是对vist初始化
{
for (int i = 0; i < vertexNum; i++)
{
vist[i] = false;
verlis[i].ver = 'A' + i;
}
}
graph()
{
vertexNum = 0;
}
graph(int num) //构造函数
{
vertexNum = num;
verlis.resize(num);
vist.resize(num);
init(); //针对vist数组进行初始化
}
void addedge(char ver1, char ver2, int weight) //往图中添加边,记住建立的是有向图
{
edge temp1;
temp1.adjver = ver2;
temp1.weight = weight;
verlis[(ver1 - 'A')].edgelis.push_back(temp1);
verlis[(ver2 - 'A')].rudu++;
}
void TopSort()
{
for (int i = 0; i < verlis.size(); i++) //遍历所有顶点
{
if (verlis[i].rudu == 0) //顶点入度为0,则从图中删除
{
verlis[i].rudu = -1; //对其进行标识,避免重复访问
cout << verlis[i].ver << " ";
list<edge>::iterator it = verlis[i].edgelis.begin();
list<edge>::iterator end = verlis[i].edgelis.end();
for (; it != end; it++)
{
char temp = it->adjver;
verlis[(temp - 'A')].rudu--; //因为删除了节点,所以要把与之相连的节点的入度减1
}
i = 0; //图一旦更改,从头开始
}
}
}
}graph;
int main()
{
char input[7][2] = { { 'A', 'B' }, { 'A', 'D' }, { 'D', 'C' }, { 'B', 'D' }, { 'B', 'C' }, { 'C', 'E' }, { 'D', 'E' }};
graph g(5);
for (int i = 0; i < 7; i++)
{
g.addedge(input[i][0], input[i][1], 1);
}
g.TopSort();
cout << endl;
system("pause");
return 0;
}