算法笔记p414拓扑排序

目录

  • 有向无环图
  • 拓扑排序
    • 求拓扑排序步骤
    • 代码实现
  • 例题

有向无环图

如果一个有向图的任意顶点都无法通过一些有向边回到自身,那么称这个有向图为有向无环图(DirectedAcyclic Graph,DAG)。

拓扑排序

拓扑排序是将有向无环图G的所有顶点排成一个线性序列,使得对图G中的任意两个顶点u、v,如果存在边u->v,那么在序列中u一定在v前面。这个序列又被称为拓扑序列。

求拓扑排序步骤

  1. 定义一个队列Q,并把所有入度为0的结点加入队列(算法笔记p251队列)。
  2. 取队首结点,输出。然后删去所有从它出发的边,并令这些边到达的顶点的入度减1,如果某个顶点的入度减为0,则将其加入队列。
  3. 反复进行②操作,直到队列为空。
  4. 如果队列为空时入过队的结点数目恰好为N,说明拓扑排序成功,图G为有向无环图;否则,拓扑排序失败,图G中有环。

代码实现

可使用邻接表实现拓扑排序。显然,由于需要记录结点的入度,因此需要额外建立一个数组inDegree[MAXV],并在程序一开始读入图时就记录好每个结点的入度。接下来就只需要按上面所说的步骤进行实现即可,拓扑排序的代码如下:

  1. C++实现:
#include <vector>
#include <queue>#define MAXV 10000using namespace std;vector<int> G[MAXV];             	// 邻接表
int n, 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);         // 此处可输出顶点u,作为拓扑序列中的顶点q.pop();for (int i = 0; i < G[u].size(); ++i) {int v = G[u][i];        // u的后继结点vinDegree[v]--;          // 顶点v的入度减1if (inDegree[v] == 0)   // 顶点v的入度减为0则入队q.push(v);}G[u].clear();               // 清空顶点u的所有出边(如无必要可不写)num++;                      // 加入拓扑序列的顶点数加1}if (num == n) return true;      // 加入拓扑排序的顶点数为n,说明拓扑排序成功else return false;              // 加入拓扑排序的顶点数小于n,说明拓扑排序失败
}
  • 拓扑排序的很重要的应用就是判断一个给定的图是否是有向无环图。正如上面的代码,如果 topologicalSort0函数返回true,则说明拓扑排序成功,给定的图是有向无环图;否则,说明拓扑排序失败,给定的图中有环。
  • 最后指出,如果要求有多个入度为0的顶点,选择编号最小的顶点,那么把queue改成priority_queue(堆实现),并保持队首元素是优先队列中最小的元素即可(算法笔记p335堆)。
  1. C语言实现:
#include <stdio.h>
#include <stdbool.h>#define MaxSize 1000// 图的邻接表实现数据结构定义
typedef int VertexType;
typedef int EdgeType;// 边表结点
typedef struct ArcNode {int adjVertex;            	// 该弧所指向的顶点的位置EdgeType info;            	// 弧的权值struct ArcNode *next;    	// 指向下一条弧的指针
} ArcNode;
// 顶点表结点
typedef struct VertexNode {VertexType data;            // 顶点信息struct ArcNode *first;    	// 指向第一条依附该顶点的弧的指针
} AdjList;
// 图的链式存储(邻接表实现)
typedef struct ALGraph {AdjList vertices[MaxSize];  // 邻接表int verNum, arcNum;         // 顶点数和弧数
} ALGraph;// 循环队列实现的数据结构定义
typedef int ElemType;typedef struct Queue {ElemType data[MaxSize];int front, rear;
} Queue;void init(Queue *q) {q->rear = 0;q->front = 0;
}bool empty(Queue *q) {return q->front == q->rear;
}bool full(Queue *q) {return (q->rear + 1) % MaxSize == q->front;
}bool push(Queue *q, ElemType value) {if (full(q))return false;q->data[q->rear] = value;q->rear = (q->rear + 1) % MaxSize;return true;
}bool pop(Queue *q, ElemType *p) {if (empty(q))return false;*p = q->data[q->front];q->front = (q->front + 1) % MaxSize;return true;
}// 入度
int inDegree[MaxSize];// 计算图中各个顶点的入度
void countInDegree(ALGraph *G) {// 初始化for (int i = 0; i < G->verNum; ++i)inDegree[i] = 0;// 计算入度for (int i = 0; i < G->verNum; ++i) {ArcNode *node = G->vertices[i].first;while (node) {inDegree[node->adjVertex]++;node = node->next;}}
}// 拓扑排序
bool topologicalSort(ALGraph *G) {int num = 0;                            	// 记录加入拓扑排序的顶点数Queue q;                                	// 拓扑队列init(&q);                            		// 初始化队列countInDegree(G);                    		// 计算图的入度for (int i = 0; i < G->verNum; ++i)if (inDegree[i] == 0)push(&q, i);                    	//将所有入度为0的顶点入队while (!empty(&q)) {int u;pop(&q, &u);                        	// 取队首顶点u并出队// printf("%d", u);                 	// 此处可输出顶点u,作为拓扑序列中的顶点ArcNode *i = G->vertices[u].first;while (i) {int v = G->vertices[i->adjVertex].data;inDegree[v]--;                  	// 顶点v的入度减1if (inDegree[v] == 0)           	// 顶点v的入度减为0则入队push(&q, v);i = i->next;}G->vertices[u].first = NULL;         	// 清空顶点u的所有出边(如无必要可不写)num++;                              	// 加入拓扑序列的顶点数加1}if (num == G->verNum) return true;       	// 加入拓扑排序的顶点数为n,说明拓扑排序成功else return false;                      	// 加入拓扑排序的顶点数小于n,说明拓扑排序失败
}

例题

  • 2012年中国科学技术大学研究生复试机试题:任务调度

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/758183.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字化转型急迫推进,效益提升却难见明显成效!

数字化现已不再是一种选择&#xff0c;而是企业适应市场环境、保持竞争力的必然要求。但是&#xff0c;企业在投入大量人力、物力进行数字化转型后&#xff0c;却常常面临效益不明显的问题&#xff0c;这种现象值得我们深入剖析与探讨。 我们需要明白数字化转型并非简单地购置先…

【知识简略】说说分布式常见问题及解决方案:分布式锁、分布式事务、分布式session、分布式任务调度;

分布式常见问题及解决方案 前言什么是分布式系统分布式系统与微服务两者概念傻傻分不清 1.分布式锁分布式事务分布式Session分布式任务调度 前言 什么是分布式系统 分布式系统(Distributed System)是指由多个独立计算机通过网络通信协议连接起来协同工作&#xff0c;共同完成一…

【Java】POI解析excel

一、相关介绍 POI技术 Apache POI是Apache软件基金会的开放源码函式库&#xff0c;POI提供API给Java程序对Microsoft Office格式档案读和写的功能。 poi-ooxml能解析xls&#xff0c;xlsx。 poi能解析word、ppt、excel、xml等office软件 导入坐标&#xff1a; <depende…

如何使用ArkUI从0-1写一个开发购物应用程序(下)

接下来我们继续学习如何用ArkUI来开发一个购物应用程序&#xff08;下半部分&#xff09; 底部组件是由一个横向的图片列表组成&#xff0c;iconPath是底部初始状态下的3张图片路径数组。遍历iconPath数组&#xff0c;使用Image组件设置图片路径并添加到List中&#xff0c;给每…

【RabbitMQ】【Docker】基于docker-compose构建rabbitmq容器

本文通过docker-compose构建一个单体的rabbtimq容器。 1&#xff0c;docker、docker-compose环境 首先需要有docker和docker-compose环境&#xff0c;docker安装[1]&#xff0c;docker-compose安装[2]。 通过下列命令确定docker、docker-compose是否安装成功。 [root192 ge…

【大屏设计】如何进行软件系统网站大屏页面设计?不限于智慧城市、物联网、电商、园区领域

【大屏设计】如何进行软件系统网站大屏页面设计&#xff1f;不限于智慧城市、物联网、电商、园区领域 一、什么是网站大屏设计二、网站大屏设计原型素材三、网站大屏设计设计素材四、他山之石 一、什么是网站大屏设计 网站大屏设计是网站设计中至关重要的一部分&#xff0c;因…

Ubuntu介绍

Ubuntu&#xff0c;这个源自南非祖鲁语和科萨语的词汇&#xff0c;意为“人类之间的仁慈和善良”。在计算机领域&#xff0c;Ubuntu已经成为了一个广为人知的开源操作系统&#xff0c;它以其易用性、稳定性和强大的社区支持而闻名于世。Ubuntu不仅仅是一个操作系统&#xff0c;…

数据库笔记

1、服务端架构分层&#xff1a;网关层管网络&#xff0c;应用层管业务&#xff0c;存储层管数据 2、Mysql单表数据量超百万查询慢&#xff0c;超千万查不动了 3、高级需要你熟练地使用各种数据库 是多读写少&#xff0c;还是反过来分布式扩展能力解决单机存储的瓶颈问题 4、关…

8种Kubernetes集群中Pod处于 Pending状态的故障排除方法

文章目录 一、Pod与容器二、Pod的阶段&#xff08;状态&#xff09;三、Pod 状态故障排除3.1 检查 Pod 事件3.2 检查资源可用性3.3 检查污点和容忍度3.4 检查节点亲和性设置3.5 检查持久卷声明3.6 检查配额和限制3.7 验证 Pod 和容器映像3.8 分析调度程序日志 四、用于排查 Pen…

Linux 常用命令 cat

Linux 常用命令 cat 作用 用于连接文件并打印到标准输出设备上。也可用于创建文件、显示文件内容等操作。 用法 cat [OPTION]... [FILE]...&#xff0c;参数说明如下&#xff1a; 当未指定 FILE 参数&#xff0c;或者 FILE 参数为 -&#xff0c;则从标准输入读取 -A, --show…

Django动态路由实例

Django动态路由实例 先说需求&#xff1a; 比如我前端有两个按钮&#xff0c;点击按钮1跳转到user1的用户信息页面&#xff0c;按钮2跳转user2用户信息页面&#xff0c;但是他俩共用同一个视图层 直接上代码 路由层 urlpatterns [path(user/<str:username>/, views…

图神经网络学习00--distill论文入手

distill distill是网页形式的期刊&#xff0c;其中有许多非常棒的可视化讲解&#xff0c;力求把晦涩难懂的研究工作讲得通俗易懂。 非常适合初学者学习。 其中有两篇发布于Sept.2,2021的有关图神经网络的博客&#xff0c;文章脉络清晰。 A Gentle Introduction to Graph Neural…

微软的TaskWeaver框架

微软的TaskWeaver框架是一个功能强大的工具&#xff0c;它的应用场景非常广泛。以下是几个具体的应用场景及其应用方式的简要介绍&#xff1a; 数据分析与可视化&#xff1a; 应用场景&#xff1a;企业需要对大量数据进行深度分析&#xff0c;以洞察市场趋势、优化业务决策。 …

Swift 结构化并发之全局 Actor 趣谈

概览 在 Swift 结构化并发构成的体系中,一个称为“演员”(Actor)的成员扮演了非常重要的角色,它被用来隔离和同步执行中的数据。 除了普通 Actor 以外,还有一个全局“演员”(Global Actor)的概念,它是做什么的?又有什么与众不同的长处呢? 在本篇博文中,您将学到如…

通过ETL工具快速实现单据同步

ETLCloud介绍 ETLCloud是一款旨在解决企业数据集成挑战的最新一代平台&#xff0c;它集成了离线数据集成ETL、ELT、CDC实时数据集成、编排调度和数据服务API等功能&#xff0c;形成了一体化的DataOps数据集成平台。该平台提供私有化部署以及云原生架构&#xff0c;能够满足企业…

二分查找 python

1.非递归写法 def binary_search(arr, target):left, right 0, len(arr) - 1while left < right:mid (left right) // 2if arr[mid] target: #如果相等return midelif arr[mid] < target:#当中值小于目标值 说明应该在右边查找了left mid 1 #把左索引 变成mid1els…

设计模式深度解析:适配器模式与桥接模式-灵活应对变化的两种设计策略大比拼

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 适配器模式与桥接模式-灵活应对变化的两种设计策略大比拼 探索设计模式的魅力&#xff1a;深入了…

nodejs的geoip-lite库

介绍 geoip-lite是一个用于获取IP地址地理位置信息的轻量级Node.js库。它使用MaxMind的GeoLite数据库&#xff0c;提供了方便的方式来查询IP地址对应的国家、省份和城市等地理位置信息。geoip-lite库的主要特点包括&#xff1a; 轻量级&#xff1a; geoip-lite是一个轻量级的…

ElasticSearch - 基本操作

前言 本文记录 ES 的一些基本操作&#xff0c;就是对官方文档的一些整理&#xff0c;按自己的习惯重新排版&#xff0c;凑合着看。官方的更详细&#xff0c;建议看官方的。 下文以 books 为索引名举例。 新增 添加单个文档 (没有索引会自动创建) POST books/_doc {"n…

Wpf-自定义控件波纹Button

使用用户控件&#xff0c;继承Button 前端代码 <Button x:Class"WpfApp1.SuperButton"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://sche…