【王道数据结构】第六章(下) | 图的应用

news2024/11/28 13:46:45

目录

一、最小生成树

二、最短路径

三、有向⽆环图描述表达式

四、拓扑排序

五、关键路径


一、最小生成树

1、最小生成树的概念

对于一个带权连通无向图G = (V,E),生成树不,每棵树的权(即树中所有边上的权值之和)也可能不同。设R为G的所有生成树的集合,若T为R中边的权值之和最小的生成树,则T称为G的最小生成树(Minimum-Spannino-Tree,MST).。

  • 最小生成树可能有多个,但边的权值之和总是唯一且最小的。
  • 最小生成树的边数 =顶点数 -1。砍掉一条则不连通,增加一条边则会出现回路。
  • 如果一个连通图本身就是一棵树,则其最小生成树就是它本身。
  • 只有连通图才有生成树,非连通图只有生成森林。

2、求最小生成树的两种方法

  • Prim算法
  • Kruskal算法 

Prim算法(普里姆):从某一个顶点开始构建生成树;每次将代价最小的新顶点纳入生成树,直到所有顶点都纳入为止。时间复杂度: O(V2)适合用于边稠密图

Kruskal算法(克鲁斯卡尔):每次选择一条权值最小的边,使这条边的两头连通(原本已经连通的就不选)直到所有结点都连通。时间复杂度: O(lEllog2lEl )适合用于边稀疏图

二、最短路径

1.无权图的单源最短路径问题——BFS算法

使用 BFS算法求无权图的最短路径问题,需要使用三个数组

  • d[]数组用于记录顶点 u 到其他顶点的最短路径。
  • path[]数组用于记录最短路径从那个顶点过来。
  • visited[]数组用于记录是否被访问过。

代码时间

#define MAX_LENGTH 2147483647			//地图中最大距离,表示正无穷

// 求顶点u到其他顶点的最短路径
void BFS_MIN_Disrance(Graph G,int u){
    for(i=0; i<G.vexnum; i++){
        visited[i]=FALSE;				//初始化访问标记数组
        d[i]=MAX_LENGTH;				//初始化路径长度
        path[i]=-1;						//初始化最短路径记录
    }
    InitQueue(Q);						//初始化辅助队列
    d[u]=0;
    visites[u]=TREE;
    EnQueue(Q,u);
    while(!isEmpty[Q]){					//BFS算法主过程
        DeQueue(Q,u);					//队头元素出队并赋给u
        for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w)){
            if(!visited[w]){
                d[w]=d[u]+1;
                path[w]=u;
                visited[w]=TREE;
                EnQueue(Q,w);			//顶点w入队
            }
        }
    }
}

2.单源最短路径问题——Dijkstra算法

  1. BFS算法的局限性:BFS算法求单源最短路径只适⽤于⽆权图,或所有边的权值都相同的图。
  2. Dijkstra算法能够很好的处理带权图的单源最短路径问题,但不适⽤于有负权值的带权图。
  3. 使用 Dijkstra算法求最短路径问题,需要使用三个数组:
  • final[]数组用于标记各顶点是否已找到最短路径。
  • dist[]数组用于记录各顶点到源顶点的最短路径长度。
  • path[]数组用于记录各顶点现在最短路径上的前驱。

代码实现

#define MAX_LENGTH = 2147483647;

// 求顶点u到其他顶点的最短路径
void BFS_MIN_Disrance(Graph G,int u){
    for(int i=0; i<G.vexnum; i++){		//初始化数组
        final[i]=FALSE;
        dist[i]=G.edge[u][i];
        if(G.edge[u][i]==MAX_LENGTH || G.edge[u][i] == 0)
            path[i]=-1;
        else
            path[i]=u;
        final[u]=TREE;
    }
 
  	for(int i=0; i<G.vexnum; i++){
        int MIN=MAX_LENGTH;
        int v;
		// 循环遍历所有结点,找到还没确定最短路径,且dist最⼩的顶点v
        for(int j=0; j<G.vexnum; j++){
	        if(final[j]!=TREE && dist[j]<MIN){
 	            MIN = dist[j];
                v = j;
            }
        }
        final[v]=TREE;
        // 检查所有邻接⾃v的顶点路径长度是否最短
        for(int j=0; j<G.vexnum; j++){
	        if(final[j]!=TREE && dist[j]>dist[v]+G.edge[v][j]){
            	dist[j] = dist[v]+G.edge[v][j];
                path[j] = v;
            }
        }
	}
}

3.各顶点间的最短路径问题——Floyd算法

  1. Floyd算法:求出每⼀对顶点之间的最短路径,使⽤动态规划思想,将问题的求解分为多个阶段。

  2. Floyd算法可以⽤于负权值带权图,但是不能解决带有“负权回路”的图(有负权值的边组成回路),这种图有可能没有最短路径。

  3. Floyd算法使用到两个矩阵:

    1. dist[][]:目前各顶点间的最短路径。
    2. path[][]:两个顶点之间的中转点。
  4. 代码实现:

int dist[MaxVertexNum][MaxVertexNum];
int path[MaxVertexNum][MaxVertexNum];

void Floyd(MGraph G){
	int i,j,k;
    // 初始化部分
	for(i=0;i<G.vexnum;i++){
		for(j=0;j<G.vexnum;j++){
			dist[i][j]=G.Edge[i][j];		
			path[i][j]=-1;
		}
	}
    // 算法核心部分
	for(k=0;k<G.vexnum;k++){
		for(i=0;i<G.vexnum;i++){
			for(j=0;j<G.vexnum;j++){
	   	    	if(dist[i][j]>dist[i][k]+dist[k][j]){
	   		    	dist[i][j]=dist[i][k]+dist[k][j];
	   		    	path[i][j]=k;
                }
			}
        }
    }
}

4.最短路径算法比较:

BFS算法Dijkstra算法Floyd算法
无权图
带权图
带负权值的图
带负权回路的图
时间复杂度O(|V|^2)或(|V|+|E|)O(|V|^2)O(|V|^3)
通常⽤于求⽆权图的单源最短路径求带权图的单源最短路径求带权图中各顶点间的最短路径

三、有向⽆环图描述表达式

1.有向⽆环图:若⼀个有向图中不存在环,则称为有向⽆环图,简称 DAG图(Directed Acyclic Graph)。

DAG描述表达式:((a+b)*(b*(c+d))+(c+d)*e)*((c+d)*e)

2.有向无环图描述表达式的解题步骤:

  • Step 1:把各个操作数不重复地排成一排
  • Step 2:标出各个运算符的生效顺序 (先后顺序有点出入无所谓)
  • Step 3:按顺序加入运算符,注意“分层”
  • Step 4:从底向上逐层检查同层的运算符是否可以合体

四、拓扑排序

1.AOV网(Activity on Vertex Network,用顶点表示活动的网):用DAG图(有向无环图)表示一个工程。顶点表示活动,有向边<Vi,Vj>表示活动Vi必须先于活动Vj进行。

2.拓扑排序:在图论中,由⼀个有向⽆环图的顶点组成的序列,当且仅当满⾜下列条件时,称为该图的⼀个拓扑排序:

  • 每个顶点出现且只出现⼀次;
  • 若顶点 A 在序列中排在顶点 B 的前⾯,则在图中不存在从顶点 B 到顶点 A 的路径。
  • 或定义为:拓扑排序是对有向⽆环图的顶点的⼀种排序,它使得若存在⼀条从顶点 A 到顶点 B 的路径,则在排序中顶点 B 出现在顶点 A 的后⾯。每个 AOV ⽹都有⼀个或多个拓扑排序序列。
     

3.拓扑排序的实现:

  • 从AoV网中选择一个没有前驱 (入度为0) 的顶点并输出
  • 从网中删除该顶点和所有以它为起点的有向边。
  • 重复D和2直到当前的AOV网为空或当前网中不存在无前驱的顶点为止

4.代码实现拓扑排序(邻接表实现):

#define MaxVertexNum 100			//图中顶点数目最大值

typedef struct ArcNode{				//边表结点
    int adjvex;						//该弧所指向的顶点位置
    struct ArcNode *nextarc;		//指向下一条弧的指针
}ArcNode;

typedef struct VNode{				//顶点表结点
    VertexType data;				//顶点信息
    ArcNode *firstarc;				//指向第一条依附该顶点的弧的指针
}VNode,AdjList[MaxVertexNum];

typedef struct{
    AdjList vertices;				//邻接表
    int vexnum,arcnum;				//图的顶点数和弧数
}Graph;								//Graph是以邻接表存储的图类型

// 对图G进行拓扑排序
bool TopologicalSort(Graph G){
    InitStack(S);					//初始化栈,存储入度为0的顶点
    for(int i=0;i<g.vexnum;i++){
        if(indegree[i]==0)
            Push(S,i);				//将所有入度为0的顶点进栈
    }
    int count=0;					//计数,记录当前已经输出的顶点数
    while(!IsEmpty(S)){				//栈不空,则存入
        Pop(S,i);					//栈顶元素出栈
        print[count++]=i;			//输出顶点i
        for(p=G.vertices[i].firstarc;p;p=p=->nextarc){
            //将所有i指向的顶点的入度减1,并将入度为0的顶点压入栈
            v=p->adjvex;
            if(!(--indegree[v]))
                Push(S,v);			//入度为0,则入栈
        }
    }
    if(count<G.vexnum)
        return false;				//排序失败
    else
        return true;				//排序成功
}

五、关键路径

1.AOE 网:在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如 完成活动所需的时间),称之为⽤边表示活动的⽹络,简称 AOE ⽹ (Activity On Edge NetWork)。

2.AOE⽹具有以下两个性质:

  1. 只有在某顶点所代表的事件发⽣后,从该顶点出发的各有向边所代表的活动才能开始;
  2. 只有在进⼊某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发⽣。 另外,有些活动是可以并⾏进⾏的。

3.在 AOE ⽹中仅有⼀个⼊度为 0 的顶点,称为开始顶点(源点),它表示整个⼯程的开始; 也仅有⼀个出度为 0 的顶点,称为结束顶点(汇点),它表示整个⼯程的结束。

  • 从源点到汇点的有向路径可能有多条,所有路径中,具有最⼤路径⻓度的路径称为关键路径,⽽把关键路径上的活动称为关键活动。
  • 完成整个⼯程的最短时间就是关键路径的⻓度,若关键活动不能按时完成,则整个 ⼯程的完成时间就会延⻓。

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

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

相关文章

【2023】Prometheus-接入Alertmanager并实现邮件告警通知

目录1.使用二进制方式安装Alertmanager2.Alertmanager配置3.alert接入prometheus4.创建告警配置文件&#xff08;在prometheus服务器&#xff09;5.测试告警1.使用二进制方式安装Alertmanager 下载安装包 wget https://github.com/prometheus/alertmanager/releases/download…

Python pip工具使用

一、pip工具 1、pip简介 pip 是一个通用的 Python包管理工具。提供了对 Python 包的查找、下载、安装、卸载的功能&#xff0c;便于我们对 Python的资源包进行管理。 在安装 Python时&#xff0c;会自动下载并且安装 pip。 &#xff08;1&#xff09;查看是否安装 pip 查看…

C/C++ :程序环境和预处理(上)

目录 程序的编译链接过程 1.编译过程中的预处理阶段 2.编译过程中的正式编译阶段 3.编译过程中的汇编阶段 4.链接过程 程序的编译链接过程 一个程序的源码文件要经过复杂的编译链接过程才能被转换为可执行的机器指令(二进制指令) 编译链接过程概述&#xff1a; 编译过程&…

java顺序存储二叉树应用实例

八大排序算法中的堆排序&#xff0c;就会使用到顺序存储二叉树。 1.线索化二叉树 1.1先看一个问题 将数列 {1, 3, 6, 8, 10, 14 } 构建成一颗二叉树. n17 问题分析: 当我们对上面的二叉树进行中序遍历时&#xff0c;数列为 {8, 3, 10, 1, 6, 14 } 但是 6, 8, 10, 14 这几个…

windows装双系统,添加ubuntu

1、查看分区 此电脑右键---管理----磁盘管理----选有空闲位置的硬盘右键----压缩卷 就会出现空闲的卷 2 制作U盘&#xff0c;U盘初始是空的 下载rufus win10系统怎么查看磁盘分区形式 【百科全说】 (bkqs.com.cn) 双击打开----如下配置 出现这个提示&#xff0c;照做 …

内存数据库Apache Derby、H2

概述 传统关系型数据库涉及大量的工作&#xff0c;如果想在Java应用程序里使用MySQL数据库&#xff0c;至少需要如下步骤&#xff1a; 安装&#xff08;可选&#xff1a;配置用户名密码&#xff09;建表&#xff08;要么从命令行进入&#xff0c;要么安装一个可视化工具&…

Java基础-网络编程

1. 网络编程入门 1.1 网络编程概述 计算机网络 是指将地理位置不同的具有独立功能的多台计算机及其外部设备&#xff0c;通过通信线路连接起来&#xff0c;在网络操作系统&#xff0c;网络管理软件及网络通信协议的管理和协调下&#xff0c;实现资源共享和信息传递的计算机系统…

Springboot扩展点之InstantiationAwareBeanPostProcessor

前言前面介绍了Springboot的扩展点之BeanPostProcessor&#xff0c;再来介绍另一个扩展点InstantiationAwareBeanPostProcessor就容易多了。因为InstantiationAwareBeanPostProcessor也属于Bean级的后置处理器&#xff0c;还继于BeanPostProcessor&#xff0c;因此Instantiatio…

vue-cli3创建Vue项目

文章目录前言一、使用vue-cli3创建项目1.检查当前vue的版本2.下载并安装Vue-cli33.使用命令行创建项目二、关于配置前言 本文讲解了如何使用vue-cli3创建属于自己的Vue项目&#xff0c;如果本文对你有所帮助请三连支持博主&#xff0c;你的支持是我更新的动力。 下面案例可供…

【C++】类与对象(上)

文章目录一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装①访问限定符②封装五、类的作用域六、类的实例化七、类对象模型①如何计算类对象大小②类对象的存储方式③结构体中内存对齐规则八、this指针①this指针的引出②this指针的特性一、面…

XCP实战系列介绍07-使用ASAP2 Editor生成A2l文件详解

本文框架 1.概述2. A2L文件编辑及生成2.1 新建项目工程2.2 加载elf文件2.3 A2L文件的项目属性配置2.4 DAQ事件的设定2.5 添加观察量2.6 添加标定量2.7 编译生成A2l1.概述 在前面一篇文章《看了就会的XCP协议介绍》中详细介绍了XCP的协议,在《XCP实战系列介绍01-测量与标定底层…

JavaScript 类继承

JavaScript 类继承 JavaScript 类继承使用 extends 关键字。 继承允许我们依据另一个类来定义一个类&#xff0c;这使得创建和维护一个应用程序变得更容易。 super() 方法用于调用父类的构造函数。 当创建一个类时&#xff0c;您不需要重新编写新的数据成员和成员函数&…

synchronized和ReentrantLock之间的区别

synchronized和ReentrantLock的区别 synchronized是一个关键字&#xff0c;是JVM内部实现的&#xff1b;ReentrantLock是标准库的一个类&#xff0c;是JVM外部基于Java实现的。synchronized在申请锁失败时会死等&#xff1b;ReentrantLock可以通过tryLock的方式等待一段时间就…

偏微分方程约束下的优化控制问题(PDE-constrained optimal control problems)

优化控制问题介绍 优化控制问题的数学形式 {min⁡(y(x),u(x))∈YUJ(y(x),u(x)),s.t. F(y(x),u(x))0in Ω,and u(x)∈Uad,\left\{\begin{aligned} &\min _{(y(\mathbf{x}), u(\mathbf{x})) \in Y \times U} J(y(\mathbf{x}), u(\mathbf{x}) ),\\ &\text { s.t. } \ \…

Python列表的元素比较

在用python处理多个列表元素时&#xff0c;需要处理的信息一般比较多且杂。这时运用Python列表元素比较的方法&#xff0c;就能快速处理列表信息&#xff0c;能更轻松访问每个元素。1 问题如何运用Python列表的元素比较解决问题。2 方法方法一 for循环&#xff0c;此情况是list…

Spring 事务【隔离级别与传播机制】

Spring 事务【隔离级别与传播机制】&#x1f34e;一.事务隔离级别&#x1f352;1.1 事务特性回顾&#x1f352;1.2 事务的隔离级别(5种)&#x1f352;1.3 事务隔离级别的设置&#x1f34e;二.Spring 事务传播机制&#x1f352;2.1 Spring 事务传播机制的作用&#x1f352;2.2 事…

描述性统计图表——箱线图

文章目录1、分位数1.1、分位数的概念1.2、特殊分位数1.3、分位数的计算2、箱线图2.1、概念2.2、作图步骤2.3、箱线图的作用2.3.1、定位异常值2.3.2、偏态和尾重2.3.3、数据的形状1、分位数 1.1、分位数的概念 分位数&#xff08;Quantile&#xff09;&#xff0c;亦称分位点&a…

红黑树简析

一. 概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路径会比其他路径长出俩倍&#xff0c;因而是…

java 自定义json解析注解 复杂json解析

java 自定义json解析注解 复杂json解析 工具类 目录java 自定义json解析注解 复杂json解析 工具类1.背景2、需求-各式各样的json一、一星难度json【json对象中不分层】二、二星难度json【json对象中出现层级】三、三星难度json【json对象中存在数组】四、四星难度json【json对象…

【c++之于c的优化 - 下】

前言 一、inline 概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 如果在上述函数前增加inline关键字将其改成内联函数&#xff0c;在编译期间编译…