考研之数据结构021_图的存储
PS:总结:主要理解每一个特性。
-
考试常考是:【邻接矩阵】和【邻接表】
-
十字链表法:只能存储有向图。
解决:
1、邻接矩阵空间复杂度高
2、邻接表找入度比较麻烦需要遍历所有节点。 -
邻接多重表:只能存储无向图
解决了:
1、邻接矩阵空间复杂度高
2、邻接表中的删除边和顶点不方便问题。
3、每个边对应两份冗余数据。
一、邻接矩阵(一维+二维数组)
- 数组实现的顺序存储,空间复杂度高0(n2)【n是结点的个数】,适合稠密图、不适合稀疏图
无向图:
是没有方向的,每一条边对应两个1.
1:表示的是:两个顶点之间,相互邻接
0:表示的是:两个顶点之间,相互不邻接
有向图:
由于是有方向的:每一条边对应1个1
A指向B的弧或者边。A行B列是为1。但是B行A列可能没有。
代码的实现:对邻接矩阵的定义:
- 如何求顶点的度、入度、出度?
无线图:
遍历所对应的某一行、列,记录非0元素的个数。得出度。
第i个结点的度=第i行(或第j列)的非零元素的个数。
时间复杂度是0(n),N是顶点的个数。也就是顶点V的个数。
有向图:
- 邻接矩阵法存储带权图(网)
-空间复杂度:0(n2) ——只和顶点数相关,和实际的边数无关。
- 适合用于存储稠密图,也就是边很多的图。
二、邻接表(顺序加链式)
1、常考的点:
邻接表:表示方式并不唯一。
比如A和bcd都相连。A的边链表可以用(123,也可以321的顺序)
邻接矩阵:
只要确定了各个结点的编号。图的邻接矩阵表示方式是唯一的。
2、代码分析:
1.顶点信息
- 用一维数组来存储顶点结点的信息,其中包括:数据域data、指向顶点的第一条边/弧的指针。
2.声明图
- 声明图:
- 1.顶点结点的一个数组
- 2.记录当前具体有多少个结点、边
3.边、弧的定义
//当前的边指向的那个结点。比如说:如果B的数组索引为1。A—>B.那么A指向的就是1。
3、邻接表存储有向图
例如A—>B。 那么A的后面跟了一个结点是1的弧。
结点存储的值是,是从该节点出发,到达该结点的索引。
1.求顶点的度=入度+出度
遍历这个结点 边界点的链表。从当前链表出去的的弧,也就是出度 。
而找到入度很麻烦:把所有节点的边链表都遍历
4、邻接表存储无向图
每一条边:在邻接表中都会对应两个结点。(a,b)(b,a)是一条边,但是表示了两次。所以边的数据是有冗余的。
- 边的结点的数量是边的实际数量的2倍。
1.求顶点的度
遍历这个顶点相关的单链表,有多少个边链表就是有多少个度。
三、十字链表(只能存储有向图)
一、邻接矩阵、邻接表的分析:
邻接矩阵的问题是:空间复杂度太高是:0(v2)。
邻接表的问题是:存储有向图的时候,要找入度不方便,需要遍历整个表。
而用十字链表来存储有向图的话,就可解决入度不方便和空间复杂度。
二、定义两个结构体:
顶点结点:
fistout指针:一直往后找各个结点,就可以找到从当前的顶点出发的所有的弧
fistin指针:一直顺着fistin指针,就可以找到所有指向当前结点的弧。
弧结点:
-共有四个结点ABCD,结点的信息存放在数组中。索引为0123
-A指向B和C。
A结点的firstout指针指向第一条弧的信息,也就是A指向B。
那么顺着它指向的tlink指针指向的是:弧尾相同的下一条弧。
也就是A指向的C。
-还有两条弧指向的是A:D和C指向A
-那么需要顺着A结点指向的fistin指针。也就是说C指向A。
继续顺着hlink指针,找到fistiin指针下一条弧。D指向A。
那么下面hlink指针为空,说明没有其他节点指向A的弧了
三、十字链表有向图空间复杂度:0(v+e)
四、邻接多重表(只能存储无向图)
一、分析邻接表:
用邻接表存储的问题:
1.每一条边会存储两次。每条边对应两份冗余信息。比如A和B有一条边,存储的时候就会A指向B,B指向A。
2.删除顶点:删除了A结点,还有删除A结点的边。还需要找到,冗余数据,将边界点指向A结点的存储进行删除。
二、邻接多重表的分析:
用邻接多重表来存储无向图:
想要找到和某结点相连接的边很方便。并且:每一条边只会对应一个边结点。只有一份数据。
这种特性就可以保证当我们删除边,很方便。
一、定义两个结构体:
1.顶点结点:
数据域和指针是指向 和当前这个顶点相连接的第一条边。
2.边界点
iLink:依附于顶点i的下一条边。
例如:
-
A指向B和D。
A顶点顺着firstedge指针,往后找相连接的第一条边,就是A指向B边。
在边结点的iLink指针,继续寻找,和i结点相连接的下一条边,就是A指向D的边。
找完了以后没有和A相连接的了,那么该结点的iLink指针是NULL -
B指向ACE这些结点与他相连接。
B结点的fistedge指针往后找,找到第一条边的信息,也就是A和B相连接的边。
在边结点的jLink指针,继续寻找,和j结点相连接的下一条边,就是BC结点中间的边。
直到jLink结点的指向NULL。说明找完所有的结点。
三、删除边和结点
-
例如我们要删除A和B之间的边,直接删除对应的边结点即可。
修改两个指针:
1、删除结点之前,顺着iLink指针找到下一条边。让该节点连接即可。
让A结点的firstedge的指针.指向后边的边即可。
同理B结点。 -
删出E顶点。
1.删除E的数据之外,删除和E相连的所有边的信息, 将边的ijLink的信息赋值给上一个ijLink。
四、空间复杂度
邻接多重表不需要存储边的多余的信息,