408——数据结构 第五章 图

在这里插入图片描述
在这里插入图片描述

1. 图的基本概念

图G由顶点集V边集E组成,记为G = (V, E),其中V(G)表示图G中顶点的有限非空集;E(G)表示图G中顶点之间的关系(边)集合。若V = {v1, v2, … , vn},则用|V|表示图G中顶点的个数,也称图G的阶,E = {(u, v) | u∈V, v∈V},用|E|表示图G中边的条数。

注意:线性表可以是空表,树可以是空树,但图不可以是空,即V一定是非空集

在这里插入图片描述
若E是无向边(简称边)的有限集合时,则图G为 无向图。边是顶点的无序对,记为(v, w)或(w, v),因为(v, w) = (w, v),其中v、w是顶点。可以说顶点w和顶点v互为邻接点。边(v, w)依附于顶点w和v,或者说边(v, w)和顶点v、w相关联。

若E是有向边(也称!)的有限集合时,则图G为 有向图。弧是顶点的有序对,记为<v, w>,其中v、w是顶点,v称为
弧尾,w称为弧头,<v, w>称为从顶点v到顶点w的弧,也称v邻接到w,或w邻接自v。<v, w> ≠ <w, v>

简单图——①不存在重复边;②不存在顶点到自身的边
多重图——图G中某两个结点之间的边数多于一条,又允许顶点通过同一条边和自己关联,则G为多重图
在这里插入图片描述
在这里插入图片描述

顶点-顶点的关系描述
• 路径——顶点vp到顶点vq之间的一条路径是指顶点序列,vp vi1 vi2 vim vq
• 回路——第一个顶点和最后一个顶点相同的路径称为回路或环
• 简单路径——在路径序列中,顶点不重复出现的路径称为简单路径。
• 简单回路——除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路。
• 路径长度——路径上边的数目
• 点到点的距离——从顶点u出发到顶点v的最短路径若存在,则此路径的长度称为从u到v的距离。若从u到v根本不存在路径,则记该距离为无穷(∞)。
• 无向图中,若从顶点v到顶点w有路径存在,则称v和w是连通的
• 有向图中,若从顶点v到顶点w和从顶点w到顶点v之间都有路径,则称这两个顶点是强连通的

在这里插入图片描述
无向图中的极大连通子图称为连通分量
有向图中的极大强连通子图称为有向图的强连通分量,

连通图的 生成树 是包含图中全部顶点的一个极小连通子图
若图中顶点数为n,则它的生成树含有n-1条边。对生成树而言,若砍去它的一条边,则会变成非连通图,若加上一条边则会形成一个回路。

在非连通图中,连通分量的生成树构成了非连通图的生成森林

边的权——在一个图中,每条边都可以标上具有某种含义的数值,该数值称为该边的权值。
带权图/网——边上带有权值的图称为带权图,也称网。
带权路径长度——当图是带权图时,一条路径上所有边的权值之和,称为该路径的带权路径长度。

在这里插入图片描述
在这里插入图片描述

2. 图的存储及基本操作

2.1 邻接矩阵法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
无向图:第i个结点的度=第i行(或第i列)的非零元素个数

在这里插入图片描述
第i个结点的出度=第i行的非零元素个数
第i个结点的入度=第i列的非零元素个数
第i个结点的度=第i行、第i列的非零元素个数之和

邻接矩阵法求顶点的度/出度/入度的时间复杂度为O(|V|)
空间复杂度:O(|V|2) ——只和顶点数相关,和实际的边数无关

适合用于存储稠密图
无向图的邻接矩阵是对称矩阵,可以压缩存储(只存储上三角区/下三角区)

邻接矩阵法的性质:
设图G的邻接矩阵为A(矩阵元素为0/1),则An的元素An [i][j]等于由顶点i到顶点j的长度为n的路径的数目

在这里插入图片描述
在这里插入图片描述

2.2 邻接表法

在这里插入图片描述
在这里插入图片描述

2.3 邻接多重表、十字链表

在这里插入图片描述
空间复杂度:O(|V|+|E|)
如何找到指定顶点的所有出边?——顺着绿色线路找
如何找到指定顶点的所有入边?——顺着橙色线路找
注意:十字链表只用于存储有向图

在这里插入图片描述
在这里插入图片描述

2.4 图的基本操作

• Adjacent(G,x,y):判断图G是否存在边<x, y>或(x, y)。
邻接矩阵O(1),邻接表O(1)~O(|V|)。

• Neighbors(G,x):列出图G中与结点x邻接的边。
邻接矩阵O(1),邻接表O(1)~O(|V|)。

• InsertVertex(G,x):在图G中插入顶点x。
邻接矩阵O(1),邻接表O(1)。

• DeleteVertex(G,x):从图G中删除顶点x。
邻接矩阵O(|V|),删出边:O(1)~O(|V|),删入边:O(|E|)

• AddEdge(G,x,y):若无向边(x, y)或有向边<x, y>不存在,则向图G中添加该边。
邻接矩阵O(1),邻接表O(1)。

• RemoveEdge(G,x,y):若无向边(x, y)或有向边<x, y>存在,则从图G中删除该边。
邻接矩阵O(1),邻接表O(1)~O(|V|)。

• FirstNeighbor(G,x):求图G中顶点x的第一个邻接点,若有则返回顶点号。若x没有邻接点或图中不存在x,则返回-1。
邻接矩阵O(1)~O(|V|),邻接表O(1)。

• NextNeighbor(G,x,y):假设图G中顶点y是顶点x的一个邻接点,返回除y之外顶点x的下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1。
邻接矩阵O(1)~O(|V|),邻接表O(1)。

• Get_edge_value(G,x,y):获取图G中边(x, y)或<x, y>对应的权值。
邻接矩阵O(1),邻接表O(1)~O(|V|)。

• Set_edge_value(G,x,y,v):设置图G中边(x, y)或<x, y>对应的权值为v。
邻接矩阵O(1),邻接表O(1)~O(|V|)。

3. 图的遍历

3.1 深度优先搜索(DFS)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2 广度优先搜索(BFS)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
空间复杂度:最坏情况,辅助队列⼤⼩为 O(|V|)
在这里插入图片描述
在这里插入图片描述

4. 图的基本应用

4.1 最小(代价)生成树

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

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

Prim 算法(普⾥姆): 从某⼀个顶点开始构建⽣成树;每次将代价最⼩的新顶点纳⼊⽣成树,直到所有顶点都纳⼊为⽌。

Kruskal 算法(克鲁斯卡尔): 每次选择⼀条权值最⼩的边,使这条边的两头连通(原本已经连通的就不选)直到所有结点都连通。
在这里插入图片描述

4.2 最短路径

4.2.1 BFS算法

在这里插入图片描述

4.2.2 Dijkstra算法

迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。

/*
测试数据 教科书 P189 G6 的邻接矩阵 其中 数字 1000000 代表无穷大
6
1000000 1000000 10 100000 30 100
1000000 1000000 5 1000000 1000000 1000000
1000000 1000000 1000000 50 1000000 1000000
1000000 1000000 1000000 1000000 1000000 10
1000000 1000000 1000000 20 1000000 60
1000000 1000000 1000000 1000000 1000000 1000000
结果:
D[0]   D[1]   D[2]   D[3]   D[4]   D[5]
 0   1000000   10     50     30     60
*/
#include <iostream>
#include <cstdio>
#define MAX 1000000
using namespace std;
int arcs[10][10];//邻接矩阵
int D[10];//保存最短路径长度
int p[10][10];//路径
int final[10];//若final[i] = 1则说明 顶点vi已在集合S中
int n = 0;//顶点个数
int v0 = 0;//源点
int v,w;
void ShortestPath_DIJ()
{
     for (v = 0; v < n; v++) //循环 初始化
     {
          final[v] = 0; D[v] = arcs[v0][v];
          for (w = 0; w < n; w++) p[v][w] = 0;//设空路径
          if (D[v] < MAX) {p[v][v0] = 1; p[v][v] = 1;}
     }
     D[v0] = 0; final[v0]=1; //初始化 v0顶点属于集合S
     //开始主循环 每次求得v0到某个顶点v的最短路径 并加v到集合S中
     for (int i = 1; i < n; i++)
     {
          int min = MAX;
          for (w = 0; w < n; w++)
          {
               //我认为的核心过程--选点
               if (!final[w]) //如果w顶点在V-S中
               {
                    //这个过程最终选出的点 应该是选出当前V-S中与S有关联边
                    //且权值最小的顶点 书上描述为 当前离V0最近的点
                    if (D[w] < min) {v = w; min = D[w];}
               }
          }
          final[v] = 1; //选出该点后加入到合集S中
          for (w = 0; w < n; w++)//更新当前最短路径和距离
          {
               /*在此循环中 v为当前刚选入集合S中的点
               则以点V为中间点 考察 d0v+dvw 是否小于 D[w] 如果小于 则更新
               比如加进点 3 则若要考察 D[5] 是否要更新 就 判断 d(v0-v3) + d(v3-v5) 的和是否小于D[5]
               */
               if (!final[w] && (min+arcs[v][w]<D[w]))
               {
                    D[w] = min + arcs[v][w];
                   // p[w] = p[v];
                    p[w][w] = 1; //p[w] = p[v] + [w]
               }
          }
     }
}
 
 
int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
         for (int j = 0; j < n; j++)
         {
              cin >> arcs[i][j];
         }
    }
    ShortestPath_DIJ();
    for (int i = 0; i < n; i++) printf("D[%d] = %d\n",i,D[i]);
    return 0;
}

Dijkstra 算法不适⽤于有负权值的带权图

4.2.3 Floyd算法

Floyd算法:求出每⼀对顶点之间的最短路径
使⽤动态规划思想,将问题的求解分为多个阶段
对于n个顶点的图G,求任意⼀对顶点 Vi —> Vj 之间的最短路径可分为如下⼏个阶段:
#初始:不允许在其他顶点中转,最短路径是?
#0:若允许在 V0 中转,最短路径是?
#1:若允许在 V0、V1 中转,最短路径是?
#2:若允许在 V0、V1、V2 中转,最短路径是?

#n-1:若允许在 V0、V1、V2 …… Vn-1 中转,最短路径是?

在这里插入图片描述
在这里插入图片描述

4.3 拓扑排序

有向无环图描述表达式

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

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

AOV⽹(Activity On Vertex NetWork,⽤顶点表示活动的⽹):
⽤DAG图(有向⽆环图)表示⼀个⼯程。顶点表示活动,有向边<Vi, Vj>表示活动Vi必须先于活动Vj进⾏

拓扑排序:在图论中,由⼀个有向⽆环图的顶点组成的序列,当且仅当满⾜下列条件时,称为该图的⼀个拓扑排序:
① 每个顶点出现且只出现⼀次。② 若顶点A在序列中排在顶点B的前⾯,则在图中不存在从顶点B到顶点A的路径。

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

拓扑排序的实现:
① 从AOV⽹中选择⼀个没有前驱(⼊度为0)的顶点并输出。
② 从⽹中删除该顶点和所有以它为起点的有向边。
③ 重复①和②直到当前的AOV⽹为空或当前⽹中不存在⽆前驱的顶点为⽌。

在这里插入图片描述

逆拓扑排序:
对⼀个AOV⽹,如果采⽤下列步骤进⾏排序,则称之为逆拓扑排序:
① 从AOV⽹中选择⼀个没有后继(出度为0)的顶点并输出。
② 从⽹中删除该顶点和所有以它为终点的有向边。
③ 重复①和②直到当前的AOV⽹为空。
对⼀个AOV⽹逆拓扑排序:
① 从AOV⽹中选择⼀个没有后继(出度为0)的顶点并输出。
② 从⽹中删除该顶点和所有以它为终点的有向边。
③ 重复①和②直到当前的AOV⽹为空。

在这里插入图片描述

在这里插入图片描述

4.4 关键路径

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

AOE⽹具有以下两个性质:
① 只有在某顶点所代表的事件发⽣后,从该顶点出发的各有向边所代表的活动才能开始;
② 只有在进⼊某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发⽣。另外,有些活动是可以并⾏进⾏的。

在AOE⽹中仅有⼀个⼊度为0的顶点,称为开始顶点(源点),它表示整个⼯程的开始;
也仅有⼀个出度为0的顶点,称为结束顶点(汇点),它表示整个⼯程的结束。
从源点到汇点的有向路径可能有多条,所有路径中,具有最⼤路径⻓度的路径称为关键路径,⽽把关键路径上的活动称为关键活动。
完成整个⼯程的最短时间就是关键路径的⻓度,若关键活动不能按时完成,则整个⼯程的完成时间就会延⻓。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
若关键活动耗时增加,则整个⼯程的⼯期将增⻓。
缩短关键活动的时间,可以缩短整个⼯程的⼯期。
当缩短到⼀定程度时,关键活动可能会变成⾮关键活动。
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值