C语言-图的存储结构(邻接表)

  1. 查找函数(LocateVex查找坐标)
  2. 构建有向图(Directed Graph)
  3. 构建无向图(Undirected Graph)
  4. 图的类型选择函数(GraphChoice)
  5. 输出邻接矩阵(print)

邻接表结构解析:

在这里插入图片描述

  1. 邻接表由 顶点表边表 组成,顶点表是结构体数组边表是一环一环的链节
  2. 顶点表是结构体数组,其中的每个元素有两个域:数据域(用于存放顶点元素如V1、V2、V3或A、B、C之类的)。指针域,用于连接边表。
  3. 边表是结构体,其中每个结点也有两个域:下标域,存储的是对应元素在顶点表中的下标。指针域,用于连接后续结点
  • 如何定义边表、单个顶点、顶点表?
    注:此代码为有向图/无向图,若需存储有向网与无向网,需要在顶点结构体中加入权值w
typedef struct ArcNode//边表 
{
	int adjvex;//存储的是该顶点在顶点数组即AdjList[]中的位置 
	struct ArcNode *next;
}ArcNode;

typedef struct VNode //单个顶点 
{
	VertexType vertex;
	//int weight;//存储网的时候需要添加此项
	struct ArcNode *firstarc;
}VNode;

typedef struct //顶点表 
{
	VNode AdjList[VertexMax];//由顶点构成的结构体数组 
	int vexnum,arcnum; //顶点数n和边数e 
	int kind; //记录图的类型 
}ALGraph;
  1. 邻接表用顶点表和边表所表示的含义是:从当前顶点(V1)出发对应有那些其他顶点(V4)与当前顶点有边,就记录在边表中,记录的内容是顶点的下标(记录V4的坐标3),若后续还有顶点(V2)与当前顶点有边,则连接到下去(V2链接到V4后面)

构建邻接表的基本步骤:

  1. 输入顶点数n,和边数e
  2. 顶点表数据域填值(将顶点写入顶点表数据域),并初始化顶点表指针域
  3. 输入边的信息,构造邻接表
    3.1 输入边信息,查找两顶点下标
    3.2 根据输入的边的信息用头插法插入结点(尾插法也行)

邻接表的空间复杂度及局限性:

  • 邻接表的空间复杂度为O(n+e),其中n是顶点数,e是边数。
  • 邻接表空间利用率低,适用于存储稀疏图

邻接表、逆邻接表、十字链表

  • 对于有向图而言,邻接表是将当前顶点走向其他顶点的路径信息存储在边表当中,既将出度信息存储于边表,所以求出度十分容易,出度就是边表中的链节个数,但是邻接表却难求出度。逆邻接表将入度信息存储于边表,所以容易求入度,但逆邻接表却难求出度。所以在我们如果需要频繁的求出度与入度的时候,就会引用——十字链表。十字链表是将邻接表与逆邻接表合二为一,易求出度也易求入度。总结如下:
  • 邻接表:易求出度,不易求入度
  • 逆邻接表:易求入度,不易求出度
  • 十字链表:合二为一,易求出度也易求入度

完整源代码

#include <stdio.h>
#include <stdlib.h>
#define VertexType char //顶点的数据类型(char) 
#define VertexMax 20 //最大顶点个数 

typedef struct ArcNode//边表 
{
	int adjvex;//存储的是该顶点在顶点数组即AdjList[]中的位置 
	struct ArcNode *next;
}ArcNode;

typedef struct VNode //单个顶点 
{
	VertexType vertex;
	struct ArcNode *firstarc;
}VNode;

typedef struct //顶点表 
{
	VNode AdjList[VertexMax];//由顶点构成的结构体数组 
	int vexnum,arcnum; //顶点数和边数 
	int kind; //记录图的类型 
}ALGraph;

int LocateVex(ALGraph *G,VertexType v)
{    
    int i;
	for(i=0;i<G->vexnum;i++)
	{
		if(v==G->AdjList[i].vertex)
		{
			return i;
		}
	}
	
	printf("No Such Vertex!\n");
	return -1;
}

//1.有向图 
void CreateDG(ALGraph *G)
{
	int i,j;
	//1.输入顶点数和边数 
	printf("输入顶点个数和边数:\n");
	printf("顶点数 n="); 
	scanf("%d",&G->vexnum);
	printf("边  数 e="); 
	scanf("%d",&G->arcnum);
	printf("\n"); 
	
	printf("\n");
	//2.顶点表数据域填值初始化顶点表指针域 
	printf("输入顶点元素(用空格隔开):");
	for(i=0;i<G->vexnum;i++)
	{
		scanf(" %c",&G->AdjList[i].vertex);
		G->AdjList[i].firstarc=NULL;
	} 
	printf("\n");
	
	//3.输入边信息构造邻接表 
	int n,m;
	VertexType v1,v2;
	ArcNode *p1,*p2; 
	
	printf("请输入边的信息:\n\n"); 
	for(i=0;i<G->arcnum;i++)
	{   //输入边信息,并确定v1和v2在G中的位置,即顶点在AdjList[]数组中的位置(下标)  
		printf("输入第%d条边信息:",i+1); 
		scanf(" %c%c",&v1,&v2);
		n=LocateVex(G,v1);
		m=LocateVex(G,v2);
		
		if(n==-1||m==-1)
		 {
		 	printf("NO This Vertex!\n");
		 	return;
		 } 
		
		p1=(ArcNode *)malloc(sizeof(ArcNode));
		p1->adjvex=m;//填上坐标 
		p1->next=G->AdjList[n].firstarc;//改链(头插法)  
		G->AdjList[n].firstarc=p1;
	
	}//for  
	G->kind=1;
} 

//2.无向图 
void CreateUDG(ALGraph *G)
{
	int i,j;
	//1.输入顶点数和边数
	printf("输入顶点个数和边数:\n");
	printf("顶点数 n="); 
	scanf("%d",&G->vexnum);
	printf("边  数 e="); 
	scanf("%d",&G->arcnum);
	printf("\n"); 
	
	printf("\n");
	//2.顶点表数据域填值初始化顶点表指针域
	printf("输入顶点元素(无需空格隔开):");
	for(i=0;i<G->vexnum;i++)
	{
		scanf(" %c",&G->AdjList[i].vertex);
		G->AdjList[i].firstarc=NULL;
	} 
	printf("\n");
	
	//3.输入边信息构造邻接表
	int n,m;
	VertexType v1,v2;
	ArcNode *p1,*p2; 
	
	printf("请输入边的信息:\n\n"); 
	for(i=0;i<G->arcnum;i++)
	{   //输入边信息,并确定v1和v2在G中的位置,即顶点在AdjList[]数组中的位置(下标) 
		printf("输入第%d条边信息:",i+1); 
		scanf(" %c%c",&v1,&v2);
		n=LocateVex(G,v1);
		m=LocateVex(G,v2);
		
		if(n==-1||m==-1)
		 {
		 	printf("NO This Vertex!\n");
		 	return;
		  } 
		
		p1=(ArcNode *)malloc(sizeof(ArcNode));
		p1->adjvex=m;//填上坐标 
		p1->next=G->AdjList[n].firstarc;//改链(头插法) 
		G->AdjList[n].firstarc=p1;
		
		p2=(ArcNode *)malloc(sizeof(ArcNode));//无向图的对称 
		p2->adjvex=n;
		p2->next=G->AdjList[m].firstarc;
		G->AdjList[m].firstarc=p2;
		
	}//for 
	G->kind=2; 
} 

void print(ALGraph G)
{
	int i;
	ArcNode *p;
	printf("\n-------------------------------");
	printf("\n图的邻接表表示:\n");
	
	for(i=0;i<G.vexnum;i++)
	{
		printf("\n   AdjList[%d]%4c",i,G.AdjList[i].vertex);
		p=G.AdjList[i].firstarc;
		
		while(p!=NULL)
		{
			printf("-->%d",p->adjvex);
			p=p->next;
		}
	 } 
	 printf("\n");
} 

void GraphChoice(ALGraph *G)
{
	int target;
    printf(" 请选择图的类型:1.有向图DG  2.无向图UDG\n\n");
    scanf("%d",&target);//选择图的类型 
    printf("\n");

    switch (target) //根据所选类型,调用不同的函数实现构造图的功能 
	{
        case 1:
        	 printf("您选择的是 1.DG\n\n"); 
        	 printf("-------------------------------\n");
             CreateDG(G);
            break;
        case 2:
        	 printf("您选择的是 2.UDG\n\n"); 
        	 printf("-------------------------------\n");
             CreateUDG(G);
            break;
        default:
        	printf("无效选择!!!请重新选择!\n\n"); 
        	printf("-------------------------------\n");
			GraphChoice(G);   
            break;
    }
}

int main() 
{
	ALGraph G;
	GraphChoice(&G);
	print(G);
	
	return 0;
}

执行结果:

1.DG

在这里插入图片描述

2.UDG

在这里插入图片描述

  • 24
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
C语言中,可以使用结构体和指针来实现存储结构邻接表邻接表的一种常用存储结构,由表头结点和表结点两部分组成。表头结点存储的各个顶点,而表结点则用单向链表存储每个顶点的相邻顶点,从而表示的边。 下面是一个C语言实现邻接表的示例代码: ```c // 定义邻接表的结点结构 struct Node { int data; // 存储相邻顶点的数据 struct Node* next; // 指向下一个结点的指针 }; // 定义邻接表的表头结点结构 struct Head { int vertex; // 存储顶点的信息 int flag; // 判断该顶点是否被访问过的标志 struct Node* head_ele; // 指向链表的指针,存储相邻顶点的信息 }; // 定义的结构体 struct Map { int vex; // 存储的顶点数 int edge; // 存储的边数 int tag; // 存储的其他信息 struct Head* head; // 指向表头结点数组的指针 }; // 初始化邻接表 struct Map* initMap(int vex, int edge, int tag) { struct Map* map = (struct Map*)malloc(sizeof(struct Map)); map->vex = vex; map->edge = edge; map->tag = tag; map->head = (struct Head*)malloc(vex * sizeof(struct Head)); for (int i = 0; i < vex; i++) { map->head[i].vertex = i; // 初始化表头结点的顶点信息 map->head[i].flag = 0; // 初始化访问标志 map->head[i].head_ele = NULL; // 初始化链表为空 } return map; } // 添加边到邻接表 void addEdge(struct Map* map, int start, int end) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); newNode->data = end; newNode->next = map->head[start].head_ele; map->head[start].head_ele = newNode; } // 打印邻接表 void printMap(struct Map* map) { for (int i = 0; i < map->vex; i++) { printf("顶点 %d 的相邻顶点:", map->head[i].vertex); struct Node* node = map->head[i].head_ele; while (node != NULL) { printf("%d ", node->data); node = node->next; } printf("\n"); } } // 主函数示例 int main() { struct Map* map = initMap(5, 7, 0); // 创建一个包含5个顶点和7条边的 addEdge(map, 0, 1); // 添加边 0->1 addEdge(map, 0, 2); // 添加边 0->2 addEdge(map, 1, 3); // 添加边 1->3 addEdge(map, 1, 4); // 添加边 1->4 addEdge(map, 2, 3); // 添加边 2->3 addEdge(map, 2, 4); // 添加边 2->4 addEdge(map, 3, 4); // 添加边 3->4 printMap(map); // 打印邻接表 return 0; } ``` 上述代码中,使用了两个结构体`Node`和`Head`来分别表示邻接表的结点和表头结点。通过调用`initMap`函数可以初始化一个,并通过`addEdge`函数来添加边到邻接表中。最后,使用`printMap`函数可以打印出邻接表的内容。这样就实现了C语言邻接表存储结构
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Attract1206

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

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

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

打赏作者

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

抵扣说明:

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

余额充值