图的概念
图的概念比较多,我只选一部分写
无向边:顶点Vi到Vj的边没有方向,则称这条边为无向边,用无需偶(Vi, Vj)来表示。
上图为无向图G1,G1={V1, E1},则其中
V1 = {A,B,C,D},
E1 = {(A,B),(B,C),(C,D),(D,A),(A,C)}
有向边:若顶点Vi到Vj的边有方向,则称这条边为有向边,也称为弧。用有序偶< Vi, Vj>来表示,Vi为弧尾,Vj为弧头。是弧尾指向弧头。
上图是一个无向图G2,G2={V2,E2},其中
V2 = {A,B,C,D}
E2 = {< B,A>, <B,C>,<C,A>,<A,D>}
简单图:不可指向自己或者不能重复弧
无向完全图:任意两个顶点之间都存在边,含有n个顶点的无向完全图有n*(n-1)/2条边。
4个顶点,6条边。
有向完全图:任意两个顶点之前都存在方向互为相反的两条弧。含n个顶点的有向完全图有n*(n-1)条边。
稀疏图和稠密图
边或弧数小于n*logn(n为顶点数)为稀疏图
带权的图称为网。
图的顶点和边的关系,略
图的存储结构
多对多的情况,任何一个顶点都可以当作是第一个顶点,邻接点之间不存在次序关系。
- 由于任何两个顶点之间都可能存在联系,无法用物理位置来存储元素之间关系。
- 用多重链表来表示关系倒是可以,如果各个顶点度数相差太大,但是会浪费。
- 五种不同的存储结构。
邻接矩阵
把 顶点 和 边 两个部分组成,合成一起比较困难,所以考虑用用两个结构来分别存储。
顶点不区分大小,主次,所以用一一维数组来存储是很不错的选择。
边是顶点和顶点之间的关系,就要考虑二维数据存储。
-无向图
有向图
网
邻接表
邻接表类似于临时工,平时都是用邻接矩阵。
对于边数相对顶点较少的图,这种邻接矩阵很浪费。
因此我们可以考虑另一种方式存储。把数组和链表结合起来存储。
邻接表的处理方式:
顶点可以用数组,也可以用单链表,不过数组更容易读取定点信息,更方便。
每个顶点Vi的所有邻接点构成一个线性表,由于邻接点的个数不确定,所以我们选择用单链表来存储。
无向图
有向图
把顶点当弧尾建立邻接表,表示每个顶点的出度。逆邻接表只能表示入度。十字链表可以弥补这个问题。弧尾指向弧头。
建立一个逆邻接表,以便确定入度。把顶点当弧头。
这样可以很快看出出度和入度,也很快判断出弧数。
网
因为有权值,可以在边表结点定义种再增加一个数据域来存储权值。下图的第二个就是数据域就是。
十字链表
把邻接表和逆邻接表结合起来。有向图的优化结构。
我们重新定义顶点表的结点结构。
data-顶点数据
firstIn-第一个入边表的指针
firstQut-第一个出边表的指针
接着,重新定义边表结点结构。
tailVex- 弧起点的顶点的下标。尾指向头
headVex-弧的终点的顶点的下标。所以这个结构表示的是一个边而不是点。
headLink-终点指针,图中红色入度
tailLink-起点指针,图中蓝色出度
头指向空时,就是没有入度。
十字链表的好处:
- 把邻接表和逆邻接表整合到一起,这样容易找到弧和出度和入度。
- 虽然十字链表的结构有些复杂,其实创建图的算法的时间复杂度和邻接表相同,因此,在有向图的应用中,十字链表是很好的数据结构模型。
邻接多重表
怎么优化无向图的邻接表?
如果在无向图中重点关注顶点,那么邻接表是不错的选择。如果逆更关注边的操作,比如对已访问的边做标记,或者删除某一条边。邻接表就不那么方便了。
因此,仿造十字链表的方式对边表结构进行改装。
iVex 和 jVex是与某条边依附的两个顶点在顶点表中的下标。iLink指向依附顶点iVex的下一条边,jLink指向依附顶点jVex的下一条边。
边表存放的是一条边,而不是一个顶点。
01 12 23 30 02为无向图的五条边,根据顶点找边
01的顶点为0,下一条边是03,连线03的0。
12的顶点为1,下一条边是10,连线10的1.以此类推。
最后看02这条边,顶点为2,12和02相连接,12的2指向02的2;顶点为0,30的02相连接,30的0指向02的0.
其余的 01的1,23的3,02的0和2,都没有可指向的了
到这里,边和边的关系已经表示完了。
边集数组
由两个一维数组组成的,一个存顶点,一个存边。由一条边的起点下标begin,终点下标end,权weight,组成。很简单,看看图就知道了。