拓扑排序
最后更新于:2022-04-01 20:06:13
对一个**有向无环图**(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为**拓扑排序**。(摘抄自:[拓扑排序-百度百科](http://baike.baidu.com/link?url=LQa-nm5WHvlG9AFeR27hZOvYN3HCyfgyLZiVFzh6TfULibSs3QGawKSwR5_dzy58dN7fx6H56zGyfoGA57Z2fq))。
首先对于一个优先图需要先判断是否存在环,然后再进行拓扑排序操作。如何判断有向图是否存在环呢,参考:[有向图是否有环](http://blog.csdn.net/u012796139/article/details/49863539)。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-17_57b429234fa00.jpg)
**源代码**示例:
~~~
#include
#include
#include
#include
using namespace std;
class Digraph
{
public:
Digraph(size_t nvertax) : arr(nvertax), vertaxs(nvertax), edges(0) {}
void addEdge(size_t a, size_t b);
void removeEdge(size_t a, size_t b);
void addVertax(size_t v);
void removeVertax(size_t v);
Digraph reverse() const;
vector adj(size_t v) const;
void showAdj(size_t v) const;
void showDigraph() const;
size_t edge() const { return edges; }
size_t vertax() const { return vertaxs; }
size_t arrSize() const { return arr.size(); }
private:
vector> arr; // 邻接表
size_t vertaxs; // 顶点个数
size_t edges; // 边的个数
};
/// 使用深度优先遍历在有向图中寻找有向环
class DirectedCycle
{
public:
DirectedCycle(const Digraph &graph) : marked(graph.arrSize()), edgeto(graph.arrSize()), on_stack(graph.arrSize())
{
for (size_t i = 0; i < graph.arrSize(); i++)
marked[i] = on_stack[i] = false;
for (size_t i = 0; i < graph.arrSize(); i++)
{
if (!marked[i])
dfs(graph, i);
}
}
bool hasCycle() const { return !sta.empty(); }
stack cycle() const { return sta; }
private:
void dfs(const Digraph &graph, size_t v)
{
on_stack[v] = true;
marked[v] = true;
vector vec = graph.adj(v);
for (size_t i = 0; i < vec.size(); i++)
{
if (this->hasCycle())
return;
else if (!marked[vec[i]])
{
edgeto[vec[i]] = v;
dfs(graph, vec[i]);
}
else if (on_stack[vec[i]])
{
for (size_t x = v; x != vec[i]; x = edgeto[x])
sta.push(x);
sta.push(vec[i]);
sta.push(v);
}
}
on_stack[v] = false;
}
vector marked;
vector edgeto;
vector on_stack;
stack sta;
};
/// 有向图中基于深度优先遍历的顶点排序,保证图中没有有向环
class DepthFirstOrder
{
public:
DepthFirstOrder(const Digraph &graph) : marked(graph.arrSize())
{
for (size_t i = 0; i < marked.size(); i++)
marked[i] = false;
for (size_t i = 0; i < graph.arrSize(); i++)
{
if (!marked[i])
dfs(graph, i);
}
}
vector getPre() const { return pre; }
vector getPost() const { return post; }
stack getReversePost() const { return reverse_post; }
private:
void dfs(const Digraph &graph, size_t v)
{
marked[v] = true;
pre.push_back(v);
vector vec = graph.adj(v);
for (size_t i = 0; i < vec.size(); i++)
{
if (!marked[vec[i]])
dfs(graph, vec[i]);
}
post.push_back(v);
reverse_post.push(v);
}
vector marked;
vector pre; // 所有顶点的前序排列
vector post; // 所有顶点的后序排列
stack reverse_post; // 所有顶点的逆后序排列
};
/// 拓扑排序,借助于DepthFirstOrder来实现,保证图中没有环
class Topological
{
public:
Topological(const Digraph &graph)
{
DepthFirstOrder dfs(graph);
stack sta = dfs.getReversePost();
while (!sta.empty())
{
order.push_back(sta.top());
sta.pop();
}
}
vector getOrder() const { return order; }
private:
vector order; // 顶点的拓扑顺序
};
int main(void)
{
Digraph graph(13);
graph.addEdge(0, 1); graph.addEdge(0, 5); graph.addEdge(0, 6);
graph.addEdge(2, 0); graph.addEdge(2, 3);
graph.addEdge(3, 5);
graph.addEdge(5, 4);
graph.addEdge(6, 4); graph.addEdge(6, 9);
graph.addEdge(7, 6);
graph.addEdge(8, 7);
graph.addEdge(9, 10); graph.addEdge(9, 11); graph.addEdge(9, 12);
graph.addEdge(11, 12);
cout << graph.vertax() << endl;
cout << graph.edge() << endl;
graph.showDigraph();
cout << endl;
DirectedCycle cycle(graph);
stack sta;
if (cycle.hasCycle())
{
cout << "graph has cycle" << endl;
sta = cycle.cycle();
while (!sta.empty())
{
cout << sta.top() << " ";
sta.pop();
}
cout << endl;
}
else
cout << "graph hasn't cycle" << endl;
Topological topo(graph);
vector vec = topo.getOrder();
for (size_t i = 0; i < vec.size(); i++)
cout << vec[i] << " ";
cout << endl;
system("pause");
return 0;
}
void Digraph::addEdge(size_t a, size_t b)
{
if (!(a < vertax() && b < vertax()))
return;
arr[a].push_back(b);
edges++;
}
void Digraph::removeEdge(size_t a, size_t b)
{
if (!(a < vertax() && b < vertax()))
return;
vector::iterator iter = find(arr[a].begin(), arr[a].end(), b);
if (iter != arr[a].end())
{
arr[a].erase(iter);
edges--;
}
}
void Digraph::addVertax(size_t v)
{
if (v != arrSize())
return;
arr.push_back(vector());
vertaxs++;
}
void Digraph::removeVertax(size_t v)
{
if (v >= arrSize())
return;
vector::iterator iter;
for (size_t i = 0; i < arrSize(); i++)
{
if (i == v)
{
edges -= arr[i].size(); // 减去头部是v的边的个数
arr[i].clear();
vertaxs--;
}
else
{
iter = find(arr[i].begin(), arr[i].end(), v);
if (iter != arr[i].end())
{
arr[i].erase(iter);
edges--;
}
}
}
}
Digraph Digraph::reverse() const
{
Digraph graph(vertax());
vector vec;
for (size_t i = 0; i < arrSize(); i++)
{
vec = adj(i);
for (size_t j = 0; j < vec.size(); j++)
{
graph.addEdge(vec[j], i); // 取得该图的反向图
}
}
return graph;
}
vector Digraph::adj(size_t v) const
{
if (v < arrSize())
return arr[v];
else
vector();
}
void Digraph::showAdj(size_t v) const
{
if (v >= arrSize())
return;
vector vec = adj(v);
for (size_t i = 0; i < vec.size(); i++)
cout << vec[i] << " ";
cout << endl;
}
void Digraph::showDigraph() const
{
for (size_t i = 0; i < arr.size(); i++)
{
cout << i << ": ";
showAdj(i);
}
}
~~~
**参考资料**:
1、[https://github.com/luoxn28/algorithm_data_structure](https://github.com/luoxn28/algorithm_data_structure) (里面有常用的数据结构源代码,图相关算法在graph文件夹中)
2、《算法 第4版》 图有关章节
';