查看原文:http://www.wyblog.cn/2016/12/05/%e6%8b%93%e6%89%91%e6%8e%92%e5%ba%8f%e7%ae%97%e6%b3%95%e5%ae%9e%e7%8e%b0/
拓扑排序,是将一个有向无环图DAG中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。具体可参考百科。 我这里算法核心思想是先用邻接表实现一个DAG图,同时计算图里所有顶点的入度。首先将度为零的顶点全部入队列,然后不断从队列里弹出入度为0的顶点,再把与这个顶点邻接的所有定点给加入队列,直到最后队列为空。这里要注意的是要设置一个counter变量计数,用来检查生成的图是否存在环。 算法思想纯参考《数据结构与算法》这本书里的伪代码。 具体实现如下:
#include<cstdio>
#include<iostream>
#include<queue>
#define MAX_VERTEX_NUM 100
#define Vertextype int
using namespace std;
typedef struct ArcNode //邻接表里的邻接点
{
int adjVertex;
ArcNode *nextEdgeNode;
}ArcNode;
typedef struct VerNode //DAG图顶点
{
int indeed;
Vertextype data;
ArcNode *firstedge;
}VerNode;
typedef struct Graph
{
VerNode verNode[MAX_VERTEX_NUM];
int vertex_num,edge_num;
}Graph;
void CreateDAG(Graph &G,int n,int e)
{
int i,j,k;
G.vertex_num=n;
G.edge_num=e;
for(i=1;i<=n;i++) //初始化所有顶点
{
cin>>G.verNode[i].data;
G.verNode[i].firstedge=NULL;
G.verNode[i].indeed=0;
}
for(k=1;k<=e;k++)
{
ArcNode *p;
p=new ArcNode;
cin>>i>>j;
p->adjVertex=j;
p->nextEdgeNode=G.verNode[i].firstedge; //头部插入
G.verNode[i].firstedge=p;
G.verNode[j].indeed+=1; //入度计算
}
}
void Topsort(Graph &G)
{
int i;
queue<VerNode> Q;
int counter=0;
VerNode V;
ArcNode *w;
for(i=1;i<=G.vertex_num;i++)
if(G.verNode[i].indeed==0)
Q.push(G.verNode[i]);
cout<<"The topsort is: ";
while(!Q.empty())
{
V=Q.front();Q.pop();
cout<<V.data<<" ";
counter++;
w=V.firstedge;
while(w)
{
G.verNode[w->adjVertex].indeed--;
if(G.verNode[w->adjVertex].indeed==0)
Q.push(G.verNode[w->adjVertex]);
w=w->nextEdgeNode;
}
}
if(counter<G.vertex_num)
cout<<"Graph has a cycle!"<<endl;
}
int main(void)
{
Graph G;
CreateDAG(G,7,12); //这里明确给出DAG含多少个顶点、多少条边
Topsort(G);
}
以下是vector容器实现的拓扑排序,程序精简了许多,参考自博客:
http://blog.csdn.net/lrgdongnan/article/details/51679781
#include <iostream>
#include <stack>
#include <vector>
#include <list>
using namespace std;
vector<list<int>> Adj; //邻接表
vector<int> inDegree; //保存每个节点的入度
stack<int> stk; //保存当前入度为0的节点编号
void CreatGraph()
{
int n, m, v1, v2;
cin >> n >> m;
Adj.assign(n, list<int>());
inDegree.assign(n, 0);
while (m--)
{
cin >> v1 >> v2;
Adj[v1].push_back(v2);
inDegree[v2]++;
}
for (int i = 0; i < n;i++)
if (inDegree[i] == 0) stk.push(i);
}
void tpSort()
{
vector<int> vec;
int v;
while (!stk.empty())
{
v = stk.top();
stk.pop();
//inDegree[v] = -1;
//遍历与节点v相连的节点
for (auto it = Adj[v].begin(); it != Adj[v].end(); it++)
{
inDegree[*it]--;
if (inDegree[*it] == 0) stk.push(*it);
}
//Adj[v].clear(); //本行可以省略,以提升程序效率
vec.push_back(v);
}
if (vec.size() != inDegree.size())
{
cout << "图中存在环路,不能进行拓扑排序!\n";
return;
}
for (auto item : vec)
cout << item << " ";
cout << endl;
}
int main()
{
CreatGraph();
tpSort();
system("pause");
return 0;
}