基本概念:
- 图 (Graph):一种比较复杂的数据结构,其中的任何两个元素都可以有序偶关系。
- 顶点:图中的数据元素。
- 弧:如果图中顶点的关系用< v , w >表示,则< v , w >表示从顶点 v 到顶点 w 的一条弧,其中 v 是弧尾,w 是弧头。
- 有向图:顶点的关系用弧表示的图称有向图。
- 无向图:如果图中顶点的关系用(v , w)表示,则(v,w)表示从顶点 v 到顶点 w 的一条边,此时的图成为无向图。
- 完全图:每一对不同顶点恰有一条边相连的图称为完全图。边数为 n(n−1)2 (结点数为 n)。
- 有向完全图:每两个顶点之间都有两条方向相反的边连接的图称为有向完全图。弧数为 n(n -1)(结点为 n) 。
- 稀疏图、稠密图:有很少条边或弧(一般少于n log2 n,n为结点数)的图称为稀疏图,反之称为稠密图。
- 子图:如果某个图的顶点集为V,边集或弧集为E,则由V的子集组合而成的图为原图的子图。
- 邻接点:在无向图中,如果有边(v,w),则称顶点 v 和 w 互为邻接点,即 v 和 w 相邻接。边 (v,w)依附于顶点 v 和 w,或者说(v,w)与顶点 v 和 w相关联。
- 度:无向图中,顶点 v 的度是指和 v 相关联的边的数目。
- 入度、出度:有向图中,以顶点 v 为弧头的弧的数目称为顶点 v 的入度,以顶点 v 为弧尾的弧的数目称为顶点 v 的出度。
- 路径:从顶点 v 经过一系列的边或弧到达顶点 w ,则称这一系列的边或弧为顶点v 到顶点 w 的路径。
- 连通:在无向图中,如果从顶点 v 到顶点 w 有路径,则称顶点 v 和 顶点 w 是连通的。如果对于图中的任意两个顶点都是连同的,则称为连通图。无向图中的极大连通子图为其连通分量。
- 强连通图:在有向图中,如果对每一对顶点 v 、w 从v 和 从w到v都有路径,则称该有向图是强连通图。有向图中的极大强连通子图称为有向图的强连通分量。
- 生成树:一个连通图的生成树是一个极小连通子图。它含有图中全部顶点,但只有足以构成一棵树的 n - 1 条边。
图的存储:
1. 邻接矩阵(Adjacency Matrix):
存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。
2. 邻接表:
邻接矩阵是不错的一种图存储结构,但是对于边数多顶点少的图,这种结构存在对存储空间的极大浪费。因此,找到一种数组与链表相结合的存储方法称为邻接表(链式存储结构)。
邻接表的处理方法是这样的:
- 图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过,数组可以较容易的读取顶点的信息,更加方便。
图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。
3. 十字链表(适用于有向图、有向网)
对于有向图来说,邻接表是有缺陷的。关心了出度问题,想了解入度就必须要遍历整个图才知道,反之,逆邻接表解决了入度却不了解出度情况。
十字链表,就是把邻接表和逆邻接表结合起来的,这样既容易找到以Vi为尾的弧,也容易找到以Vi为头的弧,因而容易求得顶点的出度和入度。十字链表除了结构复杂一点外,其实创建图算法的时间复杂度是和邻接表相同的,因此,在有向图的应用中,十字链表也是非常好的数据结构模型。
如下图所示:
- 顶点结点
- data:顶点数据
- firstin:指向以该顶点为弧头的第一个弧结点(入度的第一条弧)
- firstout:指向以该顶点为弧尾的第一个弧结点(出度的第一条弧)
- 弧结点
- tailve:弧尾
- headvex:弧头
- hlink:指向弧头相同的下一条弧(入度)
- tlink:指向弧尾相同的下一条弧(出度)
- info:存储边或弧相关的信息,如权重等
4. 邻接多重表(适用于无向图、无向网):
如果我们在无向图的应用中,关注的重点是顶点的话,那么邻接表是不错的选择,但如果我们更关注的是边的操作,比如对已经访问过的边做标记,或者删除某一条边等操作,邻接表就显得不那么方便了。例如,对已访问过的边做标记,或者要删除图中某一条边等,都需要找到表示同一条边的两个结点。因此,在进行这一类操作的无向图的问题中采用邻接多重表作存储结构更为适宜。
如下图所示:
- mark:标记域
- ivex:顶点位置
- ilink:指针域
- jvex:顶点位置
- jlink:指针域
- info:边上信息
总结:
图的存储结构是显示世界中的图在计算机中的一种存在形式。一个图在计算机中的存在形式不一定唯一。例如,别人给你一个图,你可以画出几个十字链表出来,但是这几个邻接表在本质上都是反映这个图的,相反,别人给你一个十字链表,你只能画出一个图与之对应。