C语言—邻接矩阵和邻接表的理解

要谈邻接表,那我们先谈谈邻接矩阵,因为邻接表就是因为邻接矩阵对于稀疏图造成内存的很大浪费。那么它是如何浪费的哪? 别急慢慢来!

  • 什么叫做邻接矩阵?
    它就是存储顶点是否存在连接关系的二维数组如下(右),关系图(左)
    在这里插入图片描述在这里插入图片描述
    解释图:如果a1->a2有线连接的话,用1表示反之用0表示。
    代码如下:
#define MAX_VERTEX_NUM 20  /*最多顶点数目*/

#define INFINITY 32768  /*表示最大值*/
#include <stdio.h>
#include <stdlib.h>

/*图的种类: DG表示有向图   DN表示有向网 UDG表示无向图   UDN表示无向网*/

typedef  enum {DG,DN,UDG,UDN} GraphKind;

typedef  int VertexData;//假设顶点数据为字符型

typedef  struct ArcNode//存储邻接结点的信息
{
	int adj;             //对于无权图,用1或0表示是否相邻;对带权图,则为表示权值类型
	int info;        //暂时不知道存储什么。
}ArcNode;
typedef struct 
{
	VertexData vertex[MAX_VERTEX_NUM];

	ArcNode   arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//邻接矩阵 
	int vexnum, arcnum;//图放入顶点数和弧数
	GraphKind  kind;//图的种类标志
}AdjMatrix;//邻接矩阵信息

int locateVertex(AdjMatrix *G, VertexData v)//找顶点函数
{
	int j = 0, k;
	for (k = 0; k < G->vexnum; k++)
	{
		if (G->vertex[k] == v)
		{
			j = k; break;
		}
	}
	return (j);
}

int main()
{
	AdjMatrix *G;
	G = (AdjMatrix *)malloc(sizeof(AdjMatrix));//定义对象
	int  i, j, k, weight;
	VertexData v1=0, v2=0;//两顶点。
	printf("请输入图的顶点数和弧数\n");
	scanf_s("%d,%d", &G->vexnum, &G->arcnum);
	getchar();
	for (i = 0; i < G->vexnum; i++)//初始化邻接矩阵
	{
		for (j = 0; j < G->vexnum; j++)
		{
			G->arcs[i][j].adj = 0;//权值最大
		}
	}
	printf("请输入顶点的数据\n");
	for (i = 0; i < G->vexnum; i++)
	{
		scanf_s("%d", &G->vertex[i]);
	}
	printf("请输入两个顶点和权值\n");
	for (k = 0; k < G->arcnum; k++)//两个顶点建立联系
	{
		scanf_s("%d,%d,%d", &v1, &v2, &weight);//读入数据
		i = locateVertex(G, v1);
		j = locateVertex(G, v2);
		G->arcs[i][j].adj = weight;//赋权值
	}//建弧完成
	printf("打印出带权图结构如下\n");
	for (i = 0; i < G->vexnum; i++)
	{
		for (j = 0; j < G->vexnum; j++)
		{
			printf("%d  ", G->arcs[i][j].adj);
		}
		printf("\n");
	}
	system("pause");
	return 0;
}

运行结果如下:
认真分析下结果出现的原因
从图中我们发现存了不少0,表示它们不是邻接关系,但是我们并不需要记住它们不相邻,所以这就大大浪费了内存。所以就有了邻接表法存储。

  • 邻接法
    优点:只存储关联的信息,对于图中存在的边信息,则存储,而不相邻的顶点则不保留信息。
    图奉上如下:
    在这里插入图片描述在这里插入图片描述
    后面的结点我只分了两份,实际还要给权值给开个空间存储信息。(我给省略了)。
    代码如下:
//邻接表存储结构的形式
#include <stdio.h>
#include<stdlib.h>

#define MAX_VERTEX_NUM 20
#define   VertexData  int 
#define max 100
#define size  4//存储数字的大小
#define bian  4//存储边的大小

int edge[1000][2] = { 0 };
typedef enum{DG,DN,UDG,UDN} GraphKind;//图的种类

typedef struct ArcNode
{
	int data;
	struct ArcNode *nextarc;  //指向下一条弧的指针
	//int weight;//权值  先不考虑
}ArcNode;
typedef struct VertexNode
{
	VertexData data;//顶点数据
	ArcNode *firstarc;//指向该顶点第一条弧的指针
}VertexNode;
typedef struct
{
	VertexNode vertex[MAX_VERTEX_NUM];//一维顶点数组
	int vexnum, arcnum;//顶点个数和弧数
}AdjList;//邻接目录

int find_insert(ArcNode *edge, ArcNode *temp)
{
	ArcNode *p;
	p = edge;
	while (p->nextarc != NULL)//循环找到一维顶点数组中的每一个顶点之后的邻接点
	{
		p = p->nextarc;
	}
	p->nextarc = temp;//插入找到的边
	return 0;
}

AdjList* CreGraph()//创建图
{
	int i,c1,c2;
	ArcNode *Arc;
	Arc = (ArcNode*)malloc(sizeof(ArcNode));
	AdjList *picture;
	picture = (AdjList*)malloc(sizeof(AdjList));

	picture->vexnum = size;
	picture->arcnum = bian;
	printf("请输入顶点\n");
	for (i = 1; i <= picture->vexnum; i++)
	{
		scanf_s("%d", &picture->vertex[i].data);
		picture->vertex[i].firstarc = NULL;//刚开始把一维数组建立起来
	}
	//再确定哪两个顶点连接需要存边0代表出度连接1代表入度
	

    for (int i = 1; i <= picture->arcnum; i++)//建立联系
	{
		c1 = edge[i][0];
		c2 = edge[i][1];
		Arc = (ArcNode*)malloc(sizeof(ArcNode));//新申请的结点
		Arc->data = edge[i][1];//获取顶点数
		Arc->nextarc = NULL;
   //从输入的弧中将入度相同的结点连接起来
		if (picture->vertex[c1].firstarc == NULL)
		{
			picture->vertex[c1].firstarc = Arc;
		}
		else
		{
			find_insert(picture->vertex[c1].firstarc, Arc);
		}
	
    }
   return picture;
}
int main()
{
	int i = 0;
	AdjList* picture;
	
	printf("请输入要连接的序号边\n");
	for (i = 1; i <= bian ; i++)
	{
		scanf("%d",&edge[i][0]);//代表号,不是放权值
		scanf("%d", &edge[i][1]);
	}
	picture = CreGraph();
	printf("邻接表如下\n");
    for (int i = 1; i <= picture->vexnum; i++)
	{
		ArcNode *p;
		p = (ArcNode*)malloc(sizeof(ArcNode));
		if (picture->vertex[i].firstarc == NULL)
		{
			printf("error");
		}
		else
		{
			p = picture->vertex[i].firstarc;
			printf("%d ", picture->vertex[i].data);
			while (p != NULL)
			{
				printf("%d ", p->data);
				p = p->nextarc;
			}
		}
		printf("\n");
	}
	system("pause");
	return 0;
}

代码有点长,但对于IT专业的我们来说,耐的住心慢慢理解,到最终get it,是非常重要的,加油!

猜你喜欢

转载自blog.csdn.net/qq_43079376/article/details/84191344