您的位置:首页 > 其它

拓扑排序

2015-07-11 23:10 225 查看
  在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序(Topological sorting)。

  1)每个顶点出现且只出现一次;

  2)若A在序列中排在B的前面,则在图中不存在从B到A的路径。

也可以定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得如果存在一条从顶点A到顶点B的路径,那么在排序中B出现在A的后面。



  什么地方会用到拓扑排序呢?比如在存在着前后依赖关系的情况下,整个工程中,有些子工程(活动)必须在其它有关子工程完成之后才能开始,也就是说,一个子工程的开始是以它的所有前序子工程的结束为先决条件的,但有些子工程没有先决条件,可以安排在任何时间开始。

  举个例子:学习《数据结构》课程就必须安排在学完它的两门先修课程《离散数学》和《算法语言》之后。学习《高等数学》课程则可以随时安排,因为它是基础课程,没有先修课。

  拓扑排序是对于有向无环图而言的(DAG),就是对于这个图所有的点(V1, V2, … Vn)找到一个点序列使得任意边(u, v), u出现在v的前面。很容易证明,如果一个有向图中有环那么不存在拓扑排序。

  1)从 DAG 图中选择一个 没有前驱(即入度为0)的顶点并输出。

  2)从图中删除该顶点和所有以它为起点的有向边。

  3)重复 1 和 2 直到当前的 DAG 图为空或当前图中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。









……

复杂度分析:

§Initialize In-Degree array:

O(|E|)

§Find vertex with in-degree 0:

|V| vertices, each takes O(|V|) to search In-Degree array.

Total time = O(|V|^2)

§Reduce In-Degree of all vertices adjacent to a vertex:

O(|E|)

§Output and mark vertex:

O(|V|)

Total time = O(|V|^2 + |E|) Quadratic time!

Kahn算法:



Total time = O(|V| + |E|)

#include <iostream>
#include <list>
#include <queue>
#include <vector>
using namespace std;
class Graph{
int V; //定点数
list<int>* adj; //邻接表数组指针
public:
Graph(int v);
void AddEdge(int v, int w);
int GetVecNum();
list<int>* GetAdj();
};

Graph::Graph(int v):V(v){
adj = new list<int>[v];
};
void Graph::AddEdge(int v, int w){
adj[v].push_back(w);
}

int Graph::GetVecNum(){
return V;
}

list<int>*  Graph::GetAdj(){
return adj;
}

const int V = 6;
queue<int> zeroInDegreesQueue;
int inDegrees[V];
vector<int> resultVec;

void InitZeroIndegreeQueue(Graph& graph){
list<int>* adj = graph.GetAdj();
for(int i=0; i<graph.GetVecNum(); i++){
for (list<int>::iterator it=adj[i].begin(); it != adj[i].end(); ++it)
inDegrees[*it]++;
}
for(int i=0; i<graph.GetVecNum(); i++){
if(inDegrees[i] == 0)
zeroInDegreesQueue.push(i);
}
}

void KahnTopologicalSort(Graph& graph){
int item;
int vecNum = 0;
list<int>* adj = graph.GetAdj();

while(!zeroInDegreesQueue.empty()){
resultVec.push_back(item = zeroInDegreesQueue.front());
zeroInDegreesQueue.pop();
vecNum++;
for (list<int>::iterator it=adj[item].begin(); it != adj[item].end(); ++it){
if(--inDegrees[*it] == 0)
zeroInDegreesQueue.push(*it);
}
}

if(vecNum < graph.GetVecNum())
cout<<"There is a cycle!\n";
}

void printResult(int i){
cout << ' ' << i;
}

int _tmain(int argc, _TCHAR* argv[])
{
Graph g(V);
g.AddEdge(5, 2);
g.AddEdge(5, 0);
g.AddEdge(4, 0);
g.AddEdge(4, 1);
g.AddEdge(2, 3);
g.AddEdge(3, 1);

cout << "Following is a KahnTopological Sort of the given graph \n";

InitZeroIndegreeQueue(g);
KahnTopologicalSort(g);

for_each(resultVec.begin(),resultVec.end(),printResult);

return 0;
}


DFS:

  深度优先方法,其实可看做逆向的方法,找到没有出度的点,通过递归逆推。

L ← Empty list that will contain the sorted nodes

S ← Set of all nodes with no outgoing edges

for each node n in S do

  visit(n)

function visit(node n)

  if n has not been visited yet then

  mark n as visited

  for each node m with an edge from m to n do

   visit(m)

  add n to L

// A recursive function used by topologicalSort
void Graph::topologicalSortUtil(int v, bool visited[], stack<int> &Stack)
{
// Mark the current node as visited.
visited[v] = true;

// Recur for all the vertices adjacent to this vertex
list<int>::iterator i;
for (i = adj[v].begin(); i != adj[v].end(); ++i)
if (!visited[*i])
topologicalSortUtil(*i, visited, Stack);

// Push current vertex to stack which stores result
Stack.push(v);
}

// The function to do Topological Sort. It uses recursive topologicalSortUtil()
void Graph::topologicalSort()
{
stack<int> Stack;

// Mark all the vertices as not visited
bool *visited = new bool[V];
for (int i = 0; i < V; i++)
visited[i] = false;

// Call the recursive helper function to store Topological Sort
// starting from all vertices one by one
for (int i = 0; i < V; i++)
if (visited[i] == false)
topologicalSortUtil(i, visited, Stack);

// Print contents of stack
while (Stack.empty() == false)
{
cout << Stack.top() << " ";
Stack.pop();
}
}

// Driver program to test above functions
int main()
{
// Create a graph given in the above diagram
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);

cout << "Following is a Topological Sort of the given graph \n";
g.topologicalSort();

return 0;
}


参考:

https://zh.wikipedia.org/wiki/%E6%8B%93%E6%92%B2%E6%8E%92%E5%BA%8F

http://www.ivy-end.com/archives/992
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: