用C++代码实现拓扑排序template <typename T, typename WGT_T> std::vector<typename std::graf<T, WGT_T>::size_type> topsort(const std::graf<T, WGT_T>& g)
时间: 2023-09-23 20:05:53 浏览: 179
### 回答1:
以下是用C++代码实现拓扑排序的函数:
```c++
template <typename T, typename WGT_T>
std::vector<typename std::graf<T, WGT_T>::size_type> topsort(const std::graf<T, WGT_T>& g) {
std::vector<typename std::graf<T, WGT_T>::size_type> order;
std::queue<typename std::graf<T, WGT_T>::size_type> q;
std::vector<typename std::graf<T, WGT_T>::size_type> in_degree(g.num_vertices(), 0);
for (typename std::graf<T, WGT_T>::size_type i = 0; i < g.num_vertices(); ++i) {
for (auto& e : g.adj_list(i)) {
++in_degree[e.to()];
}
}
for (typename std::graf<T, WGT_T>::size_type i = 0; i < g.num_vertices(); ++i) {
if (in_degree[i] == 0) {
q.push(i);
}
}
while (!q.empty()) {
typename std::graf<T, WGT_T>::size_type u = q.front();
q.pop();
order.push_back(u);
for (auto& e : g.adj_list(u)) {
--in_degree[e.to()];
if (in_degree[e.to()] == 0) {
q.push(e.to());
}
}
}
return order;
}
```
该函数的输入参数为一个有向图 `g`,返回值为一个顶点序列,表示拓扑排序后的顶点访问顺序。算法思路如下:
1. 统计每个顶点的入度。遍历每个顶点的邻接表,将邻接表中每个顶点的入度加1。
2. 将所有入度为0的顶点入队列。
3. 取出队列的第一个顶点,并将其加入拓扑排序结果序列中。
4. 遍历该顶点的邻接表,将邻接表中每个顶点的入度减1。如果减完之后某个顶点的入度变为0,则将该顶点入队列。
5. 重复步骤3和4,直到队列为空。
时间复杂度为 $O(V+E)$,其中 $V$ 是顶点数,$E$ 是边数。
### 回答2:
拓扑排序是一种用于有向图的算法,将图中的顶点按照一种线性顺序进行排序。在拓扑排序中,如果图中存在从顶点 A 到顶点 B 的有向边,那么在排序结果中,顶点 A 一定在顶点 B 之前。
下面是用 C++ 代码实现拓扑排序的示例:
```cpp
#include <iostream>
#include <vector>
#include <queue>
template <typename T>
std::vector<T> topsort(const std::vector<std::vector<T>>& graph) {
std::vector<T> sortedResult;
std::vector<int> inDegree(graph.size(), 0);
std::queue<T> zeroInDegreeQueue;
// 计算每个顶点的入度
for (const auto& adjacentNodes : graph) {
for (const auto& node : adjacentNodes) {
inDegree[node]++;
}
}
// 将入度为 0 的顶点加入队列
for (int i = 0; i < inDegree.size(); i++) {
if (inDegree[i] == 0) {
zeroInDegreeQueue.push(i);
}
}
// 拓扑排序主循环
while (!zeroInDegreeQueue.empty()) {
T currentNode = zeroInDegreeQueue.front();
zeroInDegreeQueue.pop();
sortedResult.push_back(currentNode);
// 将所有与当前顶点相邻的顶点入度减 1
for (const auto& node : graph[currentNode]) {
inDegree[node]--;
// 如果某个顶点的入度降为 0,则将其加入队列
if (inDegree[node] == 0) {
zeroInDegreeQueue.push(node);
}
}
}
// 如果排序后的结果包含图中所有顶点,则返回排序结果,否则返回空数组表示有环
if (sortedResult.size() == graph.size()) {
return sortedResult;
} else {
return std::vector<T>();
}
}
int main() {
// 创建一个有向图
std::vector<std::vector<int>> graph = {
{1, 2}, // 0 -> 1, 0 -> 2
{2, 3}, // 1 -> 2, 1 -> 3
{3}, // 2 -> 3
{4}, // 3 -> 4
{5}, // 4 -> 5
{5} // 5 -> 5 (自环)
};
// 调用拓扑排序函数
std::vector<int> sortedResult = topsort(graph);
// 输出排序结果
if (sortedResult.empty()) {
std::cout << "The graph contains a cycle." << std::endl;
} else {
std::cout << "Topological Sort Result:";
for (const auto& node : sortedResult) {
std::cout << " " << node;
}
std::cout << std::endl;
}
return 0;
}
```
以上代码使用邻接表表示有向图,并使用队列实现拓扑排序算法。首先计算每个顶点的入度,将入度为 0 的顶点加入队列,并在主循环中不断处理队列中的顶点,将其邻接顶点的入度减 1。最后,如果排序后的顶点数与图中的顶点数相同,则返回排序结果;否则,说明存在环,返回空数组。
示例中的有向图中包含了一个自环(5 -> 5),即一个顶点指向自己。因为拓扑排序要求没有环,所以自环会导致拓扑排序无法进行,最后的结果会返回一个空数组。
### 回答3:
拓扑排序是一种用于有向无环图(DAG)的排序算法。在拓扑排序中,将图中的节点按照一种线性顺序进行排序,使得对于任意的边 (u, v),节点 u 在节点 v 之前。
下面是C++代码实现拓扑排序的模板函数:
```cpp
template <typename T, typename WGT_T>
std::vector<typename std::graf<T, WGT_T>::size_type> topsort(const std::graf<T, WGT_T>& g) {
std::vector<typename std::graf<T, WGT_T>::size_type> result; // 存储拓扑排序的结果
std::queue<typename std::graf<T, WGT_T>::size_type> q; // 存储入度为0的节点
// 统计每个节点的入度
std::vector<typename std::graf<T, WGT_T>::size_type> in_degree(g.num_vertices(), 0);
for (typename std::graf<T, WGT_T>::size_type u = 0; u < g.num_vertices(); ++u) {
for (auto v : g.adjacency_list(u)) {
++in_degree[v];
}
}
// 将入度为0的节点入队列
for (typename std::graf<T, WGT_T>::size_type u = 0; u < g.num_vertices(); ++u) {
if (in_degree[u] == 0) {
q.push(u);
}
}
// 循环处理入度为0的节点
while (!q.empty()) {
typename std::graf<T, WGT_T>::size_type u = q.front();
q.pop();
result.push_back(u);
// 将所有u指向的节点的入度减1,并将入度减为0的节点入队列
for (auto v : g.adjacency_list(u)) {
--in_degree[v];
if (in_degree[v] == 0) {
q.push(v);
}
}
}
// 如果结果集合的大小不等于节点的数量,则说明图中存在环路
if (result.size() != g.num_vertices()) {
result.clear(); // 清空结果
throw std::runtime_error("Graph contains a cycle");
}
return result;
}
```
这个函数使用了队列来存储入度为0的节点。首先,统计每个节点的入度,然后将入度为0的节点入队列。然后,循环处理队列中的节点,将结果放入拓扑排序的结果集合中,并将所有从该节点出发的边的终点的入度减1。如果结果集合的大小不等于节点的数量,则说明图中存在环路,此时会抛出一个异常。
这个函数的时间复杂度是O(V + E),其中V是节点的数量,E是边的数量。
阅读全文