图的应用3.0-----拓扑排序

news2024/10/6 6:52:54

 目录

前言

AOE网

1.相关概念

2.AOE网特征

拓扑排序

1.基本概念

2.方法步骤

 3.拓扑排序的应用

拓扑排序代码实现

1.邻接矩阵的代码

2.邻接表代码


前言

        今天我们学习图的应用----拓扑排序,说到排序,你们是不是会想到冒泡排序,插入排序,快速排序等等排序方法?但是拓扑排序跟这些不一样,拓扑排序是属于图的一种遍历算法,不属于用于纯数字排序,那什么是拓扑排序呢?下面就一起来看看吧!

AOE网

1.相关概念

        有向无环图常用来描述一个工程或系统的进行过程。(通常把计划、施工、生产、程序流程等当成是一个工程

        一个工程可以分为若干个子工程,只要完成了这些子工程(活动),就可以导致整个工程的完成。

AOV网

用一个有向图表示一个工程的各子工程及其相互制约的关系,其中以顶点表示活动,弧表示活动之间的优先制约关系,称这种有向图为顶点表示活动的网,简称AOV网(Activity On Vertex network)。

如图所示,做出AOE网: 

2.AOE网特征

  • 若从i到j有一条有向路径,则i是j的前驱i是i的后继。
  • 若<ij> 是网中有向边,则i是j的直接前驱;j是i的直接后继
  • AOV 网中不允许有回路,因为如果有回路存在,则表明某项活动以自己为先决条件,显然这是荒谬的。

拓扑排序

1.基本概念

在AOV 网没有回路的前提下,我们将全部活动排列成一个线性序列,使得若AOV 网中有弧 <i,j>存在,则在这个序列中,i一定排在的前面,具有这种性质的线性序列称为拓扑有序序列,相应的拓扑有序排序的算法称为拓扑排序

拓扑排序是对一个有向图构造拓扑序列,解决工程是否能顺利进行的问题。构造时有 2 种结果:

  1. 此图全部顶点被输出:说明说明图中无「环」存在, 是 AOV 网
  2. 没有输出全部顶点:说明图中有「环」存在,不是 AOV 网

形象化理解:

排序类似 流程图一样 任务

例如早上起床的任务:

例如:这里你只有穿了衬衣才能穿外套,而不是穿了外套再穿衬衣

2.方法步骤

  • 在有向图中选一个没有前驱的顶点且输出之
  • 从图中删除该顶点和所有以它为尾的弧
  • 重复上述两步,直至全部顶点均已输出:或者当图中不存在无前驱的顶点为止

示例1: 

示例2:

 3.拓扑排序的应用

检测AOV网中是否存在环方法:

对有向图构造其顶点的拓扑有序序列,若网中所有顶点都在它的拓扑有序序列中,则该AOV 网必定不存在环。

拓扑排序代码实现

图的存储方式有两种,邻接矩阵和邻接表,下面我就分别给出了这两种储存方式的代码写法。

1.邻接矩阵的代码

邻接矩阵结构如下:

#define Maxint 32767
#define Maxnum 100//最大顶点数

//数据类型
typedef struct datatype {
	char id[10];
	//……
}
ElemType;
//图的邻接数组
typedef struct graph {
	ElemType vexs[Maxnum];//图数据
	int matrix[Maxnum][Maxnum];//二维数组矩阵
	int vexnum;//点数
	int arcnum;//边数
}Graph;

拓扑排序代码: 

//拓扑排序
void Topo_sort(Graph G) {
	int n = G.vexnum;
	int* result = (int*)malloc(sizeof(int) * n);//储存结果
	int* indegree = (int*)malloc(sizeof(int) * n);//入度
	int*queue= (int*)malloc(sizeof(int) * n);//队列,储存下标
	//初始化
	for (int i = 0; i < n; i++) {
		result[i] = -1;
		indegree[i] = 0;
		queue[i] = -1;
	}
	int que_count = 0;
	int count = 0;
	//统计每一个顶点的入度
	for (int x = 0; x < n; x++) {
		for (int y = 0; y < n; y++) {
			if (G.matrix[y][x] != 0 && G.matrix[y][x] != Maxint)
				indegree[x]++;
		}
	}
	//把入度为0的顶点放入队列
	for (int i = 0; i < n; i++) {
		if (indegree[i] == 0) {
			queue[que_count] = i;
			que_count++;
		}
	}
	//后继处理
	while (que_count > 0) {
		//出队操作
		int pop = queue[0];
		for (int j = 0; j < que_count-1; j++) {
			queue[j] = queue[j + 1];
		}
		que_count--;

		result[count++] = pop;
		for (int i = 0; i < n; i++) {
			if (G.matrix[pop][i] != 0 && G.matrix[pop][i] != Maxint) {
				indegree[i]--;//把与这个出队的顶点相连的后继顶点入度都-1
				//以上操作完成了之后,如果还有入度为0的顶点就进入到队列当中
				if (indegree[i] == 0) 
					queue[que_count++] = i;
			}
		}
	}

	printf("拓扑排序结果:\n");
	for (int k = 0; k < n; k++) {
		printf("%s->", G.vexs[result[k]].id);
	}
	printf("end\nprint over!\n");
	//释放空间
	free(result);
	free(indegree);
	free(queue);
	result = queue = indegree = NULL;
}

2.邻接表代码

队列头文件.h代码:

#pragma once
#include<stdio.h>
#include<string.h>
#include <stdbool.h>
#include<assert.h>

//数据结构体
typedef struct datatype {
	char id[10];//字符串编号
	//………………
}ElemType;

//定义节点
typedef struct node {
	ElemType data;
	struct node* next;
}Node;
//定义队列
typedef struct queue {
	int count;	//计数
	Node* front;//指向队头指针
	Node* rear;//指向队尾指针
}Queue;

void Queue_init(Queue* queue);//初始化
bool isEmpty(Queue* queue);//判空
void enQueue(Queue* queue, ElemType data);//入队
Node* deQueue(Queue* queue);//出队
ElemType head_data(Queue queue);//获取队头数据

队列源文件代码.c

#include"queue.h"

//初始化
void Queue_init(Queue* queue) {
	assert(queue);
	queue->front = NULL;
	queue->rear = NULL;
	queue->count=0;
}

//创建节点
Node* create_node(ElemType data) {
	Node* new_node = (Node*)malloc(sizeof(Node));
	if (new_node) {
		new_node->data = data;
		new_node->next = NULL;
		return new_node;
	}
	else
	{
		printf("ERRPR\n");
	}
}

//判断是否空队列
bool isEmpty(Queue* queue) {
	assert(queue);
	if (queue->count == 0)
	{
		return true;
	}
	return false;
}

//入队
void enQueue(Queue* queue, ElemType data) {
	assert(queue);
	Node* new_node = create_node(data);
	if (queue->rear == NULL && queue->front == NULL ) {
		queue->front = new_node;
		queue->rear = new_node;
		queue->count++;
	}
	else
	{
		queue->rear->next = new_node;
		queue->rear = new_node;
		queue->count++;
	}
	
}

//出队
Node* deQueue(Queue* queue) {
	assert(queue);
	if (!isEmpty(queue)) {
		Node* deNode;
		if (queue->count == 1) {
			deNode = queue->front;
			queue->front = NULL;
			queue->rear = NULL;
		}
		else {
			deNode = queue->front;
			queue->front = deNode->next;
		}
		queue->count--;
		return deNode;
	}
	printf("error\n");
	return NULL;
}

//获取队头数据
ElemType head_data(Queue queue) {
	return queue.front->data;
}

拓扑排序代码:

//数据结构体
typedef struct datatype {
	char id[10];//字符串编号
	//………………
}ElemType;
//边节点存储结构
typedef struct arcnode {
	int index;//指向顶点的位置
	int weight;//权
	struct arcnode* nextarc;//指向下一个边节点
}Anode;
//顶点结点存储结构
typedef struct vexnode {
	ElemType data;
	Anode* firstarc;
}Vhead;
//图结构
typedef struct {
	Vhead* vertices;
	int vexnum;
	int arcnum;
}Graph;

//拓扑排序(邻接表)
void Topo_sort(Graph G) {
	int* inarry = (int*)malloc(sizeof(int) * G.vexnum);//统计每一个顶点的入度
	int* result= (int*)malloc(sizeof(int) * G.vexnum);//储存遍历结果
	//初始化
	for (int j = 0; j < G.vexnum; j++) {
		inarry[j] = 0;
		result[j] = -1;
	}
	Queue que;
	Queue_init(&que);

	//统计每个顶点的入度情况
	for (int i = 0; i < G.vexnum; i++) {
		Anode* p = G.vertices[i].firstarc;
		while (p) {
			inarry[p->index]++;
			p = p->nextarc;
		}
	}
	//把入度为0的节点放入队列
	for (int i = 0; i < G.vexnum; i++) {
		if (inarry[i] == 0)
			enQueue(&que, G.vertices[i].data);
	}
	int count = 0;

	while (!isEmpty(&que)) {
		//出队操作
		Node* pop = deQueue(&que);
		int pop_index = Locate_vex(G, pop->data.id);
		result[count++] = pop_index;//存入结果当中
		free(pop);
		pop = NULL;

		Anode* cur = G.vertices[pop_index].firstarc;
		while (cur) {
			//把与出队的顶点关联的点入度-1
			inarry[cur->index]--;
			//如果减掉入度之后入度为0的话就入队
			if (inarry[cur->index] == 0)
				enQueue(&que, G.vertices[cur->index].data);
			cur = cur->nextarc;
		}
	}

	printf("拓扑排序结果:\n");
	for (int i = 0; i < count; i++) {
		printf("%s->", G.vertices[result[i]].data.id);
	}
	printf("end\nprintf over!\n");
	//释放空间;
	free(inarry);
	free(result);
	inarry = result = NULL;
}

以上就是本期的全部内容了,我们下次见!

分享一张壁纸: 

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

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

相关文章

网络安全将会是IT行业中比较容易就业的方面

当前&#xff0c;网络空间安全面临的形势复杂多变&#xff0c;对抗趋势越发凸显。以窃取敏感数据、破坏关键信息技术设施为目标的有组织网络攻击愈演愈烈&#xff0c;零日漏洞、供应链攻击、数据泄露等重大安全事件层出不穷。 回望2022年&#xff0c;国内&#xff0c;以西北工业…

OpenTiny Vue 3.11.0 发布:增加富文本、ColorPicker等4个新组件,迎来了贡献者大爆发!

你好&#xff0c;我是 Kagol。 非常高兴跟大家宣布&#xff0c;2023年10月24日&#xff0c;OpenTiny Vue 发布了 v3.11.0 &#x1f389;。 OpenTiny 每次大版本发布&#xff0c;都会给大家带来一些实用的新特性&#xff0c;8.14 我们发布了 v3.10.0 版本&#xff0c;增加了4个…

“深入探讨操作系统和虚拟化技术“

目录 引言1.操作系统1.1.什么是操作系统1.2.常见操作系统1.3.个人版本和服务器版本的区别1.4.Linux的各个版本 2.安装VMWare虚拟机1.VMWare虚拟机介绍2.VMWare虚拟机安装3.VMWare虚拟机配置 3.安装配置Windows Server 2012 R24.完成电脑远程访问电脑5.服务器环境搭建配置jdk配置…

Windows下安装Anaconda、Pycharm以及iflycode插件图解

目录 一、下载Anaconda、Pycharm以及iflycode插件 二、创建相关文件夹 三、Pycharm社区版安装详细步骤 四、Anaconda安装详细步骤 五、配置Pycharm 六、安装iflycode插件 Anaconda是一款集成的Python环境&#xff0c;anaconda可以看做Python的一个集成安装&#xff0c;安…

Go学习第十一章——协程goroutine与管道channel

Go协程goroutine与管道channel 1 协程goroutine1.1 基本介绍1.2 快速入门1.3 调度模型&#xff1a;MPG模式介绍1.4 设置cpu数1.5 协程资源竞争问题1.6 解决协程并发方案 2 管道channel2.1 基本介绍2.2 快速入门2.3 管道的关闭和遍历2.4 管道和协程的结合2.5 声明 只读/只写 的管…

竞赛 深度学习图像修复算法 - opencv python 机器视觉

文章目录 0 前言2 什么是图像内容填充修复3 原理分析3.1 第一步&#xff1a;将图像理解为一个概率分布的样本3.2 补全图像 3.3 快速生成假图像3.4 生成对抗网络(Generative Adversarial Net, GAN) 的架构3.5 使用G(z)生成伪图像 4 在Tensorflow上构建DCGANs最后 0 前言 &#…

浅谈一下Vue3的TreeShaking特性

什么是Treeshaking&#xff1f; Treeshaking是一个术语,通常用于描述移除JavaScript中无用代码的过程。 在Vue3中,借助于它的编译优化,可以显著减少打包后的大小。 Vue3的Treeshaking实现 Vue3中的Treeshaking主要通过以下两点实现: 源码级的Tree-shaking Vue3源码采用ES mo…

香港服务器运行不正常原因简析

​  网站在线业务的部署需要服务器的存在。于我们而言&#xff0c;租用正规服务商(正规机房)的服务器&#xff0c;一般情况下是会很少出现问题。但&#xff0c;要知道&#xff0c;再稳定的服务器也有出现问题的时候&#xff0c;香港服务器也不例外&#xff0c;而且恰恰这个原…

【C++系列】STL容器——vector类的例题应用(12)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01;本章主要内容面向接触过C的老铁&#xff0c;下面是收纳的一些例题与解析~ 主要内容含&#xff1a; 目录 【例1] 只出现一次的数字i&#xff08;范围for与模等&#xff08;^&#xff09;)【例2]…

vscode 通过ssh 连接虚拟机vmware(ubuntu)

1.网络连接是否ping的通&#xff08;ubuntu虚拟机使用的是net 连接方式&#xff09; 2.配置环境 ubuntu 需要安装ssh server 服务 &#xff08;1&#xff09;&#xff1a; 安装&#xff08;Ubuntu安装ssh server) apt-get install openssh-server 检查是否ssh server 是否启动…

如何使用LoRA和PEFT微调 Mistral 7B 模型

一、前言 对于大模型在一些安全级别较高的领域&#xff0c;比如在金融服务领域实施人工智能解决方案时&#xff0c;面临的最大挑战之一是数据隐私、安全性和监管合规性。 因为担心数据泄露的问题&#xff0c;很多银行或机构都会回避利用人工智能的优势潜力&#xff0c;尤其是…

微信小程序学习(02)

页面导航 - 声明式导航 1. 导航到 tabBar 页面 tabBar 页面指的是被配置为 tabBar 的页面。 在使用<navigator> 组件跳转到指定的 tabBar 页面时&#xff0c;需要指定 url 属性和 open-type 属性&#xff0c;其中&#xff1a; ⚫ url 表示要跳转的页面的地址&#xff0…

backend-learning: personal blog(1)

问题记录&#xff1a; 跨度太大&#xff0c;无法完成&#xff0c;遂决定从基础学起。 规划路线&#xff1a; 1.完成JAVA与c语言差异部分&#xff0c;&#xff08;注解&#xff0c;其实没多少&#xff09; 2.上springboot官网查看开发手册&#xff0c;了解大致原理。 3. 开始挑…

【VUE】ElementPlus之动态主题色调切换(Vue3 + Element Plus+Scss + Pinia)

前言 关于ElementPlus的基础主题色自定义可以参阅《【VUE】ElementPlus之自定义主题样式和命名空间》 有了上面基础的了解&#xff0c;我们知道ElementPlus的主题色调是基于CSS3变量特性进行全局控制的&#xff0c; 那么接下来我们也基于CSS3变量来实现主题色调的动态切换效果&…

SpringBoot整合MyBatis-Plus详解(二)

文章目录 SpringBoot整合MyBatis-Plus详解&#xff08;二&#xff09;MyBatis-Plus简介条件构造器和常用接口⭐Wrapper介绍QueryWrapper&#xff08;Mapper接口提供的&#xff09;和QueryChainWrapper&#xff08;Service接口提供的&#xff09;案例1&#xff1a;组装查询条件案…

隐私计算python实现Paillier同态加密

1.基本概念 Paillier同态加密是一种公钥加密方案&#xff0c;具有同态加密的特性。它由Pascal Paillier于1999年提出。 Paillier同态加密基于数论问题&#xff0c;其安全性基于大整数分解问题和离散对数问题的困难性。该方案可以用于保护隐私数据&#xff0c;同时支持在加密状态…

在类库中使用ASP.NET Core API

解决办法1 官方文档 解决办法2 将类库修改为web项目&#xff0c;然后设置输出为类库形式即可 <Project Sdk"Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>netcoreapp3.1</TargetFramework><OutputType>Library</O…

剑指JUC原理-3.线程常用方法及状态

常用方法 start和run 调用run public static void main(String[] args) {Thread t1 new Thread("t1") {Overridepublic void run() {log.debug(Thread.currentThread().getName());FileReader.read(Constants.MP4_FULL_PATH);}};t1.run();log.debug("do othe…

[已解决]安装的明明是pytorch-gpu,但是condalist却显示cpu版本,而且torch.cuda.is_available 也是flase

问题; 安装了gpu版本的pytorch&#xff0c;但是显示的torch.cuda.is_available(&#xff09;却是flase。 conda list查看 版本显示只有cpuonly 在网上找了半天&#xff0c;也没有解决办法。 仔细看了一下&#xff0c;发现&#xff0c;有个单独的包叫cpuonly&#xff0c;不知道…

【工具问题】IDEA每次关闭的时候都会弹框显示closing project,然后弹框持续很久就像卡住了

idea关闭的时候出现问题 问题展示为什么会出现这种情况怎么解决 问题展示 我idea已经关闭了&#xff0c;但是这个弹框要持续很久才能关闭 为什么会出现这种情况 我的plugins原本是加载不出来的&#xff0c;所以我按照网上说法去做 怎么解决 file->setting,再如图选择…