13.图——邻接表表示法

本文介绍了图的邻接表表示法,这是一种链式存储图的方式。每个顶点对应一个链表,链表中的节点表示与该顶点相关的边。在给出的程序中,虽然没有包含边的附加信息,但详细阐述了邻接表如何组织和表示图的结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文针对图的邻接表存储。

邻接表示图的链式存储方式。有几个顶点就有几个链表,每个链表的后边的节点表示与顶点有关的边。如下图:

左边都是顶点,右边都是边。

在本文程序里没有包含边的附件信息。


程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>


typedef int status;
#define MAX_NAME 5  //顶点字符串的最大长度 + 1
typedef char VertexType[MAX_NAME];
#define MAX_VERTEX_NUM 20
typedef enum {DG,DN,UDG,AN} GraphKind;  //{有向图,有向网,无向图,无向网}
int visited[MAX_VERTEX_NUM];
void(*VisitFunc)(char* v); /* 函数变量(全局量) */

typedef struct ArcNode  //没有相关信息
{
	int adjvex;  //所指向的顶点的下标
	int *info;  //网权值
	struct ArcNode *nextarc;
}ArcNode;  //边结点

typedef struct
{
	VertexType data;
	ArcNode *firstarc;
}VNode,AdjList[MAX_VERTEX_NUM];  //头结点

typedef struct
{
	AdjList vertexs;
	int vexnum,arcnum;  //图当前顶点数和弧数
	int kind;
}Graph;  //图


//返回顶点在图中位置
int locate_vertex(Graph *G,VertexType u)
{
	int i;
	for(i = 0;i < G->vexnum;++i)
		if(strcmp(u,G->vertexs[i].data) == 0)
			return i;
	return -1;
}

//创建图
status CreateGraph(Graph *G)
{
	int i,j,k;
	int w;
	VertexType va,vb;
	ArcNode *p;
	
	printf("please input the type of graph(directed graph:0  directed net:1  undirected graph:2  undirected net:3): ");
	scanf("%d",&G->kind);
	printf("please input the vertex number, edge number: ");
	scanf("%d %d",&G->vexnum,&G->arcnum);
	printf("please input %d string of vertex value(<%d chars of each string):\n",G->vexnum,MAX_NAME);
	for(i = 0;i < G->vexnum;++i){
		scanf("%s",G->vertexs[i].data);
		G->vertexs[i].firstarc = NULL;
	}
	if(G->kind == 1 || G->kind == 3)  //网
		printf("please input tail head power of %d edges in order:\n",G->arcnum);
	else  //图
		printf("please input tail head of %d edges in order:\n",G->arcnum);
	for(k = 0;k < G->arcnum;++k){
		if(G->kind == 1 || G->kind == 3)  //网
			scanf("%s %s %d",va,vb,&w);
		else  //图
			scanf("%s %s",va,vb);
		i = locate_vertex(G,va);
		j = locate_vertex(G,vb);
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = j;
		if(G->kind == 1 || G->kind == 3){
			p->info = (int*)malloc(sizeof(int));
			*(p->info) = w;
		}
		else
			p->info = NULL;
		p->nextarc = G->vertexs[i].firstarc;  //往表头插
		G->vertexs[i].firstarc = p;
		
		if(G->kind >= 2){  //无向图或网 (vb,va)
			p = (ArcNode*)malloc(sizeof(ArcNode));
			p->adjvex = i;
			if(G->kind == 3){  //无向网
				p->info = (int*)malloc(sizeof(int));
				*(p->info) = w;
			}
			else
				p->info = NULL;  //无向图
			p->nextarc = G->vertexs[j].firstarc; /* 插在表头 */
			G->vertexs[j].firstarc = p;
		}
	}
	return 1;
}

//销毁图
void DestroyGraph(Graph *G)
{
	int i;
	ArcNode *p,*q;
	
	G->vexnum = 0;
	G->arcnum = 0;
	for(i = 0;i < G->vexnum;++i){
		p = G->vertexs[i].firstarc;
		while(p){
			q = p->nextarc;
			if(G->kind % 2)  //网要释放权值
				free(p->info);
			free(p);
			p = q;
		}
	}
}

//返回顶点下标v的值
VertexType* GetVex(Graph *G,int v)
{
	if(v < 0 || v >= G->vexnum)
		exit(0);
	return G->vertexs[v].data;
}

//返回顶点值为v的第一个邻接顶点的下标
int first_adjver(Graph *G,VertexType v)
{
	ArcNode *p;
	int v1;
	
	v1 = locate_vertex(G,v);
	p = G->vertexs[v1].firstarc;
	if(p)
		return p->adjvex;
	else
		return -1;
}

//返回顶点值为v的(w之后的)下一个邻接顶点的下标
int NextAdjVex(Graph *G,VertexType v,VertexType w)
{
	ArcNode *p;
	int v1,w1;
	
	v1 = locate_vertex(G,v);
	w1 = locate_vertex(G,w);
	p = G->vertexs[v1].firstarc;
	while(p && p->adjvex != w1)
		p = p->nextarc;
	if(!p || !p->nextarc)
		return -1;
	else
		return p->nextarc->adjvex;
}

//添加新顶点值为v
void InsertVex(Graph *G,VertexType v)
{
	strcpy(G->vertexs[G->vexnum].data,v);
	G->vertexs[G->vexnum].firstarc = NULL;
	G->vexnum++;
}

//删除G中顶点值为v及其相关的弧
status delete_vertex(Graph *G,VertexType v)
{
	int i,j;
	ArcNode *p,*q;
	
	j = locate_vertex(G,v);
	if(j < 0)
		return 0;
	p = G->vertexs[j].firstarc;
	while(p){  //从前往后删除以顶点值v为出度的弧
		q = p;
		p = p->nextarc;
		if(G->kind % 2)  //网
			free(q->info);
		free(q);
		G->arcnum--;
	}
	G->vexnum--;
	
	for(i = j;i < G->vexnum;i++)  //顶点数组之后的向前移
		G->vertexs[i] = G->vertexs[i + 1];
	for(i = 0;i < G->vexnum;i++){  //删除以顶点值v为入度的弧
		p = G->vertexs[i].firstarc;  //指向第1条弧或边
		while(p){
			if(p->adjvex == j){
				if(p == G->vertexs[i].firstarc)  //待删结点是第1个结点
				{
					G->vertexs[i].firstarc = p->nextarc;
					if(G->kind % 2)  //网
						free(p->info);
					free(p);
					p = G->vertexs[i].firstarc;
					if(G->kind < 2)  //有向,无向的只减一次
						G->arcnum--;
				}
				else{
					q->nextarc = p->nextarc;
					if(G->kind % 2)  //网
						free(p->info);
					free(p);
					p = q->nextarc;
					if(G->kind < 2)  //有向,无向的只减一次
						G->arcnum--;
				}
			}
			else{
				if(p->adjvex>j)
					p->adjvex--;
				q = p;
				p = p->nextarc;
			}
		}
	}
	return 1;
}

//添加弧<v,w>或(v,w)
status insert_arc(Graph *G,VertexType v,VertexType w)
{
	ArcNode *p;
	int w1,i,j;
	
	i = locate_vertex(G,v);
	j = locate_vertex(G,w);
	if(i < 0 || j < 0)
		return 0;
	G->arcnum++;
	p = (ArcNode*)malloc(sizeof(ArcNode));
	if(G->kind % 2){  //网
		printf("please input the power of the edge: ");
		scanf("%d",&w1);
		p->info = (int*)malloc(sizeof(int));
		*(p->info) = w1;
	}
	else
		p->info=NULL;
	p->adjvex = j;
	p->nextarc = G->vertexs[i].firstarc;  //插在表头
	G->vertexs[i].firstarc = p;
	if(G->kind >= 2){  //无向图、网
		p = (ArcNode*)malloc(sizeof(ArcNode));
		if(G->kind == 3){
			p->info = (int*)malloc(sizeof(int));
			*(p->info) = w1;
		}
		else
			p->info = NULL;
		p->adjvex = i;
		p->nextarc = G->vertexs[j].firstarc;
		G->vertexs[j].firstarc = p;
	}
	return 1;
}

//删除弧<v,w>或(v,w)
status DeleteArc(Graph *G,VertexType v,VertexType w)
{
	ArcNode *p,*q;
	int i,j;
	
	i = locate_vertex(G,v);
	j = locate_vertex(G,w);
	if(i < 0 || j < 0 || i == j)
		return 0;
	
	p = G->vertexs[i].firstarc;
	while(p && p->adjvex != j){
		q = p;  //记录前一个边
		p = p->nextarc;
	}
	if(p && p->adjvex == j){  //没有这个边就不做处理
		if(p == G->vertexs[i].firstarc)
			G->vertexs[i].firstarc = p->nextarc;
		else
			q->nextarc = p->nextarc;
		if(G->kind % 2)  //网
			free(p->info);
		free(p);
		G->arcnum--;
	}
	if(G->kind >= 2){
		p = G->vertexs[j].firstarc;
		while(p && p->adjvex != i){
			q = p;
			p = p->nextarc;
		}
		if(p && p->adjvex == i){
			if(p == G->vertexs[j].firstarc)
				G->vertexs[j].firstarc = p->nextarc;
			else
				q->nextarc = p->nextarc;
			if((*G).kind==3)
				free(p->info);
			free(p);
		}
	}
	return 1;
}

//第v个顶点出发递归地深度优先遍历图G。算法7.5 */
void DFS(Graph *G,int v)
{
	int w;
	VertexType v1,w1;
	
	strcpy(v1,*GetVex(G,v));
	visited[v] = 1;
	printf("%s",G->vertexs[v].data);
	for(w = first_adjver(G,v1);w >= 0;w = NextAdjVex(G,v1,w1)){
		if(!visited[w])
			DFS(G,w);
		strcpy(w1,*GetVex(G,w));
	}
}

//深度优先遍历
void DFSTraverse(Graph *G,void(*Visit)(char*))
{
	int v;
	
	VisitFunc = Visit;
	for(v = 0;v < G->vexnum;v++)
		visited[v] = 0;
	for(v = 0;v < G->vexnum;v++)
		if(!visited[v])
			DFS(G,v);
	printf("\n");
}

//输出顶点值与邻接矩阵
void Display(Graph *G)
{
	int i;
	ArcNode *p;
	char s[20];
	
	switch(G->kind){  
        case DG: strcpy(s,"directed graph\0");break;  
        case DN: strcpy(s,"directed net\0");break;  
        case UDG: strcpy(s,"undirected graph\0");break;  
        case AN: strcpy(s,"undirected net\0");  
    }
    printf("the %s has %d vertex and %d edge\n",s,G->vexnum,G->arcnum);  
    for(i = 0;i < G->vexnum;++i)  
        printf("%s\n",G->vertexs[i].data);  
    	
	for(i = 0;i < G->vexnum;i++){
		p = G->vertexs[i].firstarc;
		while(p){
			if(G->kind <= 1){
				printf("%s-->%s",G->vertexs[i].data,G->vertexs[p->adjvex].data);
				if(G->kind == DN)
					printf("\t power is %d",*(p->info));
			}
			else{
				if(i < p->adjvex){
					printf("%s--%s",G->vertexs[i].data,G->vertexs[p->adjvex].data);
					if(G->kind == AN)
						printf("\t power is %d",*(p->info));
				}
			}
			p = p->nextarc;
			printf("\t");
		}
		printf("\n");
	}
}


void main()
{
	int i,j,k,n;
	Graph g;
	VertexType v1,v2;
	
	for(i = 0;i < 4;i++){
		CreateGraph(&g);
		Display(&g);
		
		printf("please input the new vertex value to insert: ");
		scanf("%s",v1);
		InsertVex(&g,v1);
		Display(&g);
			
		printf("insert the edge of the new vertex, so please input the number of the edge: ");
		scanf("%d",&n);
		for(k = 0;k < n;k++){
			printf("please input the next vertext value: ");
			scanf("%s",v2);
			if(g.kind <= 1){
				printf("please input the vertex %s 's type(head:0 tail:1): ",v1);
				scanf("%d",&j);
				if(j)
					insert_arc(&g,v1,v2);
				else
					insert_arc(&g,v2,v1);
			}
			else
				insert_arc(&g,v1,v2);
		}
		Display(&g);
		
		printf("please input the vertex value to delete: ");
		scanf("%s",v1);
		delete_vertex(&g,v1);
		Display(&g);
		
		printf("please input the tail head of the edge to delete: ");
		scanf("%s %s",v1,v2);
		DeleteArc(&g,v1,v2);		
		Display(&g);
		
		DestroyGraph(&g);
		Display(&g);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值