拓扑排序

来源:互联网 发布:淘宝买家秀网站 编辑:程序博客网 时间:2024/05/22 12:30

       对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

       一个最简单的例子就是我们的学习过程,我们的学习顺序是幼儿园-小学-中学-大学。当然我们在阅读一本书的时候也是这个样子的,特别是专业书,有时我们需要其他几本书的基础上才能读懂这本书。这就是先后后顺序,也是拓扑排序的主要思想。

       在图论中,能够进行拓扑排序的是有向无环图。这样的图才能够进行排序,因为每一个顶点出发后都不会回到自身,这样就满足了事情发展的顺序。也就是说我们不可能读完大学后在回去读幼儿园。

       为了形式化,我们需要求出每一个顶点的入度(indegree),用数组来储存结果(ex:下图顶点4的入度为3,indegree[4]=3),求出入度后就需要一个队列或者栈来存放入度为0的顶点,下面我们使用队列来讲解。首先我们找出入度为0的顶点,入队。接着出队,出的的顶点v指向的顶点(w0,w1,...)的入度减一,并检查这些顶点(w0,w1,...)的入度是否为零,是的话入队。接着出队,重复以上操作,知道队列为空。

下图拓扑顺序为:1->2->5->4->3->7->6




                                       

一.邻接表的拓扑 

               
                     
#include<iostream>#include<queue>using namespace std;const int NumVertex = 7;typedef struct Node {int index;struct Node *next;}Node;typedef struct VertexNode {int date;Node *firstarc;}VertexNode;typedef struct AGraph {VertexNode adjlist[NumVertex+1];int NumVertexs, NumEdges;}AGraph;void InPutEdge(AGraph &G, int v, int w) {//输入v指向w的边Node *p;if (!(p = (Node *)malloc(sizeof(Node))))cout << "FAILED MALLOC!" << endl;p->index = w;p->next = G.adjlist[v].firstarc;G.adjlist[v].firstarc = p;}void Create(AGraph &G) {int i;G.NumVertexs = NumVertex;G.NumEdges = 12;//初始化邻接表for (i = 1; i <= G.NumVertexs; ++i) {G.adjlist[i].date = i;G.adjlist[i].firstarc = NULL;}InPutEdge(G, 1, 2);InPutEdge(G, 1, 4); InPutEdge(G, 1, 3); InPutEdge(G, 2, 5); InPutEdge(G, 2, 4);InPutEdge(G, 3, 6);InPutEdge(G, 4, 3);InPutEdge(G, 4, 6);InPutEdge(G, 4, 7);InPutEdge(G, 5, 4);InPutEdge(G, 5, 7);InPutEdge(G, 7, 6);}void Set_Indegree(const AGraph &G,int indegree[]) {int i;//初始化indefree数组for (i = 0; i < G.NumVertexs; indegree[++i] = 0);Node *p;for (i = 1; i <= G.NumVertexs; ++i) {p = G.adjlist[i].firstarc;while (p) {++indegree[p->index];p = p->next;}}}void OutPutGraph(const AGraph &G) {//输出整个图Node *p;for (int i = 1; i <= G.NumVertexs; ++i) {p = G.adjlist[i].firstarc;if (!p)cout << "Vertex " << i << " point to none!" << endl;else {while (p) {cout << i << " -> " << p->index << endl;p = p->next;}}}}/*拓扑排序*/void TopoSort(const AGraph &G) {cout << "TopoSort:" << endl;queue<int> Q;int i, v;int counter = 0;Node *p;int indegree[NumVertex + 1];//用于存放各顶点的入度Set_Indegree(G, indegree);for (i = 1; i <= G.NumVertexs; ++i)//检查入度,入度为0的顶点入队if (indegree[i] == 0) {Q.push(i);--indegree[i];}while (!Q.empty()) {v = Q.front();Q.pop();++counter;cout << v << " ";//将v所指向的所有顶点的入度减一p = G.adjlist[v].firstarc;while (p) {//检查各顶点入度,为0入队if (--indegree[p->index] == 0) {--indegree[p->index];Q.push(p->index);}p = p->next;//指向顶点的下一条边}}if (counter < G.NumVertexs)cout << "Graph has a cycle!" << endl;}void main() {AGraph G;Create(G);OutPutGraph(G);TopoSort(G);system("pause");}

二.邻接矩阵的拓扑排序


#include<iostream>  #include<queue>using namespace std;const int MAX_NUM = 100;const int INF = 65536;template<typename node_name>class MGraph {public://初始化MGraph(int vertexs, int edge) :_vertexs(vertexs),                            _Edges(edge) {for (int i = 0; i < _vertexs; ++i)for (int j = 0; j < _vertexs; ++j)arcs[i][j] = INF;for (int i = 0; i < _vertexs; ++i)vertex[i] = i + 1;}void Create() {//创建图Set_Arc(1, 2);Set_Arc(1, 3); Set_Arc(1, 4);Set_Arc(2, 4);Set_Arc(2, 5);Set_Arc(3, 6);Set_Arc(4, 6);Set_Arc(4, 7);Set_Arc(4, 3);Set_Arc(5, 7);Set_Arc(5, 4);Set_Arc(7, 6);}void Print_Edge() {//输出每一条边for (int i = 0; i < _vertexs; ++i)for (int j = 0; j < _vertexs; ++j)if (arcs[i][j] == 1)cout << vertex[i] << "->" << vertex[j] <<  endl;}void TopoSort() {int i, tmp;queue<int> Q;int Indegree[7];for (i = -1; i < _vertexs - 1; Indegree[++i] = 0);Set_Indegree(Indegree);for (i = 0; i < _vertexs; ++i)//检查各点入度,为0入队if (Indegree[i] == 0) {Q.push(i);--Indegree[i];//减一保证这个顶点下次检查时不会被入队}while (!Q.empty()) {tmp = Q.front();Q.pop();cout << vertex[tmp] << " ";for (i = 0; i < _vertexs; ++i)//将出队的顶点指向的顶点的入度减一if (arcs[tmp][i] == 1)--Indegree[i];for (i = 0; i < _vertexs; ++i)//检查入度,同上if (Indegree[i] == 0) {Q.push(i);--Indegree[i];}}cout << endl;}private:void Set_Arc(int a, int b) {//设置a指向b的边arcs[a-1][b-1] = 1;}void Set_Indegree(int *indegree) {//生成入度for (int i = 0; i < _vertexs; ++i)for (int j = 0; j < _vertexs; ++j)if (arcs[i][j] == 1)++indegree[j];}private:int _vertexs;//节点数int _Edges;//边数node_name vertex[MAX_NUM];//顶点信息float arcs[MAX_NUM][MAX_NUM];//矩阵,用于存放权值};void main() {MGraph<int> G(7, 12);G.Create();G.Print_Edge();G.TopoSort();system("pause");}





               

0 0
原创粉丝点击