跳转至

Graph

Abstract
  • 图的定义
  • 拓扑排序(AOV网)
  • 最短路问题
    • 无权
    • 带正边权:Dijkstra 算法
    • 有负边权
    • AOE网
  • 网络流
    • 解题:流量图、残量图
  • 最小生成树(MST)
    • Prim算法
    • Kruskal算法
  • 深度优先搜索(DFS)
    • 基本算法
    • 关节点(割点)、双连通分量
    • 欧拉路、欧拉环

Definitions

  1. G(V, E)

ADT Definition

  • 类型名称:图(graph)
  • 数据对象集:\(G(V, E)\)
  • 操作集:
    • Graph Create():创建并返回一个空图
    • Graph InsertVertex(Graph G, Vertex v):在图G中插入顶点v
    • Graph InsertEdge(Graph G, Edge e):在图G中插入边e
    • void DFS(Graph G, Vertex v):从顶点v开始进行深度优先搜索,遍历图G
    • void BFS(Graph G, Vertex v):从顶点v开始进行广度优先搜索,遍历图G
    • void ShortestPath(Graph G, Vertex v, int Dist[]):计算从顶点v到其他各顶点的最短路径
    • void MST(Graph G):计算图G的最小生成树
  • \(G\) 表示 图(graph)
  • \(V = V(G)\) 表示关于 顶点(vertices) 的有限非空集合
  • \(E = E(G)\) 表示关于 边(edges/arcs) 的有限集合

  • 无向图(undirected graph)\((v_i,v_j) = (v_j,v_i)\)

  • 有向图(directed graph, digraph)\(<v_i,v_j> \neq <v_j,v_i>\) (单行线)

稀疏图 稠密图 完全图

Representation of Graph

邻接矩阵 (adjacency matrix)

无向图 -- 将 下三角矩阵 存入一维数组中(节约一半空间)

\(a_{ij}\)的索引为 \(\frac{i(i+1)}{2} + j\)

  • 查看任意一对顶点间是否存在边
  • 查找某个顶点的所有邻接点(有边直接相连的顶点)
  • 计算任一顶点的度数(degree)
    • 出度:从该顶点 出发 的边的数量
    • 入度:指向 / 到达该顶点的边的数量
    • 无向图:度数 = 出度 = 入度
    • 有向图:度数 = 出度(行) + 入度(列)

不适合存储 稀疏图(sparse graph) -- 边的数量远小于顶点数量的平方

稠密图 -- 边的数量接近于顶点数量的平方

Question
  1. 有向图的邻接矩阵一定是不对称的 ❌×
  2. 无向图的邻接矩阵一定是对称的 ✔️√
  3. 用一维数组G[]={0,1,0,1,1,0,0,0,1,0},则顶点2和顶点0之间是有边的

    \(a_{2,0}\) ,即\(G[3]\)

邻接表 (adjacency list)

Question
  • 用邻接表表示有 \(N\) 个顶点、\(E\) 条边的图,则遍历图中所有边的时间复杂度为?

    \(O(N+E)\) 遍历顶点表 + 遍历链表

邻接多重表 (adjacency multilist)

Graph Traversal遍历

Depth-First Search (DFS)

深度优先搜索(DFS)-- (前序遍历 的泛化推广)

从一个起始顶点开始,沿着图的边向下探索,直到无法继续为止,然后回溯到上一个顶点继续探索其他路径。

走到一个没有任何未访问邻居的节点时,不能直接“瞬移”到图上的另一个点,而是必须按原路退回到上一个还有岔路口的节点

pseudocode -- iterative

    void DFS(Vertex V){
        visited[V] = true; // 标记当前顶点为已访问
        for (each neighbor W of V) { // 遍历V的所有邻接点
            if (!visited[W]) // 如果邻接点W未被访问
                DFS(W); // 递归调用DFS访问邻接点W
        }
    }

recursive

若有N个顶点、E条边

  • 时间复杂度
    • 邻接表:\(O(N+E)\)
    • 邻接矩阵:\(O(N^2)\)
  • 空间复杂度 \(O(N)\)(递归调用栈的深度)

Breadth-First Search (BFS)

广度优先搜索(BFS)-- (层序遍历 的泛化推广)

pseudocode -- iterative

    void BFS(Vertex V){
        visited[V] = true;       // 标记当前顶点为已访问
        Enqueue(V, Q);           // 将起始顶点V加入队列Q
        while (!IsEmpty(Q)) {    // 当队列Q不为空
            V = Dequeue(Q);      // 从队列Q中取出一个顶点V
            for (each neighbor W of V) {    // 遍历V的所有邻接点
                if (!visited[W]) {          // 如果邻接点W未被访问
                    visited[W] = true;      // 标记邻接点W为已访问
                    Enqueue(W, Q);          // 将邻接点W加入队列Q
                    }
            }
        }
    }

若有N个顶点、E条边

  • 时间复杂度
    • 邻接表:\(O(N+E)\)
    • 邻接矩阵:\(O(N^2)\)
  • 空间复杂度 \(O(N)\)(队列中最多同时存在N个顶点)

Topological Sort

拓扑排序(topological sort)-- AOV网(activity on vertex network)

对于有向图 \(G\)\(V(G)\)表示活动,\(E(G)\) 表示位次关系

  • 拓扑序(topological order)

    拓扑序不唯一

  • 有效的AOV网一定是有向无环图 (Directed Acyclic Graph, DAG)
version 1
void TopSort(Graph G) {
    int cnt;
    Vertex V, W;
    for(cnt = 0; )
}
  • 环?
  • \(T = O(|V|^2)\)
version 2 optimized


关键路径(critical path)问题

  • 关键路径:最长路径(longest path)-- 从源点到汇点的最长路径
  • 关键活动:在关键路径上的活动
  • 关键路径法(Critical Path Method, CPM)
  • 关键路径的长度 = 项目的最短完成时间
  • 关键路径上的活动没有任何时间余量(slack time)-- 任何一个关键活动的延迟都会导致整个项目的延迟

AOE(Activity on Edge)网:边表示活动,顶点表示事件(event)

Critical Path Method (CPM)


取最长 倒推,从最后一个开始

Shortest Path

最短路径问题(shortest path problem)-- AOE网(activity on edge network)

在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的那条路径(最短路径 Shortest Path)

  • 源点 (source vertex)-- 起点
  • 汇点 (sink vertex)-- 终点

Question

  • 单源最短路径(single-source shortest path)-- 从一个源点到其他所有顶点的最短路径
    • (有向)无权图
    • (有向)有权图
  • 单汇最短路径(single-sink shortest path)-- 从所有顶点到一个汇点的最短路径
  • 多源最短路径(multi-source shortest path)-- 从多个源点到其他所有顶点的最短路径
  • 全源最短路径(all-pairs shortest path)-- 所有顶点之间的最短路径

Network Flow

网络流(network flow)-- 流量图(flow graph)、残量图(residual graph)

Minimum Spanning Tree (MST)

最小生成树(minimum spanning tree, MST)-- Prim算法、Kruskal算法


HW8 -- Graph

HW9 -- Shortest Path

HW10 -- Network Flow & Minimum Spanning Tree