数据结构20————图的五种存储结构

数据结构20————图的存储结构

一. 目录

二. 邻接矩阵

1. 存储形式
  • 使用一维数组存储顶点信息,使用二维数组存储边信息。
  • 如果是图a[i][j]=1表示顶点i和顶点j直接存在边,a[i][j]=0表示顶点i和j不存在边。
  • 如果是网,则a[i][j=m(m为数字)表示顶点i和j之间存在一个权值为m的边,a[i][j]=无穷表示顶点i和j之间不存在边。
  • 无向图的邻接矩阵为对称矩阵

优点:简单易用
缺点:对于稀疏矩阵而言,太过浪费空间

2. 图例

无向图:
这里写图片描述
有向图
这里写图片描述

这里写图片描述

3. 数据结构的结构体设计
#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 30
typedef char Vertype;
typedef struct{
	int acre[MAXVEX][MAXVEX];//邻接表
	Vertype Vex[MAXVEX];//顶点信息
	int vexnum;//顶点数量
	int acrenum;//边的数量 
}AdjMatrix;
4. 实现有向图的存储,并统计出度和入度
AdjMatrix *Create(){
	AdjMatrix *adj;
	adj = (AdjMatrix*)malloc(sizeof(AdjMatrix));
	
	printf("请输入图的顶点数和边数:");
	scanf("%d%d",&adj->vexnum,&adj->acrenum);
	
	int i;
	printf("请输入点信息:\n");
	for(i = 0;i < adj->vexnum;i++){
		getchar();
		printf("请输入第%d个顶点:",i+1);
		scanf("%c",&adj->Vex[i]);
	} 

	
	int j,k;
	char a[3];
	for(i=0;i<adj->vexnum;i++) // 初始化 
		for(j=0;j<adj->vexnum;j++)
			adj->acre[i][j]=0;

	getchar();
	printf("\n请输入边信息:如ab\n");
	for(i=0;i<adj->acrenum;i++){
		printf("请输入第%d个边:",i+1);
		gets(a);
		
		j=0;
		k=0;	
		while(adj->Vex[j++] != a[0]&&j<adj->acrenum);
		while(adj->Vex[k++] != a[1]&&k<adj->acrenum);
		adj->acre[j-1][k-1]=1;
	}
	
	printf("\n你输入的邻接矩阵如下:\n");
	for(i=0;i<adj->vexnum;i++){
		for(j=0;j<adj->vexnum;j++){
			printf("%4d",adj->acre[i][j]);
		}
		printf("\n");
	}
	
	return adj;
} 

void Statistics(AdjMatrix *adj){
	int i,j;
	int countA,countB;
	for(i=0;i<adj->vexnum;i++){
		countA=0;
		countB=0;
		for(j=0;j<adj->acrenum;j++){  
			if(adj->acre[i][j]==1){//出度
				countA++;
			} 
			if(adj->acre[j][i]==1){//入度 
				countB++; 
			}
		} 
		printf("顶点%c,出度为%d,入度为%d\n",adj->Vex[i],countA,countB);
	} 
}

这里写图片描述

三. 邻接表

1. 存储形式
  • 图的顶点用一个以为数组存储,该顶点的所有邻接点构成一个线性表,组成单链表,连接在该顶点后。
  • 在无向图中,每个边会出现两次
  • 对于有向图,其后面可以跟它的邻接点(邻接表),也可以跟它的逆邻接点(逆邻接表).

优点:相对于邻接表而言,解决了稀疏矩阵太过浪费空间的问题
缺点:对于有向图而言,邻接表统计每个顶点的入度都要遍历整个图,,而逆邻接表统计每个顶点的出度都要遍历整个图,对于有向图而言,对于无向图而言,每个边出现两次,浪费了一半的空间,并且删除操作需要删除两次。

2. 图例

无向图
这里写图片描述
有向图
这里写图片描述

这里写图片描述

3. 数据结构的结构体设计
typedef char Vertype;
typedef struct ArcNode{
	int adhVex;//弧尾 
	struct ArcNode *next; 
}ArcNode;

typedef struct VertexNode{
	Vertype vexdata; //点 
	ArcNode *head; 
}VertexNode;

typedef struct{
	VertexNode vertex[MAXVEX];
	int vexnum; // 顶点数
	int arcnum; //边数 
}AdjList;

4. 实现有向图的存储,并统计出度和入
AdjList *Create(){
	AdjList *adj;
	
	adj = (AdjList *)malloc(sizeof(AdjList)); 
	printf("请输入有向图的顶点的数量和边的数量:");
	scanf("%d%d",&adj->vexnum,&adj->arcnum);
	int i;
	printf("请输入点信息:\n");
	for(i=0;i < adj->vexnum;i++){
		getchar();
		printf("请输入第%d个顶点:",i+1);
		scanf("%c",&adj->vertex[i].vexdata);
		adj->vertex[i].head = NULL;
	} 
	
	
	getchar();
	int j,k;
	char a[3];
	ArcNode *arc;
	ArcNode *p;
	printf("\n请输入边信息如ab:\n");
	for(i=0;i<adj->arcnum;i++){
		printf("请输入第%d个边:",i+1);
		gets(a);                                                                                                                                                                                                                                  
		for(j=0;adj->vertex[j].vexdata != a[0] &&j<adj->vexnum;j++);
		for(k=0;adj->vertex[k].vexdata != a[1] &&k<adj->vexnum;k++);
		
		arc = (ArcNode *)malloc(sizeof(ArcNode));
	 	
		arc->adhVex = k;
		arc->next = adj->vertex[j].head;
		adj->vertex[j].head = arc; 
	}
	
	printf("你输入的邻接表如下:\n");
	for(i=0;i<adj->vexnum;i++){
		printf("顶点:%c ",adj->vertex[i].vexdata);
		p = adj->vertex[i].head;
		
		while(p!=NULL){
			printf("-->%d",p->adhVex);
			p=p->next;	
		}
		printf("\n");
	} 
 	return adj;
}

void Statistics(AdjList *adj){
	int i,j;
	int countA,countB;
	ArcNode *p;
	for(i=0;i<adj->vexnum;i++){
		countA=0;
		countB=0;
		printf("顶点%c:",adj->vertex[i].vexdata);
		p=adj->vertex[i].head;	
		while(p!=NULL){
			countA++;
			p=p->next;
		}
		printf("出度:%d,",countA);
		
		for(j=0;j<adj->vexnum;j++){
			p=adj->vertex[j].head;
			while(p!=NULL){
				if(p->adhVex==i){
					countB++;
				}
				p=p->next;
			}
		}
		printf("入度:%d\n",countB);	
		
	}
}

这里写图片描述

四. 十字链表

1. 存储形式
  • 对于有向图而言,每个顶点相当于连接两个链表,一个连所有以它为入度的邻接点,一条连接所有以它为出度的邻接点。对于每个边而言,两个指针域,一个连接与他相同起点的下一个边,一个连接与他终点相同的下一个边。

优点:解决了有向图邻接表入度的问题。
缺点:结构有些复杂.

2.图例

这里写图片描述

3.数据结构的结构体设计
#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 30
typedef char Vertype;
//弧尾-->弧头  <尾,头> 
typedef struct ArcNode{
	int tailvex;//弧尾
	int headvex;//弧头 
	struct ArcNode *tailLink;//和它具有相同弧尾的边 
	struct ArcNode *headLink;//和它具有相同弧头的边
}ArcNode;

typedef struct VertexNode{
	Vertype vexdata; //点 
	ArcNode *firstout;//连接以它为弧尾的边 
	ArcNode *firstin;//连接以它为弧头的边 
}VertexNode;

typedef struct{
	VertexNode vertex[MAXVEX];
	int vexnum; // 顶点数
	int arcnum; //边数 
}AdjList;
4.实现有向图的存储,并统计出度和入
AdjList *Create(){
	AdjList *adj;
	adj = (AdjList *)malloc(sizeof(AdjList));
	printf("请输入有向图的顶点的数量和边的数量:");
	scanf("%d%d",&adj->vexnum,&adj->arcnum);
	
	int i=0;
	printf("请输入点信息:\n");
	for(i=0;i<adj->vexnum;i++){
		getchar();
		printf("请输入第%d个顶点:",i+1);
		scanf("%c",&adj->vertex[i].vexdata);
		adj->vertex[i].firstout=NULL;
		adj->vertex[i].firstin=NULL; 
	}
	
	getchar();
	int j,k;
	ArcNode *arc;
	char a[3];
	printf("\n请输入边信息如ab:\n");
	for(i=0;i<adj->arcnum;i++){
		
		printf("请输入第%d条边:",i+1);
		gets(a); 
		for(j=0;adj->vertex[j].vexdata!=a[0]&&j<adj->vexnum;j++);
		for(k=0;adj->vertex[k].vexdata!=a[1]&&k<adj->vexnum;k++);
		arc=(ArcNode *)malloc(sizeof(ArcNode));
		arc->tailvex=j;
		arc->headvex=k;
		
		arc->tailLink=adj->vertex[j].firstout;
		adj->vertex[j].firstout=arc;
		
		arc->headLink=adj->vertex[k].firstin;
		adj->vertex[k].firstin=arc;				 
	}
	
	printf("你输入的十字链表如下:\n");
	ArcNode *p;
	for(i=0;i<adj->vexnum;i++){
		printf("顶点:%c",adj->vertex[i].vexdata);
		p = adj->vertex[i].firstout;	
		while(p!=NULL){
			printf("-->%d",p->headvex);
			p=p->tailLink;	
		}
		printf("\n");	
		printf("顶点:%c",adj->vertex[i].vexdata);
		p = adj->vertex[i].firstin;
		while(p!=NULL){
			printf("<==%d",p->tailvex);
			p=p->headLink;	
		}
		printf("\n\n");
	} 	
	return adj;	
} 

Statistics(AdjList *adj){
	int i; 
	int countA,countB;
	ArcNode *p;
	for(i=0;i<adj->vexnum;i++){
		
		for(p=adj->vertex[i].firstout,countA=0;p!=NULL;p=p->tailLink,countA++);
		for(p=adj->vertex[i].firstin,countB=0;p!=NULL;p=p->headLink,countB++);
		printf("点%c的出度为:%d,入度为:%d\n",adj->vertex[i].vexdata,countA,countB);
	}	
}

这里写图片描述

五.邻接多重表

1.存储形式
  • 无向图的每个边只会出现一次。每个边两个指针域,一个指向顶点i的下一个边,一个指向顶点j的下一个边.

优点:解决了无向图邻接表中,一条边出现两次的问题。
缺点:结构有些复杂.

2. 图例

这里写图片描述

3. 数据结构的结构体设计
#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 30
typedef char Vertype;
typedef struct ArcNode{
	int ivex;//边的i顶点 
	int jvex;//边的j顶点 
	struct ArcNode *ilink;//指向同样具有i顶点的边 
	struct ArcNode *jlink;//指向同样具有j顶点的边
}ArcNode;

typedef struct VertexNode{
	Vertype vexdata; //点 
	ArcNode *firstdge;//连接以它为弧尾的边 
}VertexNode;

typedef struct{
	VertexNode vertex[MAXVEX];
	int vexnum; // 顶点数
	int arcnum; //边数 
}AdjList;
4. 实现无向图的存储,并统计出度和入
AdjList *Create(){
	AdjList *adj;
	adj = (AdjList *)malloc(sizeof(AdjList));
	printf("请输入有向图的顶点的数量和边的数量:");
	scanf("%d%d",&adj->vexnum,&adj->arcnum);
	
	int i=0;
	printf("请输入点信息:\n");
	for(i=0;i<adj->vexnum;i++){
		getchar();
		printf("请输入第%d个顶点:",i+1);
		scanf("%c",&adj->vertex[i].vexdata);
		adj->vertex[i].firstdge=NULL;
	}
	
		getchar();
	int j,k;
	ArcNode *arc;
	char a[3];
	printf("\n请输入边信息如ab:\n");
	for(i=0;i<adj->arcnum;i++){
		
		printf("请输入第%d条边:",i+1);
		gets(a); 
		for(j=0;adj->vertex[j].vexdata!=a[0]&&j<adj->vexnum;j++);
		for(k=0;adj->vertex[k].vexdata!=a[1]&&k<adj->vexnum;k++);
		arc=(ArcNode *)malloc(sizeof(ArcNode));
		arc->ivex=j;
		arc->jvex=k;
		
		arc->ilink=adj->vertex[j].firstdge;
		adj->vertex[j].firstdge=arc;
		
		arc->jlink=adj->vertex[k].firstdge;
		adj->vertex[k].firstdge=arc;				 
	}
	
	printf("你输入的邻接多重表如下:\n");
	ArcNode *p;
	for(i=0;i<adj->vexnum;i++){
		printf("顶点:%c",adj->vertex[i].vexdata);
		p = adj->vertex[i].firstdge;	
		while(p!=NULL){
			if(p->ivex==i){
				printf("-->%d",p->jvex);
				p=p->ilink;
			}else{
				printf("-->%d",p->ivex);
				p=p->jlink;
			}
				
		}
		printf("\n");	
	} 	
	return adj;	
} 
void Statistics(AdjList *adj){
	int i; 
	int count;
	ArcNode *p;
	for(i=0;i<adj->vexnum;i++){
		
		for(p=adj->vertex[i].firstdge,count=0;p!=NULL;count++){
			if(p->ivex==i){
				p=p->ilink;
			}else{
				p=p->jlink;
			}
		}
		printf("点%c的度为:%d\n",adj->vertex[i].vexdata,count);
	}
} 

这里写图片描述

六. 边集数组

1. 存储形式
  • 由两个一维数组组成
  • 一个一维数组存储点
  • 一个一维数组存储边(起点,终点,权值).
2. 图例

这里写图片描述

3. 数据结构的结构体设计
#include<stdlib.h>
#define MAXVEX 30
typedef char Vertype;
typedef struct ArcNode{
	int ivex;//边的i顶点 
	int jvex;//边的j顶点 
	struct ArcNode *ilink;//指向同样具有i顶点的边 
	struct ArcNode *jlink;//指向同样具有j顶点的边
}ArcNode;

typedef struct VertexNode{
	Vertype vexdata; //点 
	ArcNode *firstdge;//连接以它为弧尾的边 
}VertexNode;

typedef struct{
	VertexNode vertex[MAXVEX];
	int vexnum; // 顶点数
	int arcnum; //边数 
}AdjList;

4. 实现有向图的存储,并统计出度和入
AdjList *Create(){
	AdjList *adj;
	adj = (AdjList *)malloc(sizeof(AdjList));
	printf("请输入有向图的顶点的数量和边的数量:");
	scanf("%d%d",&adj->vexnum,&adj->arcnum);
	
	int i=0;
	printf("请输入点信息:\n");
	for(i=0;i<adj->vexnum;i++){
		getchar();
		printf("请输入第%d个顶点:",i+1);
		scanf("%c",&adj->vertex[i].vexdata);
		adj->vertex[i].firstdge=NULL;
	}
	
		getchar();
	int j,k;
	ArcNode *arc;
	char a[3];
	printf("\n请输入边信息如ab:\n");
	for(i=0;i<adj->arcnum;i++){
		
		printf("请输入第%d条边:",i+1);
		gets(a); 
		for(j=0;adj->vertex[j].vexdata!=a[0]&&j<adj->vexnum;j++);
		for(k=0;adj->vertex[k].vexdata!=a[1]&&k<adj->vexnum;k++);
		arc=(ArcNode *)malloc(sizeof(ArcNode));
		arc->ivex=j;
		arc->jvex=k;
		
		arc->ilink=adj->vertex[j].firstdge;
		adj->vertex[j].firstdge=arc;
		
		arc->jlink=adj->vertex[k].firstdge;
		adj->vertex[k].firstdge=arc;				 
	}
	
	printf("你输入的邻接多重表如下:\n");
	ArcNode *p;
	for(i=0;i<adj->vexnum;i++){
		printf("顶点:%c",adj->vertex[i].vexdata);
		p = adj->vertex[i].firstdge;	
		while(p!=NULL){
			if(p->ivex==i){
				printf("-->%d",p->jvex);
				p=p->ilink;
			}else{
				printf("-->%d",p->ivex);
				p=p->jlink;
			}
				
		}
		printf("\n");	
	} 	
	return adj;	
} 
void Statistics(AdjList *adj){
	int i; 
	int count;
	ArcNode *p;
	for(i=0;i<adj->vexnum;i++){
		
		for(p=adj->vertex[i].firstdge,count=0;p!=NULL;count++){
			if(p->ivex==i){
				p=p->ilink;
			}else{
				p=p->jlink;
			}
		}
		printf("点%c的度为:%d\n",adj->vertex[i].vexdata,count);
	}
} 

这里写图片描述

七. 源码地址

text16中

八. 参考资料

《大话数据结构》
《数据结构与算法》

  • 7
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值