考研笔记 | 数据结构 §6. 图

§1. 概述

  1. 定义:由定点集 V 和边集 E 组成,记为 G (V,E)

  2. 注意:线性表、树可为空,但图不可为空。至少一个顶点。

  3. 有向图:E 是有向边(简称弧)的有限集合。 0en(n1) 弧

  4. 无向图:E 是无向边(简称边)的有限集合。 0en(n1)2

  5. 简单图:满足 ① 不存在重复边,② 不存在定点到自身的边。

* 在数据结构中,讨论的均为简单图!(与之对应的是多重图)

  1. 无向完全图:任意两个顶点都存在边,e=n(n1)2

  2. 有向完全图:任意两个顶点存在着方向相反的两条弧,e=n(n1)

  3. 连通:从顶点 V 到顶点 W 有路径存在,则称 V 与 W 连通。

  4. 连通图:若图 G 中任意两个顶点都是连通的,称 G 为连通图,否则为非连通图。

  5. 无向图中的极大连通图称为连通分量。

  6. 强连通图(仅针对有向图),若从顶点 V 到顶点 W 和从顶点 W 到顶点 V 之间都有路径,则称这两个顶点强连通,则称。

  7. 强联通分量(仅针对有向图),图中极大强连通子图称为有向图的强连通分量。

  8. 生成树:连通图的生成树是包含图中全部顶点的一个极小连通子图。若图中顶点数为 n,则它的生成树有 n1 条边。

    对生成树:若砍去一条边则为非连通图,加上一条边为回路。

  • 度:边数
  • 出度:“起点边数”
  • 入度:“终点边数”

15.

  • 无向图中,度为 i=1nTD(Vi)=2e
  • 有向图中,TD(Vi)=ID(V)+OD(V)
  • e 条边有向图,i=1nID(Vi)=i=1nOD(Vi)=e
  1. 稠密图与稀疏图:边数很少(enlog2n),称为稀疏图。

  2. 路径:顶点 v0 到顶点 vq 之间的一条路径,即顶点序列 v1,v2,v3,,vn

  3. 路径长度:路径上边的数目。

  4. 回路:第一个顶点和最后一个顶点相同的路径。
    若一个图有 n 个顶点,且有大于 n1 条边,则此图一定有环。

  5. 简单路径:在路径序列中,顶点不重复出现的路径。

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

  7. 图的存储结构:邻接矩阵、邻接表、逆邻接表、十字链表、邻接多重表。(邻接多重表仅适用于存储无向图)。

§2. 邻接矩阵表示法

  1. 邻接矩阵法:一位数组存储顶点 + 二维数组存储图的边 + 顶点数 + 弧数

  2. 1
    2
    3
    4
    5
    6
    7
    8
    #define MaxVertexNum 100 // 顶点数目最大值
    typedef char VertexType; // 顶点数据类型
    typedef int EdgeType; //带权图中边上权值的数据类型
    typedef struct Graph{
    VertexType vex[MaxVertexNum]; //顶点表
    EdgeType Edge[MaxVertexNum][MaxVertexNum]; //矩阵边表
    int Vexnum,arcnum; //图中当前顶点数与弧数
    }MGraph;//空间复杂度O(n²),n为顶点数
  3. 无向图的邻接矩阵一定是对称矩阵(且唯一)。在世纪应用可以压缩存储(上 / 下三角矩阵)。

  4. 无向图邻接矩阵第 i 行(第 j 列)非 0 元素的个数为第 i 个顶点的度。

  5. 有向图邻接矩阵第 i 行(第 j 列)非 0 元素的个数为第 i 个顶点的出度(入度)。

  6. 用临街矩阵法存储图,很容易确定图中任意两个顶点是否有边相连。但要确定途中有多少条便需按行、列对每个元素检测。

§3. 邻接表表示法

  1. 邻接表法:数组(弧尾顶点)+ 链表(邻接点)+ 个数

  • 顶点表:
Datafirstarc
顶点域头指针
  • 边表:
adjVexnextarc
邻接点域指针域
  1. ```c
    #define MaxVertexNum 100
    typedef struct ArcNode {// 边表结点
    int adjVex;
    struct ArcNode *next;// 指向下一条弧的指针
    InfoType info;// 网的边权值
    }ArcNode;
    typedef struct VNode{
    VertexType data;
    ArcNode *first;
    }VNode,AdjList[MaxVertexNum];
    typedef struct{
    AdjList vertices;
    intVexnum arcnum;
    }ALGroph
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40

    32. 若G为无向图,则所需存储空间为$O(|V|+2|e|)$,
    若为有向图,则所需存储空间为$O(|V|+|e|)$,
    前者的2是因为无向图中每条边出现了两次。
    33. 对于稀疏图,适用于邻接表存储,节约存储空间。
    34. 在邻接表中,给定顶点能容易的找到领边,反之矩阵不行($O(n)$)
    在邻接矩阵中,可以快速查找两个顶点是否存在边。
    35. 在有向图的邻接表表示中,求给定节点出度仅需计算其邻接表中结点个数,但入度需要遍历整个邻接表。因此有逆邻接表表示,不唯一。

    # §4.十字链表表示法

    36.
    - 弧结点

    | tailVex | headVex | hlinx | tlink | info |
    | :-----: | :-----: | :---: | :---: | :--: |
    | 尾域 | 头域 | 弧头相同 | 弧尾相同 | |

    - 顶点结点

    | data | fitstin | fistout |
    | :--: | :-----: | :-----: |
    | | | |
    37. 示例 ![示例][6.2]

    38. ```c
    #define MaxVertexNum 100
    typedef struct ArcNode{ //边表结点
    int tailVex,headVex; //头尾节点
    struct ArcNode *hlink,*tlink; //指向弧头相同与弧尾相同节点
    //InfoType info; //相关信息指针
    }ArcNode;
    typedef struct VNode{ //顶点表结点
    VertexType data; //顶点信息
    ArcNode *firstin,*firstout; //指向第一条弧与出弧
    }VNode;
    typedef struct{ //邻接表
    VNode *list[MaxVertexNum];
    int Vexnum,arcnum; //顶点数与弧数
    }GlGraph;

§5. 邻接多重表

  1. 临接多重表:无向图的另一种链式存储结构。“数组(顶点)+ 边结点”

  2. 容易求得顶点和边的各种信息,但在邻接表中求两个顶点是否存在边,或需对边执行删除等操作,需分别在两个顶点的边表遍历。

markivexilinkjvexjlinkinfo
标志域(是否遍历)下一顶点 ivex 边下一顶点 jvex 边
  • 顶点
datafirstdye
  1. 示例

示例

  1. #define MaxVertexNum 100
    typedef struct ArcNode{
        bool Mark;  //访问标记
        int ivex,jvex;  //指向弧结点
        struct ArcNode *ilink,*jlinkl   //分别指向两个结点下一条边
        //InfoType info;	//相关信息指针
    }ArcNode
    typedef struct VNode{   //顶点表结点
        VertexType data;    //顶点信息
        ArcNode *firstedge  //指向第一条弧与出弧
    }VNode;
    typedef struct{ //邻接表
        VNode adjmulist[MaxVertexNum];
        int Vexnum,arcnum;  //顶点数与弧数
    }GlGraph;
    

§6. 最小生成树

  1. 最小生成树(MST):图的极小连通子图,包含所有顶点和尽可能少的边。

  2. 对最小生成树,砍去一条边构成非连通图,增加一条边则形成回路。

  3. 性质:

    • 最小生成树不唯一
    • 权值之和为 1
    • 边数 = 顶点数 - 1
  4. 普里姆 (Prim) 算法:

    1. 开始时,U=v0,TE=,
    2. 计算 U 到某余顶点 VU 的最小代价,纳入 U,边纳入 TE
    3. 重复 2 知道 U=V
  5. 克鲁斯卡尔 (Kruskal) 算法:“不够成环情况下,每次先选择最小边”,适用于边稀疏且顶点多的树,结果不唯一。

算法普里姆克鲁斯卡尔
时间复杂度 O(n2)$O(
特点只与顶点个数 n 有关只与边数 e 有关
与边数 e 无关与顶点个数 n 无关
适用于稠密图适用于稀疏图
  1. Dijkstra 算法(单源带权图)

    1. 初始化:用起点 V 到该顶点 w 的直接边(弧)初始化最短路径,否则设为 ,用 dist[] 记录,dist[i] 处置 arcs[VD][i]
    2. 从未求得最短路径的终点中选择长度最小终点 V,求 VU 最短路径;
    3. 修改最短路径:计算 U 的邻接点的最短路径,若 (V,,U)+(u,v)<(V,,W),以 V,,V,W 代替;
    4. 重复 2,3,知道求出 v 到其余所有结点的最短路径。
  2. 若用邻接矩阵表示,则时间复杂度为 O(|v|2)。若求源点到其他所有结点最短路径,其时间复杂度为 O(|v|2)。若找出所有结点对之间的最短距离,时间复杂度 O(|v|3).

  3. Dijstra 算法不适用边上有负权值的图。

  4. Floyd 算法。依次计算 A(0),A(1),A(2),,A(n)。计算 Aij(k)=minA(k1)(i,j),A(k1)(i,k)+A(k1)(k,j)

  5. 时间复杂度 O(|V|3)

§7. 其他

  1. 拓扑排序:“每次删除入度为 0 的顶点并输出”

  2. 有向无环图 (DAG):一个有向图中不存在环

  3. AOV 网:用有向边 <Vi,Vj> 表示活动 Vi 必须先于活动 Vj 进行的一种关系,将这种有向图称为顶点表示活动的网络。

  4. 关键路径:在带权有向图中,以顶点表示事件,有向边表示活动,边上的权值表示完成活动的开销(如:花费时间),则称这种有向图为用边表示活动的网络,简称为 AOE 网。