6.图
1. 图的基本概念
图是一种比线性表和树更加复杂的数据结构,在线性表中,每个元素都只有一个直接前驱和一个直接后继;在树形结构中,数据元素之间有明显的层次关系,每一层上的某个元素,可能与下一层多个元素相关,但只能和上一层一个元素相关。而在图形结构中,结点之间的关系是任意的,图中任意两个数据元素之间都可能有关。
2.图的存储结构
2.1 邻接矩阵
用一个二维数组表示n个顶点的图,可以存放n个顶点n^2个弧的关系。如果是无向图,则可以值存入上三角或下三角。
2.2 邻接表
在邻接表中,对图的每个顶点建立一个单链表。若无向图有n个顶点,e条边,则它需要n个头结点,2e个表结点。
2.3 十字链表
有向图的另一种链式存储结构
2.4 临接多重表
无向图的另一种链式存储结构
3. 图的遍历
3.1 广度优先遍历
-
概念广度有限遍历类似树的层次遍历。假设从图中某一个顶点v出发,访问过v之后,依次访问未访问过的与v相邻的结点,然后再从v的临界点出发,访问v的邻接点的邻接点。直至图中从v出发,能到的结点都被访问完。此时,如果途中尚有顶点未被访问,再从这个结点开始,重复和v一样的操作,直至途中所有的顶点都被访问过为止。
-
性能分析
-
时间复杂度:
- 邻接矩阵:访问V个结点需要O(V)的时间,查找V个顶点也需要O(v)的时间,时间复杂度为O(V^2)
- 邻接表:访问V个结点需要O(V),访问各个顶点的邻接点O(V+E)
-
空间复杂度:需要一个辅助队列,辅助空间O(V)
-
3.2 深度优先遍历
-
深度优先遍历类似于树的先根遍历。从途中某个顶点V出发,访问V顶点,然后依次从V的未访问邻接点左深度优先遍历,直至图中所有与v有路径的顶点都被访问到;若此时,途中还有顶点未被访问,则另选一个未被访问的结点,重复上述过程。
-
性能分析
-
时间复杂度:
- 邻接矩阵:访问V个结点需要O(V)的时间,查找V个顶点也需要O(v)的时间,时间复杂度为O(V^2)
- 邻接表:访问V个结点需要O(V),访问各个顶点的邻接点O(V+E)
-
空间复杂度:设一个访问的标志组,最好情况是O(1),最坏的情况O(V)
-
3.3 最小生成树
连同n个顶点,只需要n-1条边。一颗树的代价就是树上各边上的代价之和。最小生成树,就是生成一棵树,使之代价最小。
- 普利姆算法:假设从顶点1出发,找到距离1最近的点2,(选过的顶点不能再组成最小生成树的边,比方说之前1-2,2-4这两条便加入最小生成树的集合),再找距离1-2这棵树最近的点。
- 普利姆算法的时间复杂度为O(n^2),它与网中的边数无关,适用于边稠密的最小生成树算法。
- 克鲁斯卡尔算法:从边集合中找一条代价最小的边加入最小生成树的集合,选过的顶点不能再组成最小生成树的边,比方说之前1-2,2-4这两条便加入最小生成树的集合,那么1-4即使是目前代价最小的边,也不能再加入最小生成树。
- 克鲁斯卡尔算法的时间复杂度是O(eloge),适用于求边稀疏的最小生成树。
3.4 最短路径
3.4.1 单源最短路径
-
BFS(无权)
-
迪杰斯特拉算法
设有两个顶点集合S和T,集合S中存放图中已找到最短路径的顶点,集合T存放图中剩余顶点。
①初始状态时,集合S中只包含源点V0,然后不断从集合T中选取到顶点V0路径长度最短的顶点Vu并入集合S中;
②集合S每并入一个新的顶点Vu,都要修改V0到集合T中的最短路径长度值。
③不断重复此过程。直到集合T中所有的顶点全部并入到S中为止
注意:边上带有负的权值时,Dijkstra算法并不适用
3.4.2 每一对顶点之间的最短路径问题
-
解决这个问题的一个办法是:每次以一个顶点为源点,重复执行Dijkstra算法n次。这样便可求得每一对顶点之间的最短路径。总的时间复杂度为O(n^3)
-
这里要介绍的由弗洛伊德提出的另一个算法。时间复杂度也是O(n^3),但是形式上简单些。
主要用来求用四阶方阵表示的图中每两个顶点之间的最短路径的过程。
引进两个辅助矩阵D,path[]
D:用来记录当前已经求得的任意两个顶点最短路径的长度。
path:用来记录当前两个顶点间最短路径上要经过的中间顶点。
注意:
Floyd算法允许图中带负权值的边,但不允许包含带负权值的边组成回路。
Floyd算法同样适用于带权无向图,因为带权无向图可视为权值相同往返二重边的有向图。
3.5 拓扑排序
不断找入度为0的顶点,访问它,然后从顶点集合中去掉它,并去掉它发出的有向边,在剩下的图的顶点集合中,重复这个过程,直至所有的顶点均被访问过,或者途中没有入度为0的顶点,这种情况说明途中有环(eg:1->2,2->3,3->1)。应用:施工流程图(AOV网,顶点来表示活动),表示次序关系。
3.6 关键路径
AOE网,边表示活动的网,AOE网是一个带权的有向无环图。路径长度最长的路径叫做关键路径。提升关键活动功效,就能缩短整个工期。
求法
-
求ve(i),vl(i),ve(j) = ve(i) + max(det<j,k>)
-
求e(i),l(i),e(i) = ve(j),l(i) = vl(k) - det<j,k>
-
计算l(i) - e(i) = 0 的活动
3.6 有向无环图及其应用
没有环的有向图。它是描述含有公共子式的表达式的有效工具。用二叉树可以描述一个表达式,两个子节点是字母,他俩的双亲结点是运算符这样。观察表达式的话,会有一些重复的子表达式,二叉树中也会重复出现,有向无环图实现了这些子表达式的共享,可以节省存储空间。