首页 > 其他分享 >图——拓扑排序

图——拓扑排序

时间:2022-12-18 22:45:05浏览次数:33  
标签:info 拓扑 搜索 visited 排序 节点

拓扑排序定义

给定一个包含 n 个节点的有向图 G,我们给出它的节点编号的一种排列,如果满足:

对于图 G 中的任意一条有向边 (u, v),u 在排列中都出现在 v 的前面。

那么称该排列是图 G 的「拓扑排序」。

 

题目与解析

lc 210. 课程表 II

 

我们可以将本题建模成一个求拓扑排序的问题了:

我们将每一门课看成一个节点;

如果想要学习课程 A之前必须完成课程 B,那么我们从 B 到 A 连接一条有向边。这样以来,在拓扑排序中,B 一定出现在A的前面。

 

思路:

用一个栈来存储所有已经搜索完成的节点。我们对图进行一遍深度优先搜索。当每个节点进行回溯的时候,我们把该节点放入栈中。最终从栈顶到栈底的序列就是一种拓扑排序。

class Solution {
private:
    // 存储有向图
    vector<vector<int>> edges;
    // 标记每个节点的状态:0=未搜索,1=搜索中,2=已完成
    vector<int> visited;
    // 用数组来模拟栈,下标 0 为栈底,n-1 为栈顶
    vector<int> result;
    // 判断有向图中是否有环
    bool valid = true;

public:
    void dfs(int u) {
         // 将节点标记为「搜索中」
        visited[u] = 1;
        // 搜索其相邻节点
        // 只要发现有环,立刻停止搜索
        for (auto v: edges[u]) {
            // 如果「未搜索」那么搜索相邻节点
            if (visited[v] == 0) {
                dfs(v);
            }
            // 如果「搜索中」说明找到了环
            if (visited[v] == 1) {
                valid = false;
                return;
            }
        }
        // 将节点标记为「已完成」
        visited[u] = 2;
        // 将节点入栈
        result.push_back(u);
    }

    vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
        edges.resize(numCourses);  // 从每个节点出发的有向边
        visited.resize(numCourses);
        // 构建有向图
        for (const auto& info: prerequisites) {  //注意这里const auto& info的含义, 用和不用都能通过
            edges[info[1]].push_back(info[0]);  //从info[1]的节点指向info[0]的节点(可以有中间节点)
        }
        // 每次挑选一个「未搜索」的节点,开始进行深度优先搜索
        for (int i = 0; i < numCourses; i++) {
            if (!visited[i]) {
                dfs(i);
            }
        }

        if (!valid) {  // 有环
            return {};
        }

        // 如果没有环,那么就有拓扑排序
        // 注意下标 0 为栈底,因此需要将数组反序输出
        reverse(result.begin(), result.end());
        return result;
    }
};

  

 

 

参考链接:

https://leetcode.cn/problems/course-schedule-ii/solution/ke-cheng-biao-ii-by-leetcode-solution/

*题解中「相邻节点」指的是从 u 出发通过一条有向边可以到达的所有节点。

标签:info,拓扑,搜索,visited,排序,节点
From: https://www.cnblogs.com/spacerunnerZ/p/16990929.html

相关文章

  • 冒泡排序相关知识总结
    轮数表示冒泡排序外层循环的次数,次数表示交换次数。设排列为\(w\),冒泡排序的轮数为\(\max_{i=1}^{n}(i-w_i)\).因为如果\(i>w_i\),那么这个数每一轮会向目的地......
  • 【算法实践】手把手带你快速实现插入排序
    前言每学习一个新东西总要首先知道他是什么,能做什么,怎么做,类似于哲学中的三大问题:我是谁,从哪里来,要到哪里去。或许我们一直徘徊在哲学的迷思中,也许一直想不明白,但是在思考的......
  • 插入排序优化
    defselection_sort(alist):n=len(alist)#需要进行n-1次选择操作a=0foriinrange(n-1):#记录最小位置min_index=i......
  • #yyds干货盘点# LeetCode程序员面试金典:栈排序
    题目:栈排序。编写程序,对栈进行排序使最小元素位于栈顶。最多只能使用一个其他的临时栈存放数据,但不得将元素复制到别的数据结构(如数组)中。该栈支持如下操作:push、pop、peek......
  • golang标准库的排序算法---sort包(转载)
    sort——排序算法该包实现了四种基本排序算法:插入排序、归并排序、堆排序和快速排序。但是这四种排序方法是不公开的,它们只被用于sort包内部使用。所以在对数据集合排......
  • 案例:成绩排序 实现Comparable接口
    //先根据学生的成绩降序排序,如果成绩相同再根据年龄升序排序,如果年龄相同再根据名字升序排序publicclassScoreListimplementsComparable{privateStringname;pri......
  • Compareble自然排序器
    让元素所属的类实现Comparable接口,重写compareTo(Objecto)方法Collections调用sort方法即可按照规则排序publicintcompareTo(Objecto){Studentcurrent=......
  • Comparator选择排序器
    步骤1让元素所属的类实现Comparator接口2重写compare​(To1,To2)方法比较两个参数的顺序。3o1,o2是接收Compareator的实现类对象规则:o1-o2——>升序o2-o1——......
  • 快速排序
    时间开销:O(logn),空间开销:0(原地分治)importjava.util.Scanner;publicclassMain{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(......
  • 选择排序(简单选择排序,堆排序)
    学习时间2022.12.17选择排序基本概念简单选择排序第1次,遍历整个数组,找到最小的数字,将其与第一位进行调换;第2次,遍历除以排序好的第1个数,遍历后面所有数字,找到最小的,与......