Leetcode|BFS+DFS拓扑排序|210. 课程表 II

本文详细介绍了两种拓扑排序算法的实现,分别是基于BFS和DFS的方法。通过邻接矩阵和入度表构建图,然后进行遍历。BFS方法从入度为0的节点开始,逐步删除节点;DFS方法通过深度优先遍历,检查环路并按顺序压栈。这两种方法可以有效地应用于课程计划等依赖关系排序问题。

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

在这里插入图片描述

1 BFS拓扑排序

class Solution {
public:
    vector<vector<int>> edges;  // 邻接矩阵
    vector<int> indegree;       // 入度表
    vector<int> res;            
    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        indegree.resize(numCourses, 0);
        // 1.构造邻接矩阵 + 入度表
        for (auto edge : prerequisites) {
            edges[edge[1]].push_back(edge[0]);
            indegree[edge[0]]++;
        }
        // 2.遍历入度表,将入度=0的节点放入队列中,即图的最先驱节点
        queue<int> q;
        for (int i = 0; i < indegree.size(); i++) 
            if (indegree[i] == 0) q.push(i);
        // 3.从图的最先驱节点一步一步删除,出队,存入res,并遍历每个出队先驱节点的所有子节点,将子节点入度-1,若子节点入度=0,则入队
        while (!q.empty()) {
            int v = q.front(); q.pop();
            res.push_back(v);
            for (auto& subv : edges[v]) {
                indegree[subv]--;
                if (indegree[subv] == 0)
                    q.push(subv);
            }

        }
        // 4.若有环,则res通常比节点数小,比如三个节点成环,则res.size()==0 < 3
        if (res.size() == numCourses) return res;
        return {};
    }
};

在这里插入图片描述

2 DFS拓扑排序

在这里插入图片描述

class Solution {
public:
    vector<vector<int>> edges;  // 邻接矩阵
    vector<int> visited;        // 0-未搜索; 1-已访问; 2-已压栈
    vector<int> res;            // 最终结果
    stack<int> stk;             // 存放结果的栈,图的子节点先入栈,父节点后入栈
    bool vaild = true;          // 是否有环,若有环则直接退出

    void dfs(int v) {
        visited[v] = 1;         // 标记已访问,但不知道子节点是否已访问,故需先DFS访问所有子节点
        for (auto& subv : edges[v]) {   // DFS遍历所有子节点
            if (visited[subv] == 1) {   // 若某个子节点已访问,则存在环,直接退出遍历
                vaild = false;
                return;
            } else if (visited[subv] == 0) {  // 当且仅当子节点为<未搜索>状态时才进行DFS,若visited[subv] == 2则直接跳过即可
                dfs(subv);
                if (!vaild) return;           // 遍历完某个子节点及其孙子节点后发现有环则直接退出遍历
            }
        }
        visited[v] = 2;         // 所有子节点均已访问并压栈,此时标记当前节点为已压栈
        stk.push(v);
    }

    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);
        visited.resize(numCourses, 0);
        // 1.构建邻接矩阵
        for (auto& edge : prerequisites) 
            edges[edge[1]].push_back(edge[0]);
        // 2.从图中任意选取1个未搜索节点进行DFS (为什么是任意选取?因为只要该节点进行DFS后则对应所有子节点均会压栈,此时其他未搜索节点一定是其先驱节点)
        for (int i = 0; i < numCourses; i++) {
            if (visited[i] == 0) dfs(i);
            if (!vaild) return {};
        }
        // 3.将stack弹出变成程序需要的vector,若使用vector的reverse(vec.begin(), vec.end())也可节省空间
        while (!stk.empty()) {
            res.emplace_back(stk.top());
            stk.pop();
        }
        return res;
    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SL_World

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值