7 > 数据结构与算法 图

概念

  1. G G G由顶点集V和边集E组成, G = ( V , E ) G=(V,E) G=(V,E) V ( G ) V(G) V(G)为图 G G G顶点的非空集合, V ( E ) V(E) V(E)为图 G G G边的非空结合。 ∣ V ∣ |V| V表示顶点个数(称为 G G G的阶), ∣ E ∣ |E| E表示边条数。
  2. 图不可以为空,V 一定是非空,但 E 可以为空(可以没有边)。
  3. 无向图:边没有方向,简称边。(v,w) = (w,v)
    1. 顶点的度:该顶点连接了多少条边,记作: T D ( v ) TD(v) TD(v)

      度之和: ∑ i = 1 n T D ( v i ) = 2 e          ( n 个顶点, e 条边 ) 度之和:\sum^n_{i=1}TD(v_i)=2e~~~~~~~_{(n个顶点,e条边)} 度之和:i=1nTD(vi)=2e       (n个顶点,e条边)

    2. 路径:顶点到另一个顶点可以经过的一系列的其他顶点。

    3. 回路:走了一个环。(简单回路:所经回路没有重复出现的点)

    4. 简单路径:顶点不重复出现的路径。

    5. 简单回路:除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路。

    6. 路径长度:总共经过几条边。

    7. 顶点之间距离:最短路径长度。若两个顶点之间没有路径则记为   ∞ ~\infty  

    8. 连通:有路径则有连通。

  4. 有向图:边有方向,简称弧,箭头方向为弧头,箭尾为弧尾。(等于是向量)<v,w> ≠ <w,v>
    1. 顶点的度:入度和出度之和,记作: T D ( v ) = I D ( v ) + O D ( v ) TD(v)=ID(v) + OD(v) TD(v)=ID(v)+OD(v)

      1. 入度:顶点上有多少个箭头,记作: I D ( v ) ID(v) ID(v)
      2. 出度:顶点上有多少个箭尾,记作: O D ( v ) OD(v) OD(v)

      度之和: ∑ i = 1 n I D ( v i ) + ∑ i = 1 n O D ( v i ) = 2 e   ( n 个顶点, e 条边 ) 度之和:\sum^n_{i=1}ID(v_i)+\sum^n_{i=1}OD(v_i)=2e~_{(n个顶点,e条边)} 度之和:i=1nID(vi)+i=1nOD(vi)=2e (n个顶点,e条边)

    2. 路径:必须按照箭头方向走,其所经过的其他顶点。

    3. 回路:和无向图一样

    4. 简单路径:和无向图一样

    5. 路径长度:和无向图一样

    6. 顶点距离:和无向图一样

    7. 连通:两顶点间有双向箭头连接,为强连通图。

  5. 简单图:不存在重复边,不存在自己到自己的边。
  6. 多重图:存在重复边,存在自己到自己的边。
  7. 连通图:
    1. 无向图:全部顶点都连通。(都有边相连,至少有 n − 1 n-1 n1 条边)(非连通图至多有 C n − 1 2 C_{n-1}^2 Cn12 条边,多一条都是连通图)
    2. 有向图:任意顶点强连通,为强连通图。(强连通图至少有 n 条边(回路))
  8. 子图:从原图中截取出来的,记作 G ′ = ( V ′ , E ′ ) G'= ( V', E') G=(V,E)
    1. 生成子图:包含原图所有顶点,但不一定包含所有边,记作 V ( G ′ ) = V ( G ) V( G') = V( G ) V(G)=V(G)
  9. 连通分量:
    1. 无向图:所有子图中的最大子图就是这个原图的连通分量。(子图包含的尽可能多)
    2. 有向图:所有子图中的最大强连通子图就是这个原图的强连通分量。
  10. 连通图的生成树:
    1. 无向图:包含所有顶点,但在原图的基础上去掉所有无影响的边。(极小连通子图)(生成树可能有多个)(例如:各种修路方案)
  11. 生成森林:在非连通图中,所有连通分量的生成树构成原图的连通森林。
  12. 带权图:边带上权值,其图也可称为 网。带权路径长度,路径上所有边之和。
  13. 无向完全图:每两个顶点之间都有一条边连接,最多有 C n 2 C_n^2 Cn2 条边。
  14. 有向完全图:每两个顶点之间都有两条箭头连接,最多有 2 C n 2 2C_n^2 2Cn2 条边。
  15. 稀疏图:边很少的图,反之为稠密图。
  16. 树:= 生成树
  17. 有向树:只有一个顶点出度为 0 (根节点),其余所有顶点的入度为 1 。(非强连通图)

存储结构

  1. 邻接矩阵法:(顺序存储)

    1. 无向图:矩阵中 1 表示两顶点相互连接,0 表示不连接。

    2. 有向图:矩阵中 1 表示有箭头指向,0表示没有箭头指向。(先行后列)

    3. 性能:空间复杂度 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2) ,无向图为对称矩阵,可以采用压缩矩阵存储。

    4. 适用范围:适合存储稠密图。(空间复杂度高)

    5. 表示方式:唯一

    6. 性质:若图的邻接矩阵为 A ,则 A n A^n An 的的元素 A n [ i ] [ j ] A^n[i][j] An[i][j] 表示由顶点 i i i 到顶点 j j j 的长度为 n n n 的路径数目。(路径长度为几就是几个矩阵相乘)

      在这里插入图片描述

  2. 邻接表法:(顺序 + 链式存储)

    1. 存储结构:

      在这里插入图片描述

      #define  MAX_VERTEX_NUM 20//最大顶点个数
      #define  VertexType int//顶点数据的类型
      #define  InfoType int//图中弧或者边包含的信息的类型
      
      typedef struct ArcNode{
          int adjvex;//邻接点在数组中的位置下标
          struct ArcNode * nextarc;//指向下一个邻接点的指针
          InfoType * info;//信息域
      }ArcNode;
      
      typedef struct VNode{
          VertexType data;//顶点的数据域
          ArcNode * firstarc;//指向邻接点的指针
      }VNode,AdjList[MAX_VERTEX_NUM];//存储各链表头结点的数组
      
      typedef struct {
          AdjList vertices;//图中顶点的数组
          int vexnum,arcnum;//记录图中顶点数和边或弧数
          int kind;//记录图的种类
      }ALGraph;
      
    2. 空间复杂度:

      1. 无向图: O ( 2 e + v ) = O ( e + v ) O(2e+v)=O(e+v) O(2e+v)=O(e+v)
      2. 有向图: O ( e + v ) O(e+v) O(e+v)
    3. 适用范围:适用于存储稀疏图。

    4. 表示方式:不唯一(各个边在孩子中出现的顺序不唯一)

  3. 十字链表:(存储有向图)

    1. 空间复杂度: O ( e + v ) O(e+v) O(e+v)

      在这里插入图片描述

  4. 邻接多重表:(存储无向图)

    1. 空间复杂度: O ( e + v ) O(e+v) O(e+v)

      在这里插入图片描述

  5. 发展过程:

    1. 邻接矩阵:可以简单明了的反映各个顶点和边之间的关系,但对于稀疏图来说浪费空间 ⇒
    2. 邻接表:克服了邻接矩阵的劣势,但对于有(无)向图来说查找存在劣势 ⇒
      1. 邻接多重表:克服了邻接表不能高效查找无向图顶点之间是否存在边的问题;
      2. 十字链表法:克服了邻接表不能高效查找有向图顶点入度的问题。
邻接矩阵邻接表十字链表邻接多重表
空间复杂度O( e^2 )无向图:O( v + 2e )有向图:O( v + e )O( v + e )O( v + e )
适用范围稠密图稀疏图有向图无向图
表示方式唯一不唯一不唯一不唯一
计算度、出度、入度必须遍历对应行、列有向图度、入度不方便,其余方便方便方便
找相邻边必须遍历对应行、列有向图找顶点“入边”不方便,其余方便方便方便

基本操作 ( 对于邻接表和邻接矩阵 ) _{(对于邻接表和邻接矩阵)} (对于邻接表和邻接矩阵)

  1. 增删改查…
  2. 广度优先遍历(BFS):队列实现(最坏空间复杂度: O ( ∣ V ∣ ) O(|V|) O(V) )(树的层次遍历)
    1. 如果是连通图:

      1. 邻接矩阵法:输出的元素序列与矩阵中元素排列顺序相同。时间复杂度: O ( v 2 ) O(v^2) O(v2)
      2. 邻接表法:输出的元素序列与链元素的排列顺序相同。时间复杂度: O ( v + e ) O(v+e) O(v+e)
    2. 对于邻接矩阵遍历序列唯一,邻接表遍历数列不唯一。

    3. 如果是非连通图:需多次调用算法。

    4. 广度优先生成树:通过广度优先遍历生成的树。(邻接表访问顺序不同,生成树不同)
      在这里插入图片描述

    5. 广度优先生成森林:遍历非连通图生成。

  3. 深度优先遍历(DFS):用栈实现(树的先序遍历)
    1. 最坏空间复杂度: O ( ∣ V ∣ ) O(|V|) O(V),主要来自递归栈

    2. 时间复杂度:和广度一样。

      在这里插入图片描述

    3. 深度优先生成树:访问序列不唯一,树不唯一。

    4. 深度优先生产森林:树不唯一,森林不唯一。

    5. 和广度一样,有向图调用算法次数一样的,只能向箭头方向访问。

应用

  1. 最小生成树(MST):

    1. 对象:带权无向图
    2. Prim算法:从某一个顶点开始构造树,每次选择代价最小的新顶点加入。(适合用于边稠密图)(可能存在多个最小生成树)
      1. 时间复杂度:只与顶点个数有关, O ( V 2 ) O(V^2) O(V2)
      2. 算法实现:挑选一个节点加入树,每次循环扫描所有节点找到距离短的,然后加入树;之后跳到新加入的节点继续循环扫描。
    3. Kruskal算法:每次挑选权值最小的边,让两顶点加入。(适合用于边稀疏图)
      1. 时间复杂度: O ( E log ⁡ 2 E ) O(E\log_2E) O(Elog2E)
      2. 算法实现:先将所有边按权值排序,依次查找排序表,先查询边两顶点是否属于同一集合,如果不是则将两顶点加入同一集合,如果是则跳过;依次重复。(需要用到并查集,每次判定以两个顶点为根的两个集合是否元素一样,是则为同一)(总共循环 e 轮,每轮都用并查集判断 log ⁡ 2 e \log_2e log2e
    4. 若图的各边权值均不相同,则 MST 唯一。
    5. 所有 MST 的总代价一定唯一。
    6. 权值问题:
      1. 所有权值最小的边不一定出现在所有 MST 中;
      2. 权值最小的边一定出现在某一个 MST 中。
  2. 最短路径:

    1. BFS算法:广度优先求无向图的最短路径。(只能用于每条边权重都一样的图)

    2. Dijkstra算法:求无向图和有向图的一个节点到其他各点的最短路径。(时间复杂度: O ( v 2 ) O(v^2) O(v2))(不适合带负权值的图)(DFS搜索)

    3. Floyd算法:求无向图和有向图的各个点到各个点的最短路径。(时间复杂度: O ( v 3 ) O(v^3) O(v3),空间复杂度: O ( v 2 ) O(v^2) O(v2))(可用于带负权的图)(但不能解决带负权回路的图)

      //需要两个矩阵,一个为邻接矩阵,一个为路径矩阵
      for (int i=0;i<MAXSIZE;i++){      //每一个节点都作为一次中转节点,总共有i个节点
      			for (int j=0;j<MAXSIZE;j++){      //j为行号,k为列号
      				for (int k=0;k<MAXSIZE;k++){
      						if (linjie[j][k]>linjie[i][k]+linjie[j][i]){//以Vi为中转点的路径更短
      								linjie[j][k]=linjie[i][k]+linjie[j][i];//更新最短路径
      								lujin[j][k]=i;	        //更新路由表(中转点)
      						}
      				}
      		}
      }
      
    BFS算法Dijkstra算法Floyd算法
    无权图
    带权图×
    带负权图××
    带负权图且回路×××
    时间复杂度 矩阵 : O ( v 2 )    表 : O ( v + e ) 矩阵:O( v^2 )~~~表:O( v+e ) 矩阵:O(v2)   :O(v+e) O ( v 2 ) O( v^2 ) O(v2) O ( v 3 ) O( v^3 ) O(v3)
    适用于无权图或所有路径均相等的有权图的单源最短路径带权图单源最短路径(用于求各个顶点间最短路径时,时间复杂度为 O ( v 3 ) O( v^3 ) O(v3)带权图各顶点间最短路径

有向无环图(DAG图)

  1. 有向图中不存在回路。(王道 6.4_5)
  2. DAG描述算数表达式:将表达式化成二叉树,合并算数表达式中的 ”相同“ 的节点。

拓扑排序

  1. AOV网(DAG图):表示一个工程,有向边 < v i , v j > <v_i,v_j> <vi,vj>表示活动 v i v_i vi 先于 v j v_j vj 进行。(vertex表示活动)
  2. 拓扑排序:从 AOV 网中找到做事的顺序,进行排序。(必须没有回路)
    1. 找到图中没有入度的点加入队列,
    2. 将当前点和当前点的出边全部删除,然后继续执行 a ,直到 AOV 为空。
    3. 序列可能不唯一。
  3. 逆拓扑排序:(DFS实现)
    1. 找到当前图中出度为 0 的点加入队列,
    2. 将当前点和当前节点的入边全部删除,然后继续执行 a ,直到 AOV 为空。
    3. 序列可能不唯一。

关键路径

  1. AOE 网:带权有向图中,顶点表示事件,边表示执行事件所需的代价。(用edge表示活动)

  2. 在 AOE 网中,有些活动可以并行,但每个顶点的事件必须要等到它的入边的活动完成之后才能进行。

  3. 在 AOE 网中,有且自由一个开始顶点(源点,入度为0),有且自由一个结束顶点(汇点,出度为0)。

  4. 关键路径,关键活动:(源点到终点的最长路径)

    在这里插入图片描述

    关键路径长度是整个工程所能完成的最短时间。

  5. 时间余量:表示在不影响整个工程总时间的情况下,活动允许被延后执行的时间。时间余量为 0 的活动为关键活动。

  6. 压缩现有关键活动,可能会改变关键路径。

  7. 可能存在多条关键路径。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值