拓扑排序详解(包含算法原理图解、算法实现过程详解、算法例题变式全面讲解等)

article/2025/10/1 7:27:33

前置知识

有向无环图

在图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。
如图所示。
在这里插入图片描述

入度

对于一个有向图,若x点指向y点,则称x点为y点的入度。

出度

对于一个有向图,若x点指向y点,则称y点为x点的出度。

队列

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

我们可以用双指针标记一下,通过front指针与rear指针,对队头和队尾进行标记,然后只允许在front、rear指针的位置进行增删改查,那么这样便实现了对数组的受限。这是一种运用数组的数据结构对队列的模拟。初学者建议先用这种方式熟悉队列。

具体操作:

/*通常将front赋值为0,rear赋值为-1方便后续进队、出队以及取队首元素*/
int a[100], front=0, rear=-1;// 进队
a[++rear] = 10;// 出队
front++// 取队首元素
a[front]// 取队尾元素
a[rear]// 判断是否为空队
if(front > rear)cout << "该队列为空队";

不过,到了后期,为了节省时间,我们可以直接用c++自带的STL容器来完成操作。

具体操作如下:

// 导入queue包
#include<queue>// 申明一个queue对象
// 填入你想装填的数据类型
queue<int> qu;// 进队
int a = 10;
qu.push(a);// 出队,无返回值
qu.pop();// 取队首元素
int front = qu.front();

概述

今天我们来学拓扑排序
什么是拓扑排序呢?
百度百科这样说:

对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。

什么意思呢?

俗话说的好:

实践是真理的试金石

那么,就让我们举一个例子吧!
如图,1、2、3、4、5几个点组成了一个图。


那么,1,2,4,3,6,5或1,2,4,3,5,6就是它的拓扑序

但是,这是如何实现的呢?请看下面的算法原理

算法原理

下面我将使用图文结合的方式演示拓扑排序的算法原理。

还是上面那张图。

首先,将入度为0的入队。上图中是点1。

在这里插入图片描述
然后,用宽搜遍历队列
对每个点的每轮遍历步骤如下:

  • 将这个点出队,并加入拓扑数组中
  • 遍历这个点的所有出度
  • 将其出度点的入度数量减少一
  • 如果其出度点入度为0,入队

那么,一轮下来,就变成这样子了:
在这里插入图片描述
以此类推。

遍历到点3时,是这样的:
在这里插入图片描述
……

然后,就没有然后了,一切结束。
在这里插入图片描述
如图所示,其拓扑序为1,2,4,3,5,6。当然,也可以是1,2,4,3,6,5。

算法实现

这可以变为以下的问题。我称为拓扑排序元问题

给你一个有向无环图,请输出它的拓扑序(m条有向边,n个结点)

建图(邻接表存图)

首先,我们要建图
这里采用邻接表建图。

邻接表是什么?
以点为一个结点,用其邻接点建表

怎么这么朦胧?好吧,偷懒了,自己查百度……

看到这里,就默认你会了建图操作。那么,放一下代码。
(此处设定为m条有向边)

for(int i=1;i<=m;i++)
{int x,y;scanf("%d%d",&x,&y);rd[y]++;e[x].push_back(y);
}

rd[y]++ 是什么意思?请往后看。

入队

上面提到,首先,将入度为0的点入队。
那么,我们就遍历一遍n个点,当遇到入度为0的点时,入队。

如何判断入度为0?

这时前面的 rd数组 就有用了。它是用于统计入度数的。
而前面为何是rd[y]++?
因为是 x指向y,因此y入度数加1

入队操作

非常简单!这里为了省力,用了STL容器
只需要**q.push(i)**一下就可以了

代码

	queue<int>q;for(int i=1;i<=n;i++){if(rd[i]==0) q.push(i);//入度为0,入队 }

核心部分

这部分的过程,我在前面是这样说的:

用宽搜遍历队列。
那就宽搜。

宽搜

没遍历到一个点,就将其弹出,并压入拓扑数组。

对每个点的操作

我在前面这样说:
对每个点的每轮遍历步骤如下:
1.将这个点出队,并加入拓扑数组中
2.遍历这个点的所有出度
3.将其出度点的入度数量减少一
4.如果其出度点入度为0,入队

那就照着做嘛。
很简单,实在看不懂代码中有注释。

代码

	while(!q.empty()){int x=q.front();q.pop();topu.push_back(x);//推入拓扑数组 for(auto y:e[x]){rd[y]--;//删掉一条边 if(rd[y]==0)//入度为0 {q.push(y);//入队 }}}

好,大功告成!

算法元代码

上面没看懂的话,看下面的代码,含有注释。

#include<bits/stdc++.h>
using namespace std;
const int NN=5005;
int n,m,rd[NN];
//rd[i]表示i点的入度数 
vector<int>e[NN],topu;
//e作为邻接表存储用,topu储存拓扑序 
void tuopu()
{queue<int>q;for(int i=1;i<=n;i++){if(rd[i]==0) q.push(i);//入度为0,入队 }while(!q.empty()){int x=q.front();q.pop();topu.push_back(x);//推入拓扑数组 for(auto y:e[x]){rd[y]--;//删掉一条边 if(rd[y]==0)//入度为0 {q.push(y);//入队 }}}
}
int main()
{scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);rd[y]++;//x指向y,因此y入度数加1 e[x].push_back(y);//加边 }tuopu();for(auto x:topu){printf("%d ",x);//输出拓扑序 }
} 

总结

拓扑排序就是这回事:
首先,将入度为0的点入队。
然后,用宽搜遍历队列。
在此之后,对每个点进行如下操作:
1.将这个点出队,并加入拓扑数组中
2.遍历这个点的所有出度
3.将其出度点的入度数量减少一
4.如果其出度点入度为0,入队

下一篇文章,我将会详细讲解拓扑排序相关例题。
好,期待三连~~


http://chatgpt.dhexx.cn/article/Q9WDbrx2.shtml

相关文章

拓扑排序算法分析(通俗易懂)

拓扑排序&#xff08;其实是一种依赖关系&#xff09;&#xff1a;对于有向且无环的图来说&#xff0c;当前这个节点的依赖来其之前已经完成了。 下面附上一个图让大伙更好的理解&#xff1a; 比如这个图&#xff1a;B需要依赖A才能完成&#xff0c;A需要依赖C和D才能完成&…

拓扑排序算法详讲

经过一天的专研,终于明白了拓扑排序算法,写篇博客记录一下心得. 一.拓扑排序介绍 在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为AOV网. 设G(V,E)是一个具有n个顶点的有向图,v中的顶点序列v1,v2…,vn,满足若从…

C++ 拓扑排序算法

拓扑排序 有向无环图 如果一个有向图的任意顶点都无法通过一些有向边回到自身&#xff0c;那么称这个有向图为有向无环图。 拓扑排序 拓扑排序是将有向无环图G的所有顶点排成一个线性序列&#xff0c;使得对图G中的任意两个顶点u、v&#xff0c;如果存在边u->v&#xff0c;那…

拓扑排序

拓扑排序 一、拓扑排序的定义&#xff1a; 先引用一段百度百科上对于拓扑排序的定义&#xff1a; 对一个有向无环图 ( Directed Acyclic Graph 简称 DAG ) G 进行拓扑排序&#xff0c;是将 G 中所有顶点排成一个线性序列&#xff0c;使得图中任意一对顶点 u 和 v &#xff0c…

拓扑排序算法

拓扑排序介绍 拓扑排序(Topological Order)是指&#xff0c;将一个有向无环图(Directed Acyclic Graph简称DAG)进行排序进而得到一个有序的线性序列。 这样说&#xff0c;可能理解起来比较抽象。下面通过简单的例子进行说明&#xff01; 例如&#xff0c;一个项目包括A、B、C…

经典算法之拓扑排序

定义&#xff1a; 把AOV网&#xff08;用定点表示活动&#xff0c;用弧表示活动间优先关系的有向图&#xff09;络中各个顶点按照它们互相之间的优先关系排列成一个线性序列的过程叫做拓扑排序。 方法&#xff1a; 在有向图中选一个没有前驱的顶点并且输出从图中删除该顶点和…

拓扑排序(topological sorting)介绍及Python实现

目录 1. 拓扑排序 2. 拓扑排序存在的前提 3. 拓扑排序的唯一性问题 4. 拓扑排序算法原理 4.1 广度优先遍历 4.2 深度优先遍历 5. 代码实现 5.1 Graph类的实现 5.2 广度优先搜索 5.3 深度优先搜索简易版&#xff08;无loop检测&#xff09; 5.4 深度优先搜索完整版 …

【算法】拓扑排序

今天学习拓扑排序。如果一个有向图的任意顶点都无法通过一些有向边回到自身&#xff0c;那么称这个有向图为有向无环图&#xff08;Directed Acyclic Graph&#xff0c;DAG&#xff09;。拓扑排序就是将有向无环图的所有顶点排序&#xff0c;使得图中任意两个点 u、v&#xff0…

拓扑排序及算法实现

一、拓扑排序概念 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序&#xff0c;是将G中所有顶点排成一个线性序列&#xff0c;使得图中任意一对顶点u和v&#xff0c;若边<u,v>∈E(G)&#xff0c;则u在线性序列中出现在v之前。通常&#xff0c;这样的线性…

利用迭代法求平方根——迭代法开平方运算

一、题目 用迭代法求&#xff1a; 的值。要求精度为0.00001&#xff0c;即 二、迭代公式 求平方根的迭代公式为&#xff1a; 当满足 时&#xff0c;这时的即是求得的根。如果 得到是精确值。如果不为0&#xff0c;则是近似值。 三、C代码 先给出开平方运算的函数。再给出主…

【算法】牛顿迭代法求平方根的原理和误差分析

前言 在《算法(第四版)》中的P23页&#xff0c;给出了经典的利用牛顿迭代法求平方根的算法&#xff0c;牛顿迭代法在数值计算中应用十分广泛&#xff0c;但是在看书中的代码时&#xff0c;我最困惑的是其中对收敛条件的判断&#xff0c;经过查阅资料和论坛&#xff0c;找到…

使用迭代法来求a的平方根

今天朋友问我一道使用迭代法求a的平方根的题&#xff0c;感觉受益匪浅&#xff0c;与诸君相分享 首先我们来看一下题目 我们也无需了解迭代法是什么原理&#xff0c;根据这个题目可以分析得到&#xff0c;需要使用while循环&#xff0c;下面是我的代码实践 #define _CRT_SEC…

利用牛顿迭代法求平方根

求n的平方根&#xff0c;先假设一猜测值X0 1&#xff0c;然后根据以下公式求出X1&#xff0c;再将X1代入公式右边&#xff0c;继续求出X2…通过有效次迭代后即可求出n的平方根&#xff0c;Xk1 先让我们来验证下这个巧妙的方法准确性&#xff0c;来算下2的平方根 (Computed b…

牛顿迭代法求解平方根

一个实例迭代简介牛顿迭代法 牛顿迭代法简介简单推导泰勒公式推导延伸与应用 一个实例 //java实现的sqrt类和方法 public class sqrt {public static double sqrt(double n){if (n<0) return Double.NaN;double err 1e-15;double t n;while (Math.abs(t - n/t) > err…

牛顿迭代法求一个数的平方根(python)

# !/usr/bin/env python # -*- coding: utf-8 -*- """ Author: P♂boy License: (C) Copyright 2013-2017, Node Supply Chain Manager Corporation Limited. Contact: 17647361832163.com Software: Pycharm File: sqrt.py.py Time: 2018/11/19 16:22 Desc:牛顿…

c++迭代法求平方根

用迭代法求x &#xff0c;要求前后两次求出的x的差的绝对值小于10-5&#xff0c;求平方根的迭代公式为&#xff1a; 输入 一个数a。 输出 的值。 样例输入 2.0样例输出 The square root of 2.00 is 1.41421 这道题我无语了...&#xff1a; #include<bits/stdc.h> …

牛顿迭代法求平方根原理

牛顿迭代法可以求解n次方的根&#xff0c;但这里只讨论用它来求平方根。 牛顿迭代法求平方根过程 Java代码实现 /*** 求一个数的平方根* param number* return*/public static double squareRoot(double number){if(number < 0){ //小于0的数无法开平方return Double.NaN;}e…

【算法】牛顿迭代法求平方根及多次方根

1. 概述 牛顿迭代法 牛顿迭代法 牛顿迭代法 是非常高效的求解方程的根的方法。其求解原理可以参考各文献。大体的思路如下&#xff1a; 通过不断地做切线来逼近真实的根&#xff0c;直到误差小于精度。 可得迭代公式&#xff1a; x n 1 x n − f ( x n ) f ′ ( x n ) x_{…

二分法和牛顿迭代法求平方根(Python实现)

求一个数的平方根函数sqrt(int num) ,在大多数语言中都提供实现。那么要求一个数的平方根&#xff0c;是怎么实现的呢&#xff1f; 实际上求平方根的算法方法主要有两种&#xff1a;二分法(binary search)和牛顿迭代法(Newton iteration) 1&#xff1a;二分法 求根号5 a:折半…

牛顿迭代法-求平方根

牛顿迭代法 求出根号a的近似值&#xff1a;首先随便猜一个近似值x&#xff0c;然后不断令x等于x和a/x的平均数&#xff0c;迭代个六七次后x的值就已经相当精确了。 例如&#xff0c;我想求根号2等于多少。假如我猜测的结果为4&#xff0c;虽然错的离谱&#xff0c;但你可以看到…