图 的 基 础 知 识 \color{FCE6C9}{图的基础知识}

o 术语

  • 顶点 Vertex

  • 弧 Arc <u , v> :从u到v的弧。u:弧尾;v:弧头

  • 边 Edge

  • 入度:ID(v) ; 出度:OD(v) ; 度:TD(v)

*o 存储方法

  • 邻接矩阵

    • 无向图只用压缩存储一个三角矩阵即可

    • 有向图要全部存储

  • 邻接表P219

    • 表头结点表:由所有表头结点以顺序结构(向量)的形式存储,以便可以随机访问任一顶点的边链表。表头结点由两部分构成,其中数据域vexdata用于存储顶点的名或其他有关信息;链域firstarc用于指向链表中第一个顶点(即与顶点 v i v_{i} vi邻接的第一个邻接点)

    • 边表:由表示图中顶点间邻接关系的n个边链表组成。边链表中结点的结构由三部分组成,其中邻接点域adjvex用于存放与顶点 v i v_{i} vi相邻接的顶点在图中的位置;链域nextarc用于指向与顶点 v i v_{i} vi相关联的下一条边或弧的结点;数据域info用于存放与边或弧相关的信息(如赋权图中每条边或弧的权值等)。

  • 十字链表(OrthogonalList)P221

    • 有向图的另一种链式存储结构,可以把它看成是将有向图的邻接表和逆邻接表结合起来的一种链表。有向图中的每一条弧对应十字链表中的一个弧结点,同时有向图中的每个顶点在十字链表中对应有一个结点,称为顶点结点。

o 应用

  • 简单路径

  • 遍历 P225-231

    • 广度优先(队列)

    • 深度优先(栈)

  • 生成树和最小生成树

    • 概念:

      • 生成树:一个连通图的生成树是指一个极小连通子图,它含有图中的全部顶点,但只有足以构成一棵树的n-1条边。如果在一棵生成树上添加一条边,必定构成一个环,这是因为该条边使得它依附的两个顶点之间有了第二条路径

      • 最小生成树:各边的代价之和最小的生成树(MST)

    • 算法:

      • Prim普里姆算法(最小生成树,加点法)

        • 假设N=(V,{E})是连通网,TE是最小生成树中边的集合
          1. 初始U={u0}(u0属于V),TE为空集

          2. 在所有的u属于U,v属于V-U的边中选一条代价最小的边放进TE,v0放进U

          3. 重复(2)直到U=V

          • 此时,TE中有n-1条边,则T必然是N的最小生成树
        • 算法步骤:
          1. 初始顶点u加入集合U,剩余的每个顶点i,将CloseEdge[i]初始化为i到u的边信息

          2. 循环n-1次:

            1. 从各组最小边CloseEdge[]里选择最小的最小边ClodeEdge[v](v属于V-U)

            2. v加入U

            3. 更新剩余节点的最小边信息CloseEdge[i](i属于V-U)

      • kruskal克鲁斯卡尔算法(加边法):

        • 找最小生成树(各边代价之和最小的生成树(连通子图))

          1. 将n个顶点看成n个集合

          2. 按照权值由小到大选择边,满足:边的两端点在不同集合中。将该边放到生成树的边集合里,合并该边的端点集合

          3. 重复(2)。直到只有一个顶点集

          • (注意:加边不能形成回)

          • 更适合于稀疏的连通图

  • 有向无环图的应用:《数据结构》P243-249

    1. 拓扑排序:

      • 概念:

        • AOV-网:用顶点表示活动的网。用顶点表示活动,弧表示活动间优先关系

        • 拓扑序列:先后关系的序列(可能不唯一)

      • 思想:

        1. 选取无前驱的节点并记录此节点

        2. 删除此节点和相连的边

        3. 重复,直到不存在没有前驱的节点

        4. 若此时记录的节点小于总节点数,说明有环。否则记录的是一个拓扑排序

      • 基于邻接矩阵G的算法:

        1. 第一个序号k=1

        2. 找一个未新编号且值全为0的列。若找到,继续(3);否则,若所有列都已经编号,排序结束,若还有列没有编号,则存在回路

        3. 输出(2)找到的列对应的顶点j,把新序号k赋给(2)中找到的列

        4. j对应的行全部置为0

        5. 序号k++,转(2)

      • 基于邻接表G的算法:

        1. 查找indegree[i]为0的顶点i

        2. 对链在i后面的所有邻接顶点j,对应的indegree[j]减一

        3. 为避免重复检测入度为0的点,设一辅助栈S,将入度为0的顶点入栈。

        4. 只要栈不空,重复:{栈顶元素i出栈并打印 -> i的每个邻接点k的入度减1,若k入度变为0,k入栈}

    2. 关键路径

      • 概念:

        • AOE-网:边表示活动的网。用顶点表示时间,边的权值表示所需时间(记顶点为v,边为a,即通常事件为v,活动为a)

        • 源点:唯一的、入度为0的节点

        • 汇点:唯一的、出度为0的节点

        • 关键路径:从源点到汇点的最长路径长度即是完成活动所需的总时间

        • 关键活动:关键路径上的活动

        • 事件v的最早发生时间:源点到v的最长路径长度

        • 事件v的最晚发生时间(在保证汇点最早发生的前提下):从汇点开始,逆拓扑顺序向源点递推

        • 活动a开始的最早时间:从源点到弧a的始点最长路径

        • 活动a开始的最晚时间:倒推

        • 活动a松弛时间(时间余量):a的最早开始时间与最晚开始时间之差

      • 关键路径步骤:

        1. 进行拓扑排序,排序时按照拓扑序列求出每个事件的最早发生时间ve(i)(程序如上)

        2. 按照逆拓扑序列求出事件最晚发生时间vl(i)

        3. 求出每个活动a(i)的最早开始时间e(i)和最晚发生时间l(i)

        4. e(i)=l(i)为所求

      • 算法思想:(部分功能已在TopOrder实现)

        1. 求出各个顶点入度,入度为0则入栈S

        2. 初始化各顶点最早发生时间为ve[i]=0

        3. 当栈S不空,重复:

          1. S栈顶元素j出栈,并压入T(生成逆拓扑序列)

          2. 对链在j后面的所有邻接顶点k,对应的indegree[k]减一。若此时入度为0,则对应节点入栈S

          3. 根据顶点j的最早发生时间和ve[j]和弧<j,k>的权值,更新k的最早发生时间

  • 最短路径

    • 迪杰斯特拉算法

      • 求给定顶点到其他顶点的最短路径

      • 时间复杂度:O( n 3 n^3 n3)

      • 空间复杂度:O(n)

      • 操作:

        1. 对图G={V,|E|},将顶点分为两组:

          第一组S:已经求出的最短路径的终点集合(开始为{v0});

          第二组V-S:尚未求出最短路径的集合(开始为V-{v0}的全部节点)

        2. 按照长度递增顺序,把第二组的加进第一组,即先把最短的加进第一组,直到加完

    • 弗洛伊德算法

      • 从任意顶点到其他顶点的最短路径

      • 时间复杂度:O( n 3 n^3 n3)

      • 空间复杂度:O( n 2 n^2 n2) //用了一个二维数组

      • 操作:

        • v i v_{i} vi v j v_{j} vj 的最短的路径长度初始化为g.arcs[i][j].adj,然后进行如下n次比较和修正:
          1. v i v_{i} vi v j v_{j} vj间加入顶点 v 0 v_{0} v0,比较( v i v_{i} vi, v 0 v_{0} v0, v j v_{j} vj )的路径长度,取其中较短的路径作为 v i v_{i} vi v j v_{j} vj的且中间顶点号不大于0的最短路径。
          2. v i v_{i} vi v j v_{j} vj 间加入顶点 v 1 v_{1} v1,得到( v i v_{i} vi, … , v 1 v_{1} v1 ) 和 ( v 1 v_{1} v1,…, v j v_{j} vj),其中( v i v_{i} vi, … , v 1 v_{1} v1 )是 v i v_{i} vi v 1 v_{1} v1 的且中间顶点号不大于0的最短路径,( v 1 v_{1} v1, … , v j v_{j} vj )是 v 1 v_{1} v1 v j v_{j} vj 的且中间顶点号不大于0的最短路径,这两条路径在上一步中已求出。将( v i v_{i} vi, … , v 1 v_{1} v1 , …, v j v_{j} vj)与上一步已求出的 v i v_{i} vi v j v_{j} vj中间顶点号不大于0的最短路径比较,取其中较短的路径作为 v i v_{i} vi v j v_{j} vj的且中间顶点号不大于1的最短路径。
          3. 在n,与v,间加人顶点 v 2 v_{2} v2得( v i , . . . v 2 v_{i},...v_{2} vi,...v2)和( v 2 v_{2} v2, … v j v_{j} vj), 其中( v i , . . . v 2 v_{i},...v_{2} vi,...v2)是 v i 到 v 2 v_{i}到v_{2} viv2的且中间顶点号不大于1的最短路径, ( v 2 v_{2} v2, … v j v_{j} vj)是 v 2 v_{2} v2 v j v_{j} vj的且中间顶点号不大于1的最短路径,这两条路径在上一步中已求出。将(v_{i}, … v_{2}, … v_{j})与上一步已求出的 v i v_{i} vi v j v_{j} vj且中间顶点号不大于1的最短路径比较,取其中较短的路径作为 v i v_{i} vi v j v_{j} vj的且中间顶点号不大于2的最短路径。
          4. 以此类推,经过n次比较和修正,在第n-1步,将求得 v i v_{i} vi v j v_{j} vj的且中间顶点号不大于n-1的最短路径,这必是从 v i v_{i} vi v j v_{j} vj的最短路径。
        • 图g中所有顶点偶对 v i v_{i} vi v j v_{j} vj间的最短路径长度对应一个n阶方阵D。在上述n+1步中,D的值不断变化,对应一个n阶方阵序列。
        • 定义:n阶方阵序列 D − 1 , D 0 , D 1 , . . . D n D^{-1}, D^0, D^1, ... D^n D1,D0,D1,...Dn, 其中,

          D − 1 D^{-1} D1[i][j]=g.arcs[i][j].adj

          D k D^k Dk[i][j]=Min{ D k − 1 D^{k-1} Dk1[i][j], D k − 1 D^{k-1} Dk1[i][k] + D k − 1 D^{k-1} Dk1[k][j] } ,0≤k≤n-1
        • 显然, D N − 1 D^{N-1} DN1中为所有顶点偶对 v i v_{i} vi v j v_{j} vj 间的最终最短路径长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值