1.内容小结:
图:
图是由顶点的有穷非空集合以及顶点的边的集合组成,通常表示为G(V,E),是一种多对多的数据结构。图不允许没有顶点,可以没有边,这点与树不同。
图的基本概念:
图的概念和性质还是挺多的,这里只列出个人觉得比较容易混淆的。
连通图
:任意两个顶点都相互连通的图极大连通子图
:包含尽可能多的顶点(必须是连通的),即找不到另外一个顶点,使得此顶点能够连接到此极大连通子图的任意一个顶点连通分量
:无向图中的极大连通子图强连通图
:隶属于有向图的概念,表示任意两个顶点a,b,使得a能够连接到b,b也能连接到a 的图- 强连通分量:有向图中的极大强连通子图
生成树
:n个顶点,n-1条边,并且保证n个顶点相互连通(不存在环)最小生成树
:该生成树的边的权重之和是所有生成树中最小的
图的存储结构:
1、邻接矩阵
邻接矩阵使用一个一维数组来存储顶点信息,一个二维数组来存储图中边或弧的信息。其中,无向图由于不分方向,所以是一个对称矩阵。
优点:
- 便于判断两点是否有边
- 便于计算一个点的度(对无向图,该点所在的那一行元素之和,就表示它的度。对有向图,对应的那一行的元素之和是它的出度,那一列的元素之和就是它的入度。
缺点:
- 不便于增加和删除点以及计算边的数目
- 对于稀疏图,邻接矩阵的存储将浪费大量的空间。
2.邻接表
图中顶点用一个一维数组存储(也可以用单链表来存储,只不过数组形式更容易读取)。顶点数组中,每个顶点分配一个指向第一个邻接点的指针,以便于查找该顶点的边信息。图中每个顶点的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储。
优点
- 便于增删顶点
- 便于统计边的数目,按顶点表顺序扫描所有边表可以得到边的个数。
- 空间利用率高。
缺点
- 不适合稠密图
- 不便于判断顶点之间的是否有边。
- 不便于计算顶点的度。
图的遍历:
图的遍历不同于树,逻辑稍不注意,就会因回路陷入死循环。一般来说,图的遍历有两种,深度优先搜需(DFS)
和广度优先搜索(BFS)
。为了避免重复访问,两种遍历都需要设置一个visited []数组,标记顶点访问情况。
两种遍历所消耗的时间复杂度都受制于具体的存储结构。
DFS:基于邻接矩阵(O(n^2)), 基于邻接表(O(n+e),e为图中边数);
BFS:基于邻接矩阵(O(n^2)), 基于邻接表(O(n+e),e为图中边数)
图的深度优先遍历与广度优先遍历算法在时间复杂度上是一样的,区别只是在于对顶点访问的顺序不同。深度优先更适合目标比较明确,以找到目标为主要目的的情况,而广度优先更适合在不断扩大遍历范围时找到相对最优解的情况。(mooc迷宫体现)。
图的应用:
最小生成树(生成树中每条边上权值之和达到最小的树):
构造原则:尽可能选取权值最小的边,但不能构成回路;选择n-1条边构成最小生成树。
最小生成树的构建有两种算法,即Prim算法和Kruskal算法,两种算法在实现思路上有所差别。
Prim算法:针对顶点,更适用于稠密图;
Kruskal算法:针对边,更适用于稀疏图。
最短路径(指定源点到其他各个顶点之间的最短路径):
Dijkstra算法:按路径长度递增的次序产生最短路径(因此不适用于边上带有负权值的情况)。
算法的思路不算难,通过列表格不断迭代最后就能求出结果,怎么转化为代码让计算机来跑就感觉有点无从下手了,有时间的话就去试试吧(不能什么都等算法课教啦!)。
2.一些心得:
个人小测得分一直都挺低的,意识到自己的理解和表达能力还是挺弱的,可能是对知识的理解还是不够透彻;
pta鳄鱼一题一开始总是抽象不出问题,应该多联系学过的东西,知识得会用才是王道;
学到后面接触的算法都挺难的,一定要坚持多看多啃。
......接下来要多多复习了!