图的数据类型的构建

1.图的抽象数据类型定义

ADT Graph
{
数据对象:具有相对特性的数据元素的集合,称为顶点集。
数据关系:R={VR}边,有意义
基本操作:
图结构的创建;
图结构的销毁;
在图中找特定结点;
对图中某个结点进行赋值;
返回某个结点的邻接结点;
添加新的结点;
删除某个结点;
深度优先遍历图;
广度优先遍历;
}ADT Graph

2.图的存储结构

2.1.分析图存储的数据类型

由于图中顶点之间的关系是多对多,即m:n,m和n都是不定的,所以从图中的关系不能通过顶点之间的存储位置反映顶点之间的逻辑关系,必须另外引入存储空间来存储顶点之间的领接关系
图中包括如下三部分信息:顶点信息;边(弧)信息,即顶点的关系;顶点数,边(弧)数。

2.1.1.顶点的存储

顶点集动态变化概率相对较小,可以预先估计最大顶点数分配空间。

2.1.2. 顶点关系的存储

在顶点确定的情况下,边或弧的数目往往是不确定。在实际应用中,可能会改变图中顶点之间的关系。采用下述方法存储关系集:
(1)领接矩阵表示法:两个结点领接,设置为1,否则设置为0;有权的话就用权值,否则人为设置一个值。
(2)领接表表示法:将每一个顶点的领接串接成一个单向链表,称为邻接表。

2.1.3.顶点数和边(弧)数的存储

用两个整形分别存储顶点数和边数。

2.2.图的领接矩阵表示

2.2.1. 图的领接矩阵数据类型

/**********************************图领接矩阵数据定义****************************************************/
#define VNUM 20
typedef char VertexType;//顶点的数据类型
typedef struct
{
	VertexType vexs[VNUM];//存储顶点结点信息
	int arcs[VNUM][VNUM];//存储顶点的关系
	int vexNum, arcNum;//存储顶点数和弧数
}MGraph;//定义图的类型

/***********************************************************************************************************/

/**********************************网领接矩阵数据定义****************************************************/
#define VNUM 20
typedef int WeightType;//边上权值的数据类型
typedef struct
{
	VertexType vexs[VNUM];//存储顶点结点信息
	WeightType arcs[VNUM][VNUM];//存储顶点的关系(边或弧上的权值)
	int vexNum, arcNum;//存储顶点数和弧数
}NetGraph;//定义网的数据类型
/***********************************************************************************************************/

2.2.2. 图的邻接矩阵生成算法

【算法实现】

//创建无向图的邻接矩阵
void crt_MGragh(MGraph* G)
{
	int ret=scanf("%d%d", &G->vexNum, &G->arcNum);//输入顶点数和边数
	for (int i = 0; i < G->vexNum; i++)ret=scanf("%c", &G->vexs[i]);//输入顶点数信息
	for (int i = 0; i < G->vexNum; i++)//领接矩阵初始化
	{
		for (int j = 0; j < G->vexNum; j++)
		{
			G->arcs[i][j] = 0;
		}
	}
	int i = 0, j = 0;
	for (int k = 0; k < G->arcNum; k++)
	{
		ret=canf("%d%d", &i, &j);//读入一条边,i和j是顶点的序号(与下标相差1)
		G->arcs[i - 1][j - 1] = 1;
		G->arcs[j - 1][i - 1] = 1;
	}
}

//调试程序:判断是否创建成功:显示顶点值和邻接矩阵
void dispMGraph(const MGraph* G)
{
	int i = 0, j = 0;
	printf("顶点如下\n");
	for (i = 0; i < G->vexNum; i++)printf("%c ", G->vexs[i]);
	printf("\n邻接矩阵如下\n");
	for (i = 0; i < G->vexNum; i++)
	{
		for (j = 0; j < G->vexNum; j++)printf("%4d", G->arcs[i][j]);
		printf("\n");
	}
}

2.2.3. 邻接矩阵的特点

(1)二维数组arcs中的元素值描述了边的邻接关系以及边上是否有权。
(2)无向图和无向网的邻接矩阵是对称矩阵,有向图和有向网的邻接矩阵不一定是对称矩阵。一旦图中顶点的顺序确定之后,邻接矩阵是唯一。
(3)对于边(弧)个数较少的稀疏图,其邻接矩阵也是稀疏的,有较多的0,用二维数组存储领接矩阵是存储空间利用率较低。
(4)存储特点是一种顺序存储结构。

较为合适的操作如下:
(1)计算顶点的度:无向图中第i个结点的度为二位数组arcs的第i行或第i列的非零元素个数或非无穷的元素个数。有向图中第i个顶点的出度为arcs二维数组的第i行非零元素个数;有向图中第i列个顶点的入度为arcs二维数组的第i列非零元素个数。
(2)求一个顶点的所有领接结点:二维数组arcs第i行的所有非零元素(不包括无穷)均表示与第i个顶点有领接关系。
(3)插入或删除一条边(弧):根据要插入或删除边(弧)位置,修改二维数组某个元素的值。
不适合操作:顶点的插入和删除(二位数组不能随意增加行或列)

2.3. 图的邻接表表示

2.3.1. 图的邻接表的数据定义

/**************************************图的领接表数据类型*************************************************/
//领接表的边结点类型
#define MAXSITZE 20//图的最大顶点数
typedef struct ArcNode
{
	int adjvex;//弧所指向顶点的下标
	struct ArcNode* nextArc;//指向下一条弧的指针
	WeightType info;//用于存放边上的信息
}ArcNode;//边结点类型
//领接表的表头结点类型
typedef int GelemType;//存放顶点值类型
typedef struct VertexNode
{
	GelemType vertex; //存放顶点值
	ArcNode* firstArc;//存放边链表的头指针
}VertexNode;//表头结点类型
//图的领接表类型
typedef struct ALGraph
{
	VertexNode adjlist[MAXSITZE];//一维结构体数组
	int vexNum, arcNum;//存放顶点数和边数
}ALGraph;//图的邻接表类型

/***********************************************************************************************************/

2.3.2. 图的邻接表的创建和显示算法

//创建有向图的领接表生成算法
void crt_ALGraph(ALGraph* G)
{
	scanf("%d%d", &G->vexNum, &G->arcNum);//输入顶点个数和弧数
	for (int i = 0; i < G->vexNum; i++)//初始化
	{
		scanf("%d", &G->adjlist[i].vertex);//输入结点信息
		G->adjlist[i].firstArc = NULL;
	}
	int k = 0, i = 0, j = 0;
	for (k = 0; k < G->arcNum; k++)
	{
		scanf("%d%d", &i, &j);//输入边的信息
		ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
		assert(p);
		p->adjvex = j - 1;
		p->nextArc = G->adjlist[i - 1].firstArc;//头插
		G->adjlist[i - 1].firstArc = p;
	}
}
//显示图的领接表函数
void dispALGraph(const ALGraph* G)
{
	int i=0;
	printf("领接链表如下\n");
	for (i = 0; i < G->vexNum; i++)
	{
		printf("%d:", i); printf("%d", G->adjlist[i].vertex);//显示头结点
		if (G->adjlist[i].firstArc == NULL)printf("^\n");//边链表为空
		else//显示非空边链表
		{
			ArcNode* p = G->adjlist[i].firstArc;//p指向第一个边结点
			while (p)
			{
				printf("%3d-->", p->adjvex);
				p = p->nextArc;
			}
			printf("^\n");
		}
	}//end_for
}

2.3.3. 邻接表的性质

(1)图的邻接表的表示不是唯一的,它与邻接点的读入顺序有关。
(2)无向图邻接表中第i个单链表中结点个数为第i个顶点的度。
(3)有向图邻接表中第i个单链表中的结点个数为第i个顶点的出度;其逆邻接表中第i个单链表中的结点个数为第i个顶点的入度。
(4)无向图的边数为邻接表中边结点个数的一半;有相同的弧数与邻接表中边链表的结点个数相同。
(5)无向图的一条边分别存在在两个边链表中;有向图的一条边只存在一个边链表中。

2.3.4.邻接表的特点

存储特点是:邻接表是一种顺序(表头数组)+链式(边链表)的存储结构,当图中顶点个数较多而边比较少时,可以节省大量的空间。
较为合适的操作有:计算顶点vi的出度;求一个顶点的所有邻接点;插入或删除一条边(弧);求顶点的一个邻接点的下一个邻接点。当在无向图(网)中插入一条边或删除一条边时,要在两个边链表中的操作。
不太合适的操作有:顶点的插入和删除;计算顶点的入度等。

2.4.有向图的十字链表表示

/*************************************有向图的十字链表数据类型*******************************************/
//①十字链表的结点类型
#define MAX_VERTEX_NUM 20
typedef int InfoType;//弧相关信息类型
typedef struct ArcBox
{
	int tailvex, headvex;//该弧的尾和头结点的位置
	struct ArcBox* hlink, * tlink;//分别指向下一个弧头和弧尾均相同的弧的指针域
	InfoType* info;//该弧相关信息的指针
}ArcBox;
//②表头结点类型
typedef struct
{
	VertexType data;
	ArcBox* firstin, * firstout;//分别指向该顶点的第一个入弧和出弧
}VexNode;
//十字链表类型
typedef struct
{
	VexNode xlist[MAX_VERTEX_NUM];//表头数组
	int vexNum, arcNum;//有向图的当前顶点数和弧数
}OLGraph;
/***********************************************************************************************************/

2.5.无向图的邻接多重表表示

/***********************************无向图的邻接多重表表示************************************************/
//便于修改边的权重——修改一次即可

//①边结点类型描述
typedef struct Ebox
{
	int mark;//访问标记
	int ivex, jvex;//该边依附的两个顶点的位置
	struct EBox* ilink, *jlink;//分别指向依附这两个顶点的下一条边
	InfoType* info;//该边信息指针
}EBox;
//②顶点结点类型描述
typedef struct VexBox
{
	VertexType data;
	EBox* firstedge;//指向第一条依附该顶点的边
}VexBox;
//③多重邻接表的类型描述
typedef struct
{
	VexBox adjmulist[MAX_VERTEX_NUM];
	int vexNum, edgeNum;//无向图的当前顶点数和边数
}AMLGraph;

/***********************************************************************************************************/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰深入学习计算机

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值