<数据结构>拓扑排序
有向无环图
有向无环图(Directed Acycilc Graph, DAG):从任意顶点出发都无法回到自身的有向图。
拓扑排序
定义#
任一两个顶点u,v间,如果存在边u->v,则排序后u一定在v前面。
问题导入#
上图表示了数学课程间的相互关系,图的每个结点表示一门课程,每条有向边u->v表示“u是v的先导课程”(即上完u才能上v)的关系。
不难发现,如果要把上面所有课程排成课程顺序,保证在学习一门课程时,它的先导课程都已经全部学完,如果两门课程之间没有先导关系则排序任意。那么这一过程就可以抽象为拓扑排序。拓扑排序的序列不唯一。
注意: 很显然,拓扑排序只有在有向无环图中才能成功。如果图中有环,就不可能满足拓扑排序的定义,比如在上例中,数学分析是计算方法的先导,计算方法是高等几何的先导,但如果高等几何又是数学分析的先导,那整个课程不就乱套了。
算法实现
过程抽象:不断抽出入度为0的结点#
- 定义一个队列Q,把所有入度为0的结点全部入队
- 取出队首结点,输出。 然后删去从它出发的所边, 并令这些边达到的顶点的入度减1。 如果某个顶点入度变为0,则入队。
- 重复2操作,直到队列为空。 队列为空时,若如果队的结点恰好为顶点数N,说明拓扑排序成功;否则,拓扑排序失败,图中有环。
代码实现#
#include<stdio.h>
#include<queue> //用stl库中的queue实现队列
#include<vector>
using namespace std;
const int MAXV = 100;
vector<int> G[MAXV]; //邻接表实现图G
int n,m,inDegree[MAXV];//顶点数,入度
//拓扑排序
bool topologicalSort(){
int num = 0;
queue<int> q;
for(int i = 0; i<n; i++){
if(inDegree[i] == 0){
q.push(i); //将所有入度为0的顶点入队
}
}
while(!q.empty()){
int u = q.front(); //取队首顶点u
// printf("%d ", u); //此处可输出顶点,作为拓扑序列中的顶点
q.pop();
for(int i = 0; i < G[u].size(); i++){
int v = G[u][i]; //u的后继结点v
inDegree[v]--; //顶点v的入度-1
if(inDegree[v] == 0){ //顶点v的入度为0,则入队
q.push(v);
}
}
G[u].clear(); //清空所有边的出边,如无必要可不写
num++; //加入拓扑序列的顶点数+1
}
if(num == n) return true; //加入拓扑序列的顶点数为n,说明拓扑排序成功
else return false; //加入拓扑排序的顶点数小于n,说明拓扑排序失败
}
用途
- 进行拓扑排序
- 判断一个有向图中是否有环
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用