6.4图的存储结构
**写在前面:**这些是我学习的时候的一些个人理解和笔记,如有错误,欢迎指正。
图是没有顺序存储结构的,但可以借助二维数组来表示元素之间的关系,即邻接矩阵表示法;图的链式存储有邻接表、十字链表和邻接多重表。
6.4.1邻接矩阵
邻接矩阵是表示顶点之间的相邻关系的矩阵。
如果是图:有边相关联的值为1,没有则为0;
如果是网:有边相关联的值为权值,没有则无穷。
有向图的邻接矩阵:出度找行,入度找列;
无向图的邻接矩阵是对称的,顶点的度:看行或者列都可以。
邻接矩阵的存储表示
需要两个表(顶点表和邻接矩阵表)+点数和边数
#define MaxInt 32767 //表示极大值
#define MVNum 100 //最大的顶点数
typedef char VerTexType; //顶点数据类型
typedef int ArcType; //假设边的权值类型为整型
typedef struct
{
VerTexType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵表
int vexnum,arcnum; //图的当前点数和边数
}AMGraph;
邻接矩阵创建无向网的算法描述
时间复杂度:O(n^2)
1.输入总顶点数和边数
2.将顶点信息存到顶点表中
3.初始化邻接矩阵,权值设为最大值
4.构造邻接矩阵
Status CreateUDN(AMGraph &G)
{//采用邻接矩阵表示法创建无向网
cin>>G.vexnum>>G.arcnum; //输入顶点个数,边的个数
for(int i=0;i<G.vexnum;++i)
cin>>G.vexs[i];
for(int i=0;i<G.vexnum;++i)
for(int j=0;j<G.vexnum;+j)
G.arcs[i][j]=MaxInt; //初始化邻接矩阵,变得权值默认最大
for(int k=0;k<G.arcnum;++k) //开始构造邻接矩阵
{
cin>>v1>>v2>>w; //输入顶点和权值
i=LocateVex(G,v1);j=LocateVex(G,v2); //确定v1,v2在G中的位置
G.arcs[i][j]=w; //网图有权值
G.arcs[j][i]=G.arcs[i][j]; //因为是无向网图
}
return OK;
}
邻接矩阵的优缺点
优点:
1.便于判断两顶点间有无边,看A[i][j]等于1还是0;
2.便于计算各个顶点的度。
缺点:
1.不便于增加和删除顶点
2.不便于统计变得数目,需要扫描邻接矩阵的所有元素才能知道,时间复杂度O(n^2)
3.空间复杂度高,空间复杂度为O(n^2)
6.4.2邻接表
邻接表是图的一种链式存储结构。
邻接表由两部分组成:表头结点和边表
- 表头结点:包括数据域和链域两部分,数据域存储顶点信息,链域用于指向链表中的第一个结点。
- 边表:包括邻接点域、数据域、链域三部分组成
图的邻接表的存储表示
需要3个结构体:边结点、顶点、邻接表
#define MVNum 100//最大顶点数
typedef struct ArcNode //边结点
{
int adjvex; //边所指的顶点位置
struct ArcNode *nextarc;//指向下一条边的指针
OtherInfo info;//和边的相关信息(如可以放权值)
}ArcNode;
typedef struct VNode //顶点
{
VerTexType data;
ArcNode * firstarc;//指向第一条依附该顶点的边的指针
}VNode,AdjList[MVNum];
typedef struct //邻接表
{
AdjList vertices;
int vexnum,arcnum; //当前的顶点数和边数
}ALGraph;
邻接表创建无向图的算法描述
时间复杂度:O(n+e)
1.输入顶点数和边数
2.输入顶点并且将其存如顶点表中,每个表头指针域初始化为NULL
3.创建邻接表。输入边依附的两个顶点,找到顶点的位置i,j,通过头插法把边结点插入
Status CreateUDG(ALGraph &G)
{
cin>>G.vexnum>>G.arcnum; //输入点数和边数
for(int i=0;i<G.vexnum;++i) //存顶点信息
{
cin>>G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
for(int i=0;i<G.arcnum;++i)
{
cin>>v1>>v2; //边依附的两个顶点
i=LocateVex(G,v1);j=LocateVex(G,v2);
ArcNode *p1=new ArcNode;//头插法
p1->adjvex=j;
p1->nextarc=G.vertices[i].firstarc; G.vertices[i].firstarc=p1;
ArcNode *p2=new ArcNode;
p2->adjvex=i;
p2->nextarc=G.vertices[j].firstarc; G.vertices[j].firstarc=p2;
}
return OK;
}
邻接表的优缺点
优点:
1.便于增加和删除结点
2.便于统计边的数目,按照顶点表扫描所有边表可以得到边的数目,时间复杂度为O(n+e)
3.空间效率高,空间复杂度为O(n+e)
缺点:
1.不便于判断顶点之间是否有边,要判断vi和vj是否有边,需要扫描第i个边表,最坏情况需要耗费O(n)时间
2.不便于计算个顶点的度数。无向图容易计算,有向图的出度也容易计算但是入度计算需要遍历整个链表