拓扑排序
问题描述
有如下插件间依赖关系:
- 插件1依赖于插件0
- 插件2依赖于插件0
- 插件3依赖于插件0
- 插件4依赖于插件1
- 插件5依赖于插件1
- 插件6依赖于插件2和插件3
- 插件7依赖于插件2和插件5
求一种插件加载队列,使得被依赖插件先于依赖插件加载。
解决方案
利用拓扑排序,根据插件间的两两依赖关系,得出合适的插件加载顺序。将插件看作节点,插件间的依赖关系看作两个插件节点之间的有向边,如插件A依赖于插件B,则有一条从B到A的有向边。据此,可得到一幅有向图。
由上述问题,可得有向图如下所示:
首先找出入度为0的节点,这说明该节点所代表的插件不依赖于其他插件。然后将其放入加载队列中并从图中去除,并把该节点所指节点的入度减一。再次循环遍历入度为0的节点,重复上述过程,直至所有入度为0的节点放入加载队列。
代码
#include <iostream>
#include <vector>
#include <list>
#include <queue>
using namespace std;
class Graph
{
private:
int m_numOfVertexs;
vector<list<int>> m_adjacency;
public:
Graph(int numOfVertexs) : m_numOfVertexs(numOfVertexs), m_adjacency(numOfVertexs, list<int>()) {}
void addEdge(int source, int target)
{
m_adjacency[source].push_back(target);
}
vector<int> topoSortByKahn() const
{
// 求每个节点的入度
vector<int> inDegrees(m_numOfVertexs, 0);
for (auto iter = m_adjacency.begin(); iter != m_adjacency.end(); iter++)
for (auto jter = iter->begin(); jter != iter->end(); jter++)
inDegrees[*jter]++;
// 将入度为零的节点入队
queue<int> cache;
for (int i = 0; i < inDegrees.size(); i++)
{
if (inDegrees[i] == 0)
cache.push(i);
}
// 宽度优先遍历
vector<int> result;
while (!cache.empty())
{
int vertexs = cache.front();
cache.pop();
result.push_back(vertexs);
for (auto iter = m_adjacency[vertexs].begin(); iter != m_adjacency[vertexs].end(); iter++)
{
inDegrees[*iter]--;
if (inDegrees[*iter] == 0)
cache.push(*iter);
}
}
return result;
}
};
int main()
{
Graph graph(8);
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(0, 3);
graph.addEdge(1, 4);
graph.addEdge(1, 5);
graph.addEdge(2, 6);
graph.addEdge(2, 7);
graph.addEdge(3, 6);
graph.addEdge(5, 7);
auto loadQueue = graph.topoSortByKahn();
for (int i = 0; i < loadQueue.size(); i++)
{
cout << loadQueue[i] << " ";
}
cout << endl; return 0;}