pythonc语言结构,图的顺序存储结构(包含C语言实现)

使用图结构表示的数据元素之间虽然具有“多对多”的关系,但是同样可以采用顺序存储,也就是使用数组有效地存储图。

使用数组存储图时,需要使用两个数组,一个数组存放图中顶点本身的数据(一维数组),另外一个数组用于存储各顶点之间的关系(二维数组)。

存储图中各顶点本身数据,使用一维数组就足够了;存储顶点之间的关系时,要记录每个顶点和其它所有顶点之间的关系,所以需要使用二维数组。

不同类型的图,存储的方式略有不同,根据图有无权,可以将图划分为两大类:图和网。

图,包括无向图和有向图;网,是指带权的图,包括无向网和有向网。存储方式的不同,指的是:在使用二维数组存储图中顶点之间的关系时,如果顶点之间存在边或弧,在相应位置用 1 表示,反之用 0 表示;如果使用二维数组存储网中顶点之间的关系,顶点之间如果有边或者弧的存在,在数组的相应位置存储其权值;反之用 0 表示。

结构代码表示:

#define MAX_VERtEX_NUM 20 //顶点的最大个数

#define VRType int //表示顶点之间的关系的变量类型

#define InfoType char //存储弧或者边额外信息的指针变量类型

#define VertexType int //图中顶点的数据类型

typedef enum{DG,DN,UDG,UDN}GraphKind; //枚举图的 4 种类型

typedef struct {

VRType adj; //对于无权图,用 1 或 0 表示是否相邻;对于带权图,直接为权值。

InfoType * info; //弧或边额外含有的信息指针

}ArcCell,AdjMatrix[MAX_VERtEX_NUM][MAX_VERtEX_NUM];

typedef struct {

VertexType vexs[MAX_VERtEX_NUM]; //存储图中顶点数据

AdjMatrix arcs; //二维数组,记录顶点之间的关系

int vexnum,arcnum; //记录图的顶点数和弧(边)数

GraphKind kind; //记录图的种类

}MGraph;

963ae606026ef1d466dc668e0d0a471c.png

图1 有向图和无向图

例如,存储图 1 中的无向图(B)时,除了存储图中各顶点本身具有的数据外,还需要使用二维数组存储任意两个顶点之间的关系。

由于 (B) 为无向图,各顶点没有权值,所以如果两顶点之间有关联,相应位置记为 1 ;反之记为 0 。构建的二维数组如图 2 所示。

b8e75ec5cc5d77c8d5a2e8da0703d8c8.gif

图2 无向图对应的二维数组arcs

在此二维数组中,每一行代表一个顶点,依次从 V1 到 V5 ,每一列也是如此。比如 arcs[0][1] = 1 ,表示 V1 和 V2 之间有边存在;而 arcs[0][2] = 0,说明 V1 和 V3 之间没有边。

对于无向图来说,二维数组构建的二阶矩阵,实际上是对称矩阵,在存储时就可以采用压缩存储的方式存储下三角或者上三角。

通过二阶矩阵,可以直观地判断出各个顶点的度,为该行(或该列)非 0 值的和。例如,第一行有两个 1,说明 V1 有两个边,所以度为 2。

存储图 1 中的有向图(A)时,对应的二维数组如图 3 所示:

3fae32f74ffd37e374906d7d3a18bd01.gif

图 3 有向图对应的二维数组arcs

例如,arcs[0][1] = 1 ,证明从 V1 到 V2 有弧存在。且通过二阶矩阵,可以很轻松得知各顶点的出度和入度,出度为该行非 0 值的和,入度为该列非 0 值的和。例如,V1 的出度为第一行两个 1 的和,为 2 ; V1 的入度为第一列中 1 的和,为 1 。所以 V1 的出度为 2 ,入度为 1 ,度为两者的和 3 。

图的顺序存储结构C语言实现

#include

#define MAX_VERtEX_NUM 20 //顶点的最大个数

#define VRType int //表示顶点之间的关系的变量类型

#define InfoType char //存储弧或者边额外信息的指针变量类型

#define VertexType int //图中顶点的数据类型

typedef enum{DG,DN,UDG,UDN}GraphKind; //枚举图的 4 种类型

typedef struct {

VRType adj; //对于无权图,用 1 或 0 表示是否相邻;对于带权图,直接为权值。

InfoType * info; //弧或边额外含有的信息指针

}ArcCell,AdjMatrix[MAX_VERtEX_NUM][MAX_VERtEX_NUM];

typedef struct {

VertexType vexs[MAX_VERtEX_NUM]; //存储图中顶点数据

AdjMatrix arcs; //二维数组,记录顶点之间的关系

int vexnum,arcnum; //记录图的顶点数和弧(边)数

GraphKind kind; //记录图的种类

}MGraph;

//根据顶点本身数据,判断出顶点在二维数组中的位置

int LocateVex(MGraph * G,VertexType v){

int i=0;

//遍历一维数组,找到变量v

for (; ivexnum; i++) {

if (G->vexs[i]==v) {

break;

}

}

//如果找不到,输出提示语句,返回-1

if (i>G->vexnum) {

printf("no such vertex.\n");

return -1;

}

return i;

}

//构造有向图

void CreateDG(MGraph *G){

//输入图含有的顶点数和弧的个数

scanf("%d,%d",&(G->vexnum),&(G->arcnum));

//依次输入顶点本身的数据

for (int i=0; ivexnum; i++) {

scanf("%d",&(G->vexs[i]));

}

//初始化二维矩阵,全部归0,指针指向NULL

for (int i=0; ivexnum; i++) {

for (int j=0; jvexnum; j++) {

G->arcs[i][j].adj=0;

G->arcs[i][j].info=NULL;

}

}

//在二维数组中添加弧的数据

for (int i=0; iarcnum; i++) {

int v1,v2;

//输入弧头和弧尾

scanf("%d,%d",&v1,&v2);

//确定顶点位置

int n=LocateVex(G, v1);

int m=LocateVex(G, v2);

//排除错误数据

if (m==-1 ||n==-1) {

printf("no this vertex\n");

return;

}

//将正确的弧的数据加入二维数组

G->arcs[n][m].adj=1;

}

}

//构造无向图

void CreateDN(MGraph *G){

scanf("%d,%d",&(G->vexnum),&(G->arcnum));

for (int i=0; ivexnum; i++) {

scanf("%d",&(G->vexs[i]));

}

for (int i=0; ivexnum; i++) {

for (int j=0; jvexnum; j++) {

G->arcs[i][j].adj=0;

G->arcs[i][j].info=NULL;

}

}

for (int i=0; iarcnum; i++) {

int v1,v2;

scanf("%d,%d",&v1,&v2);

int n=LocateVex(G, v1);

int m=LocateVex(G, v2);

if (m==-1 ||n==-1) {

printf("no this vertex\n");

return;

}

G->arcs[n][m].adj=1;

G->arcs[m][n].adj=1;//无向图的二阶矩阵沿主对角线对称

}

}

//构造有向网,和有向图不同的是二阶矩阵中存储的是权值。

void CreateUDG(MGraph *G){

scanf("%d,%d",&(G->vexnum),&(G->arcnum));

for (int i=0; ivexnum; i++) {

scanf("%d",&(G->vexs[i]));

}

for (int i=0; ivexnum; i++) {

for (int j=0; jvexnum; j++) {

G->arcs[i][j].adj=0;

G->arcs[i][j].info=NULL;

}

}

for (int i=0; iarcnum; i++) {

int v1,v2,w;

scanf("%d,%d,%d",&v1,&v2,&w);

int n=LocateVex(G, v1);

int m=LocateVex(G, v2);

if (m==-1 ||n==-1) {

printf("no this vertex\n");

return;

}

G->arcs[n][m].adj=w;

}

}

//构造无向网。和无向图唯一的区别就是二阶矩阵中存储的是权值

void CreateUDN(MGraph* G){

scanf("%d,%d",&(G->vexnum),&(G->arcnum));

for (int i=0; ivexnum; i++) {

scanf("%d",&(G->vexs[i]));

}

for (int i=0; ivexnum; i++) {

for (int j=0; jvexnum; j++) {

G->arcs[i][j].adj=0;

G->arcs[i][j].info=NULL;

}

}

for (int i=0; iarcnum; i++) {

int v1,v2,w;

scanf("%d,%d,%d",&v1,&v2,&w);

int m=LocateVex(G, v1);

int n=LocateVex(G, v2);

if (m==-1 ||n==-1) {

printf("no this vertex\n");

return;

}

G->arcs[n][m].adj=w;

G->arcs[m][n].adj=w;//矩阵对称

}

}

void CreateGraph(MGraph *G){

//选择图的类型

scanf("%d",&(G->kind));

//根据所选类型,调用不同的函数实现构造图的功能

switch (G->kind) {

case DG:

return CreateDG(G);

break;

case DN:

return CreateDN(G);

break;

case UDG:

return CreateUDG(G);

break;

case UDN:

return CreateUDN(G);

break;

default:

break;

}

}

//输出函数

void PrintGrapth(MGraph G)

{

for (int i = 0; i < G.vexnum; i++)

{

for (int j = 0; j < G.vexnum; j++)

{

printf("%d ", G.arcs[i][j].adj);

}

printf("\n");

}

}

int main() {

MGraph G;//建立一个图的变量

CreateGraph(&G);//调用创建函数,传入地址参数

PrintGrapth(G);//输出图的二阶矩阵

return 0;

}

注意:在此程序中,构建无向网和有向网时,对于之间没有边或弧的顶点,相应的二阶矩阵中存放的是 0。目的只是为了方便查看运行结果,而实际上如果顶点之间没有关联,它们之间的距离应该是无穷大(∞)。

例如,使用上述程序存储图 4(a)的有向网时,存储的两个数组如图 4(b)所示:

b06dc325686d93a0d74e814cbbe256fe.png

图 4 有向网

相应地运行结果为:

2

6,10

1

2

3

4

5

6

1,2,5

2,3,4

3,1,8

1,4,7

4,3,5

3,6,9

6,1,3

4,6,6

6,5,1

5,4,5

0 5 0 7 0 0

0 0 4 0 0 0

8 0 0 0 0 9

0 0 5 0 0 6

0 0 0 5 0 0

3 0 0 0 1 0

总结一下,本节主要详细介绍了使用数组存储图的方法,在实际操作中使用更多的是链式存储结构,例如邻接表、十字链表和邻接多重表,这三种存储图的方式放在下一节重点去讲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值