拓扑排序

来源:互联网 发布:阿儿法营创意编程网址 编辑:程序博客网 时间:2024/06/18 14:33

基本概念:

      拓扑排序是对有向无圈图的顶点的一种排序,若一条路径是从vi到vj,那么在排序序列中vj出现在vi后面。显然,如果图含有圈,那么拓扑排序是不可能的,比如对于圈上的两个顶点v和w,v在w之前同时w又在v之前,在排序中是矛盾的。另外,拓扑排序不是唯一的,比如下面一张图的拓扑排序可以是v1,v2,v5,v4,v3,v7,v6或者v1,v2,v5,v4,v7,v3,v6。


算法设计:

1.简单的拓扑排序

      基本思路:找出任意一个没有入边的顶点,然后显示该顶点,并将它和它的边从图中一起删除。然后对图的其余部分应用同样的方法。
      具体细节实现:
      ①把顶点v的入度定义为边(u,v)的条数。
      ②计算图中所有顶点的入度,保存在数组Indegree中。
      ③图被读入一个邻接表中。
      下面是代码实现,测试数据是上图中的顶点:
#include <iostream>#include <vector>#include <cstdlib>using namespace std;const int MaxSize = 20;struct ArcNode{int adjvex;ArcNode* next;};//头单元数组template<class Type>struct VertexNode{Type vertex;ArcNode* firstedge;};template<class Type>class Graph{private:VertexNode<Type> adjlist[MaxSize];int vertexNum, arcNum;Type vertex[MaxSize];int Indegree[MaxSize];public:Graph(){Type v;int i, j;vertexNum = 0;arcNum = 0;cout << "please input the nodes:" << endl;while (cin >> v){adjlist[vertexNum].vertex = v;adjlist[vertexNum].firstedge = NULL;vertex[vertexNum] = v;Indegree[vertexNum] = 0;vertexNum++;}cin.clear();cout << "please input the edges:" << endl;Type a, b;while (cin >> a >> b){findNode(a, b, i, j);Indegree[j]++;//计算各顶点的入度ArcNode* s = new ArcNode;s->adjvex = j;s->next = adjlist[i].firstedge;adjlist[i].firstedge = s;arcNum++;}cin.clear();}void findNode(Type a, Type b, int& i, int& j){for (int k = 0; k < vertexNum; k++){if (vertex[k] == a)i = k;if (vertex[k] == b)j = k;}}void TopSort(){int counter;Type V, W;int Index;for (counter = 0; counter < vertexNum; counter++){Index = FindNewVertexOfIndegreeZero();if (Index == -1){cout << "Graph has a cycle!" << endl;exit(1);}cout << vertex[Index] << " "<<flush;for (ArcNode* p = adjlist[Index].firstedge; p != NULL; p = p->next){Indegree[p->adjvex]--;}}}int FindNewVertexOfIndegreeZero(){for (int i = 0; i < vertexNum; i++){if (Indegree[i] == 0){Indegree[i] = -1;//取出该顶点,下次不再考虑return i;}}return -1;}};int main(){Graph<char> g;g.TopSort();cout << endl;return 0;}
       效率分析:函数FindNewVertexOfIndegreeZero扫描Indegree数组,寻找一个尚未被分配拓扑编号的入度是0的顶点。如果返回-1则表示这样的顶点不存在,也就意味着该图有圈。因为FindNewVertexOfIndegreeZero函数是对Indegree数组的简单顺序扫描,若以每次要花费O(|V|)的时间。由于有|V|次的这样的调用,所以该算法的运行时间为O(V^2)。
      测试结果:


2.改进的拓扑排序

       上述算法运行时间长的原因在于对Indegree数组的顺序扫描。如果图是稀疏的,那么在每次迭代期间只有一些顶点的入度被更新,但是,尽管只有一小部分发生了变化,但是在搜索入度为0的顶点时潜在地查看了所有的顶点。
      解决方法:使用一个队列,首先,对每一个顶点计算入度,将所有入度为0的顶点放入一个空的队列中。当队列不空时,删除一个顶点v,并将和v邻接的顶点的入度减1,只要有一个顶点的入度降为0,就把该顶点放入队列中。此时,拓扑排序就是顶点出队的顺序。
      下面是代码实现,测试数据 同上:
#include <iostream>#include <queue>#include <cstdlib>using namespace std;const int MaxSize = 20;struct ArcNode{int adjvex;ArcNode* next;};template<class Type>struct VertexNode{Type vertex;ArcNode* firstedge;};template<class Type>class Graph{private:VertexNode<Type> adjlist[MaxSize];int vertexNum, arcNum;Type vertex[MaxSize];int Indegree[MaxSize];public:Graph(){Type v;int i, j;vertexNum = 0;arcNum = 0;cout << "please input the nodes:" << endl;while (cin >> v){adjlist[vertexNum].vertex = v;adjlist[vertexNum].firstedge = NULL;vertex[vertexNum] = v;Indegree[vertexNum] = 0;vertexNum++;}cin.clear();cout << "please input the edges:" << endl;Type a, b;while (cin >> a >> b){findNode(a, b, i, j);Indegree[j]++;//计算各顶点的入度ArcNode* s = new ArcNode;s->adjvex = j;s->next = adjlist[i].firstedge;adjlist[i].firstedge = s;arcNum++;}cin.clear();}void findNode(Type a, Type b, int& i, int& j){for (int k = 0; k < vertexNum; k++){if (vertex[k] == a)i = k;if (vertex[k] == b)j = k;}}int findNode(Type a){for (int k = 0; k < vertexNum; k++){if (vertex[k] == a)return k;}}void TopSort(){queue<Type> q;int count = 0;int Index;int i;for (i = 0; i < vertexNum; i++){if (Indegree[i] == 0)q.push(vertex[i]);}while (!q.empty()){Type v = q.front();cout << v << " " << flush;q.pop();count++;Index = findNode(v);for (ArcNode* p = adjlist[Index].firstedge; p != NULL; p = p->next){if (--Indegree[p->adjvex]==0){q.push(vertex[p->adjvex]);}}}if (count != vertexNum){cout << "Graph has a cycle!" << endl;exit(1);}}};int main(){Graph<char> g;g.TopSort();cout << endl;return 0;}
      效率分析:如果使用邻接表,这个算法的运行时间为O(|E|+|V|),因为for循环对每条边最多执行一次,队列操作对每个顶点也是最多进行一次。
      测试结果:



      
      ps:整理自《数据结构与算法分析——C语言描述》
0 0
原创粉丝点击