图的学习1

    在我的认识中学习一种新的数据结构要面临三个问题:1,这种数据结构的定义是什么。2,这种数据结构该如何储存。3,依靠这种数据结构可以处理什么问题。我将按照这三个步骤来阐明我是如何学习图的。

    图的定义:图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,图通常表示为G(V,E),其中,G 表示一个图,V 是图 G 中顶点的集合,E 是图 G 中边的集合。

无向图:若i与j两顶点之间的连接边是没有方向的就称该边为无向边,若图中所有边都是无向边则该图为无向图。

有向图:若i与j两顶点之间的连接边是有方向的就称该边为有向边,若图中所有边都是有向边则该图为有向图。

权的定义:有些图的边或弧具有与它相关的数字,这种与图的边或弧相关的数叫做权。

度的定义:无向图顶点的边数叫度,有向图顶点的边数叫出度和入度。

附上一张简单的图的图片:

    图的储存:说到图的储存问题,这是个困扰了我好几天的问题(本人是个蒟蒻),图的储存一般有两种方法:1,邻接矩阵,2,邻接表。接下来我将介绍这两种储存方法。

邻接矩阵:多数的讲解说邻接矩阵由两个数组组成,但是为了方便使用一般直接定义二维数组来储存,邻接矩阵其实很好理解,我们定义一个二维数组G[max][max],G[i][j]就表示i与j的连接状态,一般定为为0则没有连接边为1则有连接边,你也可以用G[i][j]来储存i与j连接边的权值,总而言之是用来储存一条边的信息。附上邻接矩阵储存与遍历的代码:

#include<stdio.h>
int G[101][101],n,m;//定义所需要的变量,n,m分别代表顶点的总数与边的总数
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int a,b;//辅助输入
		scanf("%d%d",&a,&b);
		G[a][b]=1;//表示a,b间有路
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			printf("%d ",G[i][j]);
		}
		printf("\n");
	}//遍历打印邻接矩阵
	return 0;
}

虽然邻接矩阵的实现十分简单方便但是我们不难发现它的弊端,邻接矩阵对空间的占用是巨大的,在解决问题时经常会爆空间(说多了都是泪),这时候我们就得使用另一种存储方式了,它就是邻接表。

邻接表:邻接表说白了就是储存图的链式结构,想必没有几个人在刷题时使用链表吧,所以我将介绍一种用数组模拟邻接表的数据结构:链式前向星。

首先先介绍一下我们所需要定义的变量:

struct data{
	int to,next,w;
};
struct data edge[100000];
int head[10000],n,m,cnt;

我们先定义一个结构体data,其中的成员分别是to,next,w(用来储存权值可以不添加)。head[max]用于记录某点的第一条连接边,cnt作为下标无实际作用,n,m点与边的总数量。

接下来看看添加边的函数:

void add(int x,int y,int z){
	edge[++cnt].to=y;
	edge[cnt].w=z;
	edge[cnt].next=head[x];
	head[x]=cnt;
}

其实就是对链表的模拟,edge[++cnt].to用来表明cnt号边的终点(或者说连接的下一个点),edge[cnt].w=z;表示cnt号边的权值,edge[cnt].next表示cnt的下一条边的编号,如此这般便能将一条边的信息存入这几个数组,附上完整的储存与遍历代码:

#include<stdio.h>
struct data{
	int to,next,w;
};
struct data edge[100000];
int check[10000],head[10000],cnt,dis[10000],n,m,s,inf=99999999;
void add(int x,int y,int z){
	edge[++cnt].to=y;
	edge[cnt].w=z;
	edge[cnt].next=head[x];
	head[x]=cnt;
}
int main(){
scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);
	}
for(int i = 1; i <= n; i++)
    {
        printf("%d\n",i);
        for(int j = head[i]; j != 0; j = edge[j].next)
        {
            printf("%d %d %d\n",i,edge[j].to,edge[j].w);
        }
        printf("\n");
    }



return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值