C++详细讲解图的拓扑排序

C++详细讲解图的拓扑排序

什么是拓扑排序

拓扑排序是对于有向无环图(Directed Acyclic Graph)的一种排序,其输出结果为图中每个节点的线性先后序列,满足如果存在一条从节点 A 到节点 B 的路径,则在序列中节点 A 出现在节点 B 的前面。

什么是有向无环图(DAG)

有向无环图是不包含环路并且有一个或多个源点和汇点的有向图。其中源点指没有入度的节点,汇点指没有出度的节点。

如何实现拓扑排序

拓扑排序的实现可以采用拓扑排序算法,一般使用拓扑排序的核心思想,就是去除图中所有的入度为0的节点,再删除这个节点以及所有从这个节点出发的边。重复这个过程,直到找不到入度为0的节点。

代码实现

vector<int> topsort(vector<vector<int>>& graph) 
{
    int n = graph.size(); // n 表示图中点的个数
    vector<int> degree(n, 0); // 存储每个点的入度
    vector<vector<int>> adj(n); // 表示图中每个点的出边

    for (int i = 0; i < n; i++) 
    {
        for (int j = 0; j < graph[i].size(); j++)
        {
            int u = graph[i][j];
            degree[u]++; // 求每个点的入度
            adj[i].push_back(u); // 记录每个点的出边
        }
    }

    queue<int> q; // 用队列保存所有入度为0的节点
    for (int i = 0; i < n; i++) 
    {
        if (degree[i] == 0) q.push(i);
    }

    vector<int> res; // 用来保存最终的结果
    while (!q.empty()) 
    {
        int u = q.front(); q.pop(); // 取出队列的头节点
        res.push_back(u); // 将该节点加入结果中
        for (int i = 0; i < adj[u].size(); i++) 
        {
            int v = adj[u][i];
            degree[v]--; // 删掉该节点相连的出边
            if (degree[v] == 0) q.push(v); // 若该节点入度变为0则入队列
        }
    }

    return res;
}

示例说明

示例1

假设我们要对下面的有向无环图进行拓扑排序:

0 ----> 1 ----> 2 ----> 3
        |              |
        v              v
        4 ----> 5 ----> 6

按照拓扑排序的定义和实现方法,首先需要找到所有入度为0的节点,也就是节点0和节点4,因此将它们入队。

当我们出队节点0时,发现节点1和节点4的入度都会减1,但我们只处理了节点1,因为节点4的入度此时只有1,还不为0,节点4会在以后的队列中被处理。

接着,我们出队节点1,它相连的节点2和5的入度分别减1,这时节点5的入度变为0,被加入队列中,节点2则继续等待。

然后,我们出队节点4,它连接的节点5和6的入度分别减1,节点5和节点6此时的入度都变为0了,它们会被加入到队列中。

接下来出队节点2,使得节点3入度减1,此时节点3的入度变为0,被加入到队列中。最后出队节点5、节点6、节点3,完成了拓扑排序。

示例2

假设还有另外一个有向无环图:

0 ----> 1 ----> 2
        ↑      /
        |    /
        |  /
        ↓
        3

该图的拓扑排序结果是:0 -> 3 -> 1 -> 2。分析一下这个结果的产生,首先将0和3入队,删除它们后,在队列中插入1。此时仅剩节点2的入度不为零,排除2后编号0、3、1、2顺次入队,最终出队即可。

总结

拓扑排序是一种基于有向无环图的排序算法,可以用于解决很多问题。拓扑排序算法的实现中,需要使用队列、入度等数据结构,可以使用C++等高级编程语言轻松实现。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++详细讲解图的拓扑排序 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • TF-IDF与余弦相似性的应用(一) 自动提取关键词

    下面我将详细讲解“TF-IDF与余弦相似性的应用(一) 自动提取关键词”的完整攻略。 什么是TF-IDF? TF-IDF(Term Frequency-Inverse Document Frequency)是一种常用于信息检索与分类中的文本特征提取方法,用于评估一段文本中词的重要程度。TF-IDF的核心思想就是:一个词在一篇文档中出现的频次(TF)越高,同时…

    算法与数据结构 2023年5月19日
    00
  • C++ 实现桶排序的示例代码

    下面是一份详细的攻略,带有示例说明。 桶排序简介 桶排序是一种基于计数的排序算法。它将一些数据分到不同的桶里,再对每个桶中的数据进行排序,最后按照桶的顺序依次输出所有数据,即可得到排好序的序列。 桶排序的时间复杂度是 $O(n)$,空间复杂度也是 $O(n)$,适用于元素值分布比较均匀的数据。 C++ 桶排序示例 下面是一份 C++ 实现桶排序的示例代码: …

    算法与数据结构 2023年5月19日
    00
  • 深入了解javascript 数组的sort方法

    深入了解JavaScript数组的sort方法 简介 在JavaScript中,数组(Array)是一个非常常用的数据结构,而sort()是Array原型上的非常常用的方法,可用于排序。数组中的元素可以是任何类型,但在排序时,所有元素都将转换为字符串形式,所以有时打算对不同数据类型的元素进行排序,您可能需要使用自定义比较函数。 基本使用方法 sort()方法…

    算法与数据结构 2023年5月19日
    00
  • C++中二叉堆排序详解

    C++中二叉堆排序详解 什么是二叉堆排序 二叉堆是一种特殊的二叉树,它有两个特性: 根节点的键值是所有节点中最小/最大的; 对于节点i的键值一定不大/小于它的父节点i/2。 根据第二个规则,我们可以对于任何一个节点i,以i为根的子树都是一个小根堆/大根堆。将二叉堆中最小/最大的根节点取出,然后将最后一个节点放到根位置,再对根节点进行一次向下调整的操作,就可以…

    算法与数据结构 2023年5月19日
    00
  • 基于Go语言实现插入排序算法及优化

    基于Go语言实现插入排序算法及优化攻略 插入排序算法 插入排序是一种简单直观的排序方法,主要思路是将未排序部分的第一个元素插入到已排序部分合适的位置。具体实现方式如下: func InsertionSort(arr []int) { n := len(arr) for i := 1; i < n; i++ { // 寻找arr[i]合适的插入位置 fo…

    算法与数据结构 2023年5月19日
    00
  • java如何给对象按照字符串属性进行排序

    在 Java 中,我们可以使用 Collections.sort() 方法对任意类型的对象进行排序。但是,如果我们想要按照对象的某一个字符串属性进行排序,我们可以使用 Comparator 接口来实现。 具体步骤如下: 首先,创建一个 Comparator 对象,重写 compare() 方法,按照需要的属性进行排序。例如,如果我们要按照对象的 name 属…

    算法与数据结构 2023年5月19日
    00
  • js实现简单排列组合的方法

    下面是详细讲解 “js实现简单排列组合的方法” 的攻略。 排列组合的概念 排列就是由给定的n个元素中取出m(m ≤ n)个元素的所有排列总数的不同的排列数,用A(n, m)表示。例如,有3个元素A、B、C,则它们的排列有:ABC、ACB、BAC、BCA、CAB、CBA,共6种排列。 组合是指从n个不同元素中,取出m(m≤n)个元素的所有组合情况,用C(n,m…

    算法与数据结构 2023年5月19日
    00
  • 深入解析Radix Sort基数排序算法思想及C语言实现示例

    深入解析Radix Sort基数排序算法思想及C语言实现示例 什么是基数排序算法 基数排序即Radix Sort,是一种非比较型排序算法。相比于其他排序算法,如快速排序、归并排序等,基数排序的时间复杂度较为稳定,且不受数据规模的影响,适用于数据范围较小但位数较多的序列排序。 基数排序算法思想 基数排序算法的核心思想是按照不同位数上的数字对数据进行排序,从低位…

    算法与数据结构 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部