图的创建方法详解之邻接矩阵法(C语言)

为了方便读者的阅读,我们先介绍图中一些常用的术语:
1.图按照有无方向分为有向图无向图,无向图有边和顶点构成,有向图由顶点和弧构成,弧有弧尾和弧头构成。
2.图按照边或弧的多少分为稀疏图稠密图。如果任意两个顶点之间都存在边,叫完全图;有向的叫有向完全图。若无重复的边或顶点到自身的边则叫简单图
3.图中的边或弧上的带权则称为
4.无向图中连通且n个顶点n -1条边叫生成树。有向图中一顶点的入度为0其余顶点入度为1的叫有向树。一个又向图由若干颗有向树构成生成森林
在考试的时候有的同学可能遇到这样的问题,请使用邻接矩阵法建立一个图。相信大家的思路很多,那么下来小编介绍一种自己建立图的方法:先输入顶点数和边数,然后建立有顶点没有边的图,之后将邻接矩阵进行初始化,最后读入所有的边,这样就完成了图的建立。代码如下:

typedef struct
{
	VertexType vexs[MAXVEX]; /* 顶点表 */
	EdgeType arc[MAXVEX][MAXVEX];/* 邻接矩阵,可看作边表 */
	int numNodes, numEdges; /* 图中当前的顶点数和边数  */
}MGraph;

/* 建立无向网图的邻接矩阵表示 */
void CreateMGraph(MGraph *G)
{
	int i,j,k,w;
	printf("输入顶点数和边数:\n");
	scanf("%d,%d",&G->numNodes,&G->numEdges); /* 输入顶点数和边数 */
	for(i = 0;i <G->numNodes;i++) /* 读入顶点信息,建立顶点表 */
		scanf(&G->vexs[i]);
	for(i = 0;i <G->numNodes;i++)
		for(j = 0;j <G->numNodes;j++)
			G->arc[i][j]=INFINITY;	/* 邻接矩阵初始化 */
	for(k = 0;k <G->numEdges;k++) /* 读入numEdges条边,建立邻接矩阵 */
	{
		printf("输入边(vi,vj)上的下标i,下标j和权w:\n");
		scanf("%d,%d,%d",&i,&j,&w); /* 输入边(vi,vj)上的权w */
		G->arc[i][j]=w; 
		G->arc[j][i]= G->arc[i][j]; /* 因为是无向图,矩阵对称 */
	}
}

我们不能一直使用这种最基本的方式来进行图的建立操作,这种方法的弊端很多,而且不易进行后续的各种操作,不过考试进行使用倒是可以,接下来我们使用一种较为正规的方法来进行图的建立。
我们采用这样一种思路来进行图的建立:首先建立一个没有边的图,然后将图的边进行插入,这样就可以得到一个完整的图
步骤如下:
1.顶点的建立:顶点的建立很简单,我们建立一个二维数组即可,二维数组的大小由顶点数来决定,为了操作方便,我们要将图的边数与顶点数和二维数组捆绑起来,因此,我们可以将他们打包成一个结构体进行操作,结构体定义如下:

//建立顶点结构体
struct Gnode{
	int NV;         //顶点数
	int Ne;         //边数
	weighttype G[maxvertexnum][maxvertexnum];       //二维数组大小由图中的顶点数决定
    datatype data[maxvertexnum];                    //存储顶点的数据
};

typedef struct Gnode *ptrtoGnode:           //指向顶点结构体的指针
typedef struct ptrtoGnode Mgraph;           //邻接矩阵存储的图的类型,利用指针的话在向函数中传递参数的时候比较方便

如果顶点有数据,因此我们可以在建立一个一维数组来存储顶点的数据。小编在建立结构体之后会习惯性的建立一个指向该结构体的指针,这在后续的函数传参过程中会有很大帮助;试想,我们是直接传一个结构体方便还是传一个指针方便呢?

2.初始化一个没有边的图:首先我们给邻接矩阵进行内存申请操作,将顶点数设置为已知的顶点数,边数设置为0。然后将二维矩阵的所有数据都初始化为0,我们很简单的用到了二重循环进行初始化,最后将建立好的图进行返回。

Mgraph creat_graph(int vertexnum)
{
	Vertex V, W;        //将V,W定义为定点类型
	Mgraph graph;
	
	graph = (Mgraph)malloc(sizeof(struct Gnode));       //给邻接矩阵申请空间
	graph -> NV = vertexnum;        //有顶点数
	graph -> Ne = 0;                //边数为0

	//我们将V,W视作顶点而不是两个整形数
	for(V = 0;V < graph -> NV;V++)
    	for(W = 0;W < graph -> NV;w++)
		    graph -> [V][W] = 0;        //邻接矩阵的任意一个顶点得到V,W都定义为0,表示他们之间没有边

    return graph;               //将建立好的图返回
}

我们在循环中使用的是V,W,他们对应的是顶点类型(一般为整形,可以根据实际情况自行更改)
3.建立边结构体
我们知道一个边是由两个顶点所决定的,如果是有权图的话,我们还要加上他的权重,这样边结构体的定义就完成了。建立代码如下:

//建立边结构体
struct enode{
	Vertex v1, v2;      //一个边由两个节点决定 从<v1, v2> 无权图的话,这样就可以了
	weighttype weight;      //权重
};

typedef struct enode *ptrtoenode;       //指向边结构体的指针
typedef ptrtoenode edge;

4.插入边
我们将边上的权重赋值给二位数组的元素,这样就完成了边的插入,如果是无向图的话,我们还需要将权值再次进行赋值。这样就完成了边的插入。

void inert_edge(Mgraph Graph, edge e)
{
	//插入边
	Graph -> G[e -> v1][e -> v2] = e -> weight;
	//若为无向图,还需要插入边<v2, v1>
	Graph -> G[e -> v2][e -> v1] = e -> weight;
}
完成了上述的步骤之后,我们就可以进行一个图的建立了,首先,我们读入顶点数,调用函数进行没有边的图的建立,然后向图中插入边。

最终的完整版代码如下:

#include<stdio.h>       //邻接矩阵表示图
#include<malloc.h>
typedef int weighttype;
typedef int datatype;
typedef int Vertex;

//建立顶点结构体
struct Gnode{
	int NV;         //顶点数
	int Ne;         //边数
	weighttype G[maxvertexnum][maxvertexnum];       //二维数组大小由图中的顶点数决定
    datatype data[maxvertexnum];                    //存储顶点的数据
};

typedef struct Gnode *ptrtoGnode:           //指向顶点结构体的指针
typedef struct ptrtoGnode Mgraph;           //邻接矩阵存储的图的类型,利用指针的话在向函数中传递参数的时候比较方便

//建立边结构体
struct enode{
	Vertex v1, v2;      //一个边由两个节点决定 从<v1, v2> 无权图的话,这样就可以了
	weighttype weight;      //权重
};

typedef struct enode *ptrtoenode;       //指向边结构体的指针
typedef ptrtoenode edge;

//初始化一个有顶点没有边的图
Mgraph creat_graph(int vertexnum)
{
	Vertex V, W;        //将V,W定义为定点类型
	Mgraph graph;
	
	graph = (Mgraph)malloc(sizeof(struct Gnode));       //给邻接矩阵申请空间
	graph -> NV = vertexnum;        //有顶点数
	graph -> Ne = 0;                //边数为0

	//我们将V,W视作顶点而不是两个整形数
	for(V = 0;V < graph -> NV;V++)
    	for(W = 0;W < graph -> NV;w++)
		    graph -> [V][W] = 0;        //邻接矩阵的任意一个顶点得到V,W都定义为0,表示他们之间没有边

    return graph;               //将建立好的图返回
}

//向建立好的图插入边
//方法:将相应的权重赋值给相应的邻接矩阵即可
void inert_edge(Mgraph Graph, edge e)
{
	//插入边
	Graph -> G[e -> v1][e -> v2] = e -> e -> weight;
	//若为无向图,还需要插入边<v2, v1>
	Graph -> G[e -> v2][e -> v1] = e -> e -> weight;
}

Mgraph build_graph()
{
	Mgraph Graph;
	Edge E;
	Vertex V;
	int NV. i;
	
	scanf("%d", &Nv);
	Graph = creat_graph(Nv);
	scanf("%d", &(Graph -> Ne));        //直接使用创建好的图来进行边的操作
	if(Graph -> Ne != 0)        //如果没有边的话
	{
		E = (edge)malloc(sizeof(struct enode));     //建立临时的边界点,存储这个边
		for(i = 0;i < Graph -> Ne;i++)
		{
			scanf("%d %d %d", &E -> v1, &E -> v2, &E -> weight);    //读入边的信息
			insert_edge(Graph, E);      //插入边的信息
		}
	}
	//如果有数据的话,要进行数据的读入
	for(V = 0;V < Graph -> Nv;V++)
		scanf("%c", (Graph -> data[V]));
	
	return Graph;
}

//输入格式
//Nv Ne             顶点数,边数
//v1 v2 weight      顶点,权重
  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
邻接矩阵是一种表示方法,可以用于存储中节点之间的连接关系。在 Python 中,可以使用二维数组来表示邻接矩阵。 下面是一个简单的示例代码,展示了如何通过邻接矩阵来表示和操作一个简单的无向: ```python class Graph: def __init__(self, num_vertices): self.num_vertices = num_vertices self.adj_matrix = [[0] * num_vertices for _ in range(num_vertices)] def add_edge(self, src, dest): # 由于是无向,所以需要设置两个方向的连接关系 self.adj_matrix[src][dest] = 1 self.adj_matrix[dest][src] = 1 def remove_edge(self, src, dest): self.adj_matrix[src][dest] = 0 self.adj_matrix[dest][src] = 0 def print_graph(self): for row in self.adj_matrix: for val in row: print(val, end=" ") print() # 创建一个有 5 个节点的 g = Graph(5) g.add_edge(0, 1) g.add_edge(0, 4) g.add_edge(1, 2) g.add_edge(1, 3) g.add_edge(1, 4) g.add_edge(2, 3) g.add_edge(3, 4) g.print_graph() ``` 上述示例代码中,首先定义了一个 `Graph` 类,其中 `num_vertices` 表示中节点的数量,`adj_matrix` 是一个二维数组用于存储邻接矩阵。 然后,定义了几个方法来操作,例如 `add_edge` 用于添加边,`remove_edge` 用于移除边,`print_graph` 用于打印邻接矩阵。 最后,创建一个具有 5 个节点的,并添加了一些边,然后调用 `print_graph` 方法打印出邻接矩阵。 你可以根据实际需求进行修改和扩展。希望对你有帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值