拓扑排序(DFS和BFS及判断是否有环)

拓扑排序通过解决谁先谁后的问题,实现有向无环图的排序。本文探讨了使用DFS和BFS两种方法进行拓扑排序,并详细解释了在无环和有环情况下如何进行操作。对于DFS,通过递归处理有向边,判断有环时增加状态标识。而BFS则从入度为0的节点开始,逐步减少相邻节点的入度,以此判断有环情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拓扑排序其实还是挺奇妙的,就是解决谁先谁后的问题,solve contradictions and make the world peaceful接下来就探讨一下拓扑排序的两种实现方法。

一(DFS):

1.(无环)

我们给定一个有向无环图:
在这里插入图片描述
DFS是从一个点不断往下递归,比如说从序号1往下递归,有箭头就一直往下进行,直到到了最后一个元素,就开始往栈里(当然也可以是vector之类的,只不过需要反向再输出)push元素。比如说上面的从序号1开始,到序号2,序号3,序号4,到尽头了,就把4push进栈中,3push进栈,这个时候由于5也是2的下一个元素,所以5push进栈中,2push进栈,1push进栈,然后输出就是1 2 5 3 4.
当然这个递归的顺序是与你输入的顺序有关的,不过思路都是这样的,由起始点向下递归。
所以说dfs的代码还是比较简单的:

#include <bits/stdc++.h> 
const int inf=0x3f3f3f3f;
using namespace std;
bool vis[1001];
vector<int>G[1002];   //邻接表
vector<int>ans;
void dfs(int x)
{
   
    int i,v;
    vis[x]=1;
    for(i=0;i<G[x].size();i++)
    {
   
        v=G[x][i];
        if(!vis[v])
        {
   
            vis[v]=1;
            dfs(v);
        }
    }
    ans.push_back(x);             //这一层完毕才把它自己扔进去。
}
int main()
{
   
    int n,m,i,A,B;
    cin>>n>>
### 拓扑排序在有向无图中的实现 #### 使用DFS实现拓扑排序 对于有向无(DAG),通过深度优先搜索(DFS)来执行拓扑排序是一种常见的方式。当访问某个节点时,会递归地先访问其所有未被访问过的邻居节点,在回溯过程中记录下当前节点。 ```cpp void DFSVisit(const Graph& G, int u, vector<bool>& visited, list<int>& topoOrder) { visited[u] = true; for (int v : adjacencyList[u]) { if (!visited[v]) DFSVisit(G, v, visited, topoOrder); } // 记录顶点顺序(逆序) topoOrder.push_front(u + 1); } list<int> TopologicalSort_DFS(const Graph& G) { vector<bool> visited(G.n, false); list<int> topoOrder; for (int i = 0; i < G.n; ++i) { if (!visited[i]) DFSVisit(G, i, visited, topoOrder); } return topoOrder; } ``` 这种方法利用了栈结构特性——最后进入的元素最先出来(LIFO),因此可以在每次完成子树遍历之后立即将根结点加入到结果列表中[^1]。 #### 使用BFS实现拓扑排序(Kahn算法) 广度优先搜索(BFS)也可以用来做拓扑排序,这通常被称为Kahn算法。该方法基于入度的概念:只有那些没有任何前置条件的任务才能被执行。具体来说就是找到所有入度为零的节点作为起始点,并将其移除后更新其他节点的入度值,重复此操作直至处理完所有的节点为止。 ```cpp vector<int> TopologicalSort_BFS(const Graph& G) { queue<int> q; vector<int> indegree(G.n, 0); // 初始化各节点的入度 for (auto adjVertices : adjacencyList) for (int dest : adjVertices) indegree[dest]++; // 将所有入度为0的节点放入队列 for (size_t i = 0; i < indegree.size(); ++i) if (indegree[i] == 0) q.push(i); vector<int> result; while (!q.empty()) { int currentVertex = q.front(); q.pop(); result.push_back(currentVertex + 1); for (int neighbor : adjacencyList[currentVertex]) { --indegree[neighbor]; if (indegree[neighbor] == 0) q.push(neighbor); } } // 如果存在,则无法完全排序 if (result.size() != G.n) throw runtime_error("Graph has at least one cycle"); return result; } ``` 这里采用了一个先进先出(FIFO)的数据结构`queue`,每当遇到一个新的入度降为0的节点就立即处理它并继续寻找新的候选者[^2]. #### 方法比较 两种方式各有优劣: - **时间复杂度**:两者都是O(V+E),其中V表示顶点数量,E代表边的数量. - **空间消耗**:由于都需要额外的空间存储已访问状态以及最终的结果序列,BFS可能还需要更多的辅助数组用于保存各个节点的入度信息。 - **适用场景**: - 当希望按照自然逻辑顺序构建解决方案时可以选择DFS版本; - 对于大规模稀疏网络而言,Khan's Algorithm即BFS更易于理解实现,而且更容易扩展以支持动态变化的情况.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值