hello算法笔记之图

一、图的基础知识

图是一种非线性数据结构,由「顶点 Vertex」和「边 Edge」组成。

1.图的类型:

根据边是否具有方向可以分为有向图,无向图

根据所有顶点是否连通可以分为连通图(对于连通图,从某个顶点出发,可以到达其余任意顶点),非连通图

2.图常用术语:

  • 「邻接 Adjacency」:当两顶点之间存在边相连时,称这两顶点“邻接”。在
  • 「路径 Path」:从顶点 A 到顶点 B 经过的边构成的序列被称为从 A 到 B 的“路径”。
  • 「度 Degree」表示一个顶点拥有的边数。对于有向图,「入度 In-Degree」表示有多少条边指向该顶点,「出度 Out-Degree」表示有多少条边从该顶点指出。

3.图的表示:

图的常用表示方法包括「邻接矩阵」和「邻接表」。

对于邻接矩阵:A[i][j]表示i到j的边,1是有边,0是没有边。

  • 对于无向图,两个方向的边等价,此时邻接矩阵关于主对角线对称。
  • 将邻接矩阵的元素从1,0替换为权重,则可表示有权图。

使用邻接矩阵表示图时,我们可以直接访问矩阵元素以获取边,因此增删查操作的效率很高,时间复杂度均为O(1),然而,矩阵的空间复杂度为O(n²)

对于邻接表:使用n个链表来表示图,链表节点表示顶点。第 i条链表对应顶点i,其中存储了该顶点的所有邻接顶点(即与该顶点相连的顶点)。邻接表仅存储实际存在的边,而边的总数通常远小于 \(n^2\) ,因此它更加节省空间。然而,在邻接表中需要通过遍历链表来查找边,因此其时间效率不如邻接矩阵。邻接表结构与哈希表中的「链地址法」非常相似,因此我们也可以采用类似方法来优化效率。例如,当链表较长时,可以将链表转化为 AVL 树或红黑树,从而将时间效率从O(n)优化至 O(log n) ,还可以通过中序遍历获取有序序列;此外,还可以将链表转换为哈希表,将时间复杂度降低至 O(1) 。

二、图的基础操作

图的基础操作可分为对「边」的操作和对「顶点」的操作。

1.基于邻接矩阵的实现:

  • 添加或删除边:直接在邻接矩阵中修改指定的边即可,使用O(1) 时间。而由于是无向图,因此需要同时更新两个方向的边。
  • 添加顶点:在邻接矩阵的尾部添加一行一列,并全部填 0 即可,使用 O(n) 时间。
  • 删除顶点:在邻接矩阵中删除一行一列。当删除首行首列时达到最差情况,需要将 (n-1)^2 个元素“向左上移动”,从而使用 O(n^2) 时间。
  • 初始化:传入 n 个顶点,初始化长度为 n 的顶点列表 vertices ,使用 \O(n) 时间;初始化 n * n 大小的邻接矩阵 adjMat ,使用 O(n^2) 时间。

2.基于邻接表的实现

设无向图的顶点总数为 n 、边总数为 m ,则有:

  • 添加边:在顶点对应链表的末尾添加边即可,使用 O(1) 时间。因为是无向图,所以需要同时添加两个方向的边。
  • 删除边:在顶点对应链表中查找并删除指定边,使用 O(m) 时间。在无向图中,需要同时删除两个方向的边。
  • 添加顶点:在邻接表中添加一个链表,并将新增顶点作为链表头节点,使用 O(1) 时间。
  • 删除顶点:需遍历整个邻接表,删除包含指定顶点的所有边,使用 O(n + m) 时间。
  • 初始化:在邻接表中创建 n 个顶点和 2m 条边,使用 O(n + m) 时间。

三、图的遍历

「图」和「树」都是非线性数据结构,都需要使用「搜索算法」来实现遍历操作。

与树类似,图的遍历方式也可分为两种,即「广度优先遍历 Breadth-First Traversal」和「深度优先遍历 Depth-First Traversal」,也称为「广度优先搜索 Breadth-First Search」和「深度优先搜索 Depth-First Search」,简称 BFS 和 DFS。

1.BFS(通常借助队列来实现)

从某个顶点出发,先遍历该顶点的所有邻接顶点,然后遍历下一个顶点的所有邻接顶点,以此类推,直至所有顶点访问完毕。

hello算法笔记之图_第1张图片

 遍历一次所有节点,遍历两次(因为是无向图)所有边(因为要通过边到达另一个节点),总时间为O(V+E),空间为O(V)

2.DFS

从某个顶点出发,访问当前顶点的某个邻接顶点,直到走到尽头时返回,再继续走到尽头并返回,以此类推,直至所有顶点遍历完成。

hello算法笔记之图_第2张图片

 总时间为O(V+E),空间为O(V)

你可能感兴趣的:(算法,算法,笔记,数据结构)