图有等存储结构
① 图的存储结构有哪些
最常见的:
顺序查找:适合顺序结构和链式结构
二分查找:适合顺序结构
其他的二叉查找树、B-树之类有自己的数据结构
② 图的五种存储结构
图的邻接矩阵(Adjacency Matrix): 图的邻接矩阵用两个数组来表示图。一个一维数组存储图中顶点信息,另一个二维数组(一般称之为邻接矩阵)来存储图中的边或者弧的信息。从邻接矩阵中我们自然知道一个顶点的度(对于无向图)或者有向图中一个顶点的入度出度信息。
假设图G有n个顶点,则邻接矩阵是一个n*n的方阵。
1.对于如果图上的每条边不带权值来说,那么我们就用真(一般为1)和假(一般为0)来表示一个顶点到另一个顶点存不存在边。下面是一个图的邻接矩阵的定义:
邻接矩阵法实现带权值的无向图的创建如下:
按照如图输入各边(不重复)
测试程序如下:
结果可得该矩阵,证明创建树成功。 假设n个顶点e条边的创建,createGraph算法的时间复杂度为O(n+n*n+e)。如果需要创建一个有向图,那么和上面一样一个一个录入边下标和权值。
邻接矩阵这种存储结构的优缺点: 缺点是对于边数相对顶点较少的稀疏图来说会存在极大的空间浪费。假设有n个顶点,优点是对于有向完全图和无向完全图来说邻接矩阵是一种不错的存储结构,浪费的话也只浪费了n个顶点的容量。
在树的存储结构一节中我们提到对于孩子表示法的第三种:用一段连续的存储单元(数组)存储树中的所有结点,利用一个单链表来存储数组中每个结点的孩子的信息。对于图的存储结构来说,我们也可以利用这种方法实现图的存储
邻接表(Adjacency List): 这种数组与链表相结合的存储方法叫做邻接表。1.为什么不也用单链表存储图的结点信息呢?原因就是数组这种顺序存储结构读取结点信息速率快。对于顶点数组中,每个数据元素还需要存储一个指向第一个邻接顶点的指针,这样才可以查找边的信息2.图中每个顶点Vi(i > 0)的所有邻接点构成一个线性表 (在无向图中这个线性表称为Vi的边表,有向图中称为顶点作为弧尾的出边表) ,由于邻接点的不确定性,所以用链表存储,有多少个邻接点就malloc一个空间存储邻接点,这样更不会造成空间的浪费(与邻接矩阵相比来说)。3.对于邻接表中的某个顶点来说,用户关心的是这个顶点的邻接点,完全可以遍历用单链表设计成的边表或者出边表得到,所以没必要设计成双链表。
邻接表的存储结构:
假设现在有一无向图G,如下图:
从邻接表结构中,知道一个顶点的度或者判断两个顶点之间是否存在边或者求一个顶点的所有邻接顶点是很容易的。
假设现在有一有向图G,如下图:
无向图的邻接表创建示例如下:
假设在上图(无向图)中的V0V1V2V3顶点值为ABCD,则依据下面测试程序可得结果:
邻接表的优缺点: 优点是:邻接表存储图,既能够知道一个顶点的度和顶点的邻接结点的信息,并且更不会造成空间的浪费。缺点是邻接表存储有向图时,如果关心的是顶点的出度问题自然用邻接表结构,但是想了解入度需要遍历图才知道(需要考虑逆邻接表)。
十字链表(Orthogonal List) :有向图的一种存储方法,它把邻接表和逆邻接表结合起来,因此在十字链表结构中可以知道一个顶点的入度和出度情况。
重新定义顶点表的结点如下图:
现在有一有向图如下图:
则它的存储结构示意图为:
其定义如下:
十字链表是用来存储有向图的,这样可以看出一个顶点的出入度信息。对于无向图来说完全没必要用十字链表来存储。
在无向图中,因为我们关注的是顶点的信息,在考虑节约空间的情况下我们利用邻接表来存储无向图。但是如果我们关注的是边的信息,例如需要删除某条边对于邻接表来说是挺繁琐的。它需要操作两个单链表删除两个结点。因此我们仿照十字链表的方式对边表结点结构重新定义如下图:
它的邻接多重表结构为:
多重邻接表的优点:对于边的操作相比于邻接表来说更加方便。比如说我们现在需要删除(V0,V2)这条边,只需将69步骤中的指针改为nullptr即可。
边集数组(edgeset array): 边集数组是由两个数组组成,一个存储顶点信息,另一个存储边的信息,这个边数组中的每个数据元素由起点下标,终点下标,和权组成(如果边上含有权值的话)。
边数组结构如下图:
边集数组实现图的存储的优缺点:优点是对于边的操作方便快捷,操作的只是数组元素。比如说删除某条边,只需要删除一个数组元素。缺点是:对于图的顶点信息,我们只有遍历整个边数组才知道,这个费时。因此对于关注边的操作来说,边集数组更加方便。
③ 《数据结构》 常见的图的存储结构包括了哪些
矩阵,链表
④ 有关图的存储结构
(1)顺序存储方法
该方法把逻辑上相邻的结点存储在物理位置上相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现。
由此得到的存储表示称为顺序存储结构 (Sequential Storage Structure),通常借助程序语言的数组描述。
该方法主要应用于线性的数据结构。非线性的数据结构也可通过某种线性化的方法实现顺序存储。 (2)链接存储方法
该方法不要求逻辑上相邻的结点在物理位置上亦相邻,结点间的逻辑关系由附加的指针字段表示。由此得到的存储表示称为链式存储结构(Linked Storage Structure),通常借助于程序语言的指针类型描述。
⑤ 图的存储结构——所存储的信息有哪些
一、邻接矩阵存储方法
邻接矩阵是表示顶点之间相邻关系的矩阵。
设G=(V,E)是具有n(n>0)个顶点的图,顶点的顺序依次为0~n-1,则G的邻接矩阵A是n阶方阵,其定义如下:
(1)如果G是无向图,则:
A[i][j]=1:若(i,j)∈E(G) 0:其他
(2)如果G是有向图,则:
A[i][j]=1:若<i,j>∈E(G) 0:其他
(3)如果G是带权无向图,则:
A[i][j]= wij :若i≠j且(i,j)∈E(G) 0:i=j ∞:其他
(4)如果G是带权有向图,则:
A[i][j]= wij :若i≠j且<i,j>∈E(G) 0:i=j∞:其他
注意:带权图和不带权图表示的元素类型不同。
带权图(不论有向还是无向图)A[i][j]用double表示,不带权图(不论有向还是无向图)A[i][j]用int表示。
用一维数组G[ ]存储有4个顶点的无向图如:G[ ] = { 0, 1, 0, 1, 1, 0, 0, 0, 1, 0 }
则顶点2和顶点0之间是有边的。
如:
邻接矩阵的特点如下:
(1)图的邻接矩阵表示是唯一的。
(2)无向图的邻接矩阵一定是一个对称矩阵。因此,按照压缩存储的思想,在具体存放邻接矩阵时只需存放上(或下)三角形阵的元素即可。
(3)不带权的有向图的邻接矩阵一般来说是一个稀疏矩阵。因此,当图的顶点较多时,可以采用三元组表的方法存储邻接矩阵。
(4)对于无向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点的度。
(5)对于有向图,邻接矩阵的第i行(或第i列)非零元素(或非∞元素)的个数正好是第i个顶点的出度(或入度)。
(6)用邻接矩阵方法存储图,很容易确定图中任意两个顶点之间是否有边相连。但是,要确定图中有多少条边,则必须按行、按列对每个元素进行检测,所花费的时间代价很大。这是用邻接矩阵存储图的局限性。
邻接矩阵的数据类型定义如下:
#define MAXV <最大顶点个数>
typedef struct
{ int no; //顶点编号
InfoType info; //顶点其他信息
} VertexType; //顶点类型
typedef struct //图的定义
{ int edges[MAXV][MAXV]; //邻接矩阵
int n,e; //顶点数,弧数
VertexType vexs[MAXV]; //存放顶点信息
} MGraph; //图的邻接矩阵表示类型
二、 邻接表存储方法
图的邻接表存储方法是一种顺序分配与链式分配相结合的存储方法。
在邻接表中,对图中每个顶点建立一个单链表,第i个单链表中的节点表示依附于顶点i的边(对有向图是以顶点i为尾的边)。每个单链表上附设一个表头节点。
其中,表节点由三个域组成,adjvex指示与顶点i邻接的点在图中的位置,nextarc指示下一条边或弧的节点,info存储与边或弧相关的信息,如权值等。
表头节点由两个域组成,data存储顶点i的名称或其他信息,firstarc指向链表中第一个节点。
typedef struct ANode
{ int adjvex; //该边的终点编号
struct ANode *nextarc; //指向下一条边的指针
InfoType info; //该边的相关信息
} ArcNode; //边表节点类型
typedef struct Vnode
{ Vertex data; //顶点信息
ArcNode *firstarc; //指向第一条边
} VNode; //邻接表头节点类型
typedef VNode AdjList[MAXV]; //AdjList是邻接表类型
typedef struct
{ AdjList adjlist; //邻接表
int n,e; //图中顶点数n和边数e
} ALGraph; //完整的图邻接表类型
邻接表的特点如下:
(1)邻接表表示不唯一。这是因为在每个顶点对应的单链表中,各边节点的链接次序可以是任意的,取决于建立邻接表的算法以及边的输入次序。
(2)对于有n个顶点和e条边的无向图,其邻接表有n个顶点节点和2e个边节点。显然,在总的边数小于n(n-1)/2的情况下,邻接表比邻接矩阵要节省空间。
(3)对于无向图,邻接表的顶点i对应的第i个链表的边节点数目正好是顶点i的度。
(4)对于有向图,邻接表的顶点i对应的第i个链表的边节点数目仅仅是顶点i的出度。其入度为邻接表中所有adjvex域值为i的边节点数目。
例, 给定一个具有n个节点的无向图的邻接矩阵和邻接表。
(1)设计一个将邻接矩阵转换为邻接表的算法;
(2)设计一个将邻接表转换为邻接矩阵的算法;
(3)分析上述两个算法的时间复杂度。
解:
(1)在邻接矩阵上查找值不为0的元素,找到这样的元素后创建一个表节点并在邻接表对应的单链表中采用前插法插入该节点。
void MatToList(MGraph g,ALGraph *&G)
//将邻接矩阵g转换成邻接表G
{ int i,j,n=g.n; ArcNode *p; //n为顶点数
G=(ALGraph *)malloc(sizeof(ALGraph));
for (i=0;i<n;i++) //给所有头节点的指针域置初值
G->adjlist[i].firstarc=NULL;
for (i=0;i<n;i++) //检查邻接矩阵中每个元素
for (j=n-1;j>=0;j--)
if (g.edges[i][j]!=0)
{ p=(ArcNode *)malloc(sizeof(ArcNode));
//创建节点*p
p->adjvex=j;
p->nextarc=G->adjlist[i].firstarc;
//将*p链到链表头
G->adjlist[i].firstarc=p;
}
G->n=n;G->e=g.e;
}
(2)在邻接表上查找相邻节点,找到后修改相应邻接矩阵元素的值。
void ListToMat(ALGraph *G,MGraph &g)
{ int i,j,n=G->n;ArcNode *p;
for (i=0;i<n;i++)
{ p=G->adjlist[i].firstarc;
while (p!=NULL)
{ g.edges[i][p->adjvex]=1;
p=p->nextarc;
}
}
g.n=n;g.e=G->e;
}
(3)算法1的时间复杂度均为O(n2)。算法2的时间复杂度为O(n+e),其中e为图的边数。
⑥ 计算机考研:数据结构常用算法解析(7)
第七章:
对于无向图,e的范围是:
数据结构中所讨论的图都是简单图,任意两结点间不会有双重的边。
对于有向图,e的范围是:
图的各种存储结构
邻接矩阵很方便访问任意两点的边,但是不方便计算其邻接点。在深度和广度遍历中广泛的需要求某点的邻接点。所以邻接矩阵只在Floyed和Prim和Dijstra中采用。
邻接表能很方便的求某顶点的邻接点,索引对于与遍历有关的算法大多都采用邻接表。如深度、广度、拓扑排序、关键路径。但他也有不足的地方,就是不方便求入度或是那些薯早握点可以到他的操作。所以有人引进逆邻接表。最后人们把这两种表结合到一起就是十字链表和邻接多重表。一个是存储有向图,另一个是存储无向图。
在十字链睁历表和邻接多重表很方便求邻接点的操作和对应的逆操作。所以实际应用中,凡是能用邻接表实现的一定能用十字链表和邻接多重表实现。并且它们的存储效率更高。
1.邻接矩阵(有向图和无向图和网)又称为数组表示法
typedef struct
{ vextype vexs[maxn]; ∥顶点存储空间∥
adjtype A[maxn][maxn]; ∥邻接矩阵∥
int vexnum,arcnum; //图的顶点数和边数
GraphKind Kind; //图的类型
} mgraph;
2.邻接表(有向图和无向图和网)
typedef struct node ∥边
{ int adj; int w; ∥邻接点、权∥
struct node *next; ∥指向下一弧或边∥
}linknode;
typedef struct ∥顶点类型∥
{ vtype data; ∥顶点值域∥
linknode *farc; ∥指向与本顶点关联的第一条弧或边∥
}Vnode;
typedef struct
{
Vnode G[maxn]; ∥顶点表∥
int vexnum,arcnum;
GraphKind kind;
}ALGraph;
adjvexnextarcinfo
边结点
datafirstarc
顶点结点
3.十字链表(有向图和有向网)
headvextaivexhlinktlinkinfo
边结点
datafirstinfirstout
顶点结点
4.邻接多重表(无向图)
markivexjvexilinkjlinkinfo
边结点
datafirstedge
顶点结点
有向无环图(DAG):是描述含有公共子式的表达式的有效工具。二叉树也能表示表达式,但是利用有向无环图可以实现对相同子式的共享,从而节省存储空间。
顶点的度:
无向图:某顶点V的度记为D(V),代表与V相关联的边的条数
有向图:顶点V的度D(V)=ID(V)+OD(V)
强连通分量:在有向图中,若图中任意两顶点间都存在路径,则称其是强连通图。图中极大 强连通子图称之为强连通分量
“极大”在这里指的是:往一个连通分量中再加入顶点和边,就构不成原图中的一个 连通子图,即连通分量是一个最大集的连通子图。有向图的连通就是指该有向图是强连通的。
考研有疑问、不知道如何总结考研考点内容、不清楚数庆考研报名当地政策,点击底部咨询官网,免费领取复习资料:https://www.87dh.com/xl/
⑦ 存储结构有哪几种
存储结构有:
1、链接存储:在计算机中用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。
例:链。
2、顺序存储:在计算机中用一组地址连续的存储单元依次存储线性表的各个数据元素,称作线性表的顺序存储结构。
例:数组,链。
3、索引存储:除建立存储结点信息外,还建立附加的索引表来标识结点的地址,索引表由若干索引项组成。
例:线索树。
4、散列存储:散列存储,又称hash存储,是一种力图将数据元素的存储位置与关键码之间建立确定对应关系的查找技术。
例:栈(既可以通过顺序存储也可以同通过随机存储)。
顺序存储和链接存储的基本原理:
在顺序存储中,每个存储空间含有所存元素本身的信息,元素之间的逻辑关系是通过数组下标位置简单计算出来的线性表的顺序存储,若一个元素存储在对应数组中的下标位置为i,则它的前驱元素在对应数组中的下标位置为i-1,它的后继元素在对应数组中的下标位置为i+1。
在链式存储结构中,存储结点不仅含有所存元素本身的信息,而且含有元素之间逻辑关系的信息。
在数据的顺序存储中,由于每个元素的存储位置都可以通过简单计算得到,所以访问元素的时间都相同。
而在数据的链接存储中,由于每个元素的存储位置保存在它的前驱或后继结点中,所以只有当访问到其前驱结点或后继结点后才能够按指针访问到,访问任一元素的时间与该元素结点在链式存储结构中的位置有关。
⑧ 图的存储结构是什么
由于图的结构比较复杂,任意两个顶点之间都可能存在关系(边),无法通过存储位置表示这种任意的逻辑关系,所以,图无法采用顺序存储结构。这一点同其他数据结构(如线性表、树)不同。考虑图的定义,图是由顶点和边组成的,所以,分别考虑如何存储顶点和边。图常用的存储结构有邻接矩阵、邻接表、十字链表和邻接多重表。