图的基本操作(邻接矩阵)

本文只有代码,介绍了有关图(邻接矩阵)的基本操作。


已经过调试没有很大问题。
如有错误,还请批评指正。

一、图的数组(邻接矩阵)存储表示:

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

/* 状态信息 */
typedef int Status;
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

/* 图的数组(邻接矩阵)存储表示 */
typedef int VRType;       //顶点关系类型
typedef char InfoType;    //弧类型
typedef char VertexType;  //顶点类型
#define INFINITY 0  //最大值∞
#define MAX_VERTEX_NUM 20 //最大顶点个数

typedef enum { DG, DN, UDG, UDN } GraphKind;//{有向图,有向网,无向图,无向网}

typedef struct ArcCell
{
	VRType adj;    //VRType是顶点关系类型。对无权图,用1和0表示相邻否;对带权图,则为权值类型
	InfoType* info;//该弧相关信息的指针
}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct {
	VertexType vexs[MAX_VERTEX_NUM];//顶点向量 
	AdjMatrix arcs;                 //邻接矩阵 
	int vexnum, arcnum;             //图的当前顶点数和弧数 
	GraphKind kind;                 //图的种类标志 
}MGraph;

二、有关图的基本操作:

/* 函数声明 */
Status CreateGraph(MGraph* G);/* 构造图CreateGraph(&G) */

Status CreateUDN(MGraph* G);/* 构造无向网CreateUDN(&G) */

Status CreateUDG(MGraph* G);/* 构造无向图CreateUDG(&G) */

Status CreateDN(MGraph* G);/* 构造有向网CreateDN(&G) */

Status CreateDG(MGraph* G);/* 构造有向图CreateDG(&G) */

void PrintGraph(MGraph G);/* 打印图PrintGraph(G) */

Status DestroyGraph(MGraph* G);/* 销毁图DestroyGraph(&G) */

Status LocateVex(MGraph G, VertexType u);/* 若图中存在顶点u,则返回该顶点在图中的位置LocateVex(G, u) */

Status GetVex(MGraph G, VertexType v);/* v是G的某个顶点,返回v的值GetVex(G, v) */

Status PutVex(MGraph* G, VertexType v, VertexType value);/* 对v赋值PutVex(&G, v, value) */

Status FirstAdjVex(MGraph G, VertexType v);/* 返回v的第一个邻接顶点FirstAdjVex(G, v) */

Status NextAdjVex(MGraph G, VertexType v, VertexType w);/* w是v的邻接顶点,返回v相对于w的下一个邻接顶点NextAdjVex(G, v, w) */

Status InsertVex(MGraph* G, VertexType v);/* 在图中增添新顶点InsertVex(&G, v) */

Status DeleteVex(MGraph* G, VertexType v);/* 删除G中顶点v及其相关的弧DeleteVex(&G, v) */

Status InsertArc(MGraph* G, VertexType v, VertexType w, VRType value);/* 在图中增添弧InsertArc(&G, v, w, value) */

Status DeleteArc(MGraph* G, VertexType v, VertexType w);/* 在图中删除弧DeleteArc(&G, v, w) */

/* DFS/BFS使用的全局变量 */
int visited[MAX_VERTEX_NUM];

void DFS(MGraph G, int n);/* 从第n个顶点出发深度优先遍历图DFS(G, n) */

void DFSTraverse(MGraph G);/* 对图G进行深度优先遍历DFSTraverse(G) */

void BFS(MGraph G, int n);/* 从第n个顶点出发广度优先遍历图BFS(G, n) */

void BFSTraverse(MGraph G);/* 对图G进行广度优先遍历BFSTraverse(G) */

1、构造图:

/*---------------------------------------------------------------------------------------
功能:构造图
参数:1、图
输出:OK、ERROR
*/
/* 构造图CreateGraph(&G) */
Status CreateGraph(MGraph* G)
{
	printf("1.有向图 2.有向网 3.无向图 4.无向网\n");
	printf("请输入要创建表的种类:>");
	scanf("%d", &G->kind);
	switch (G->kind - 1)
	{
	case DG:
		return CreateDG(G);
	case DN:
		return CreateDN(G);
	case UDG:
		return CreateUDG(G);
	case UDN:
		return CreateUDN(G);
	default:
		break;
	}
	return ERROR;
}

2、构造无向网:

/*---------------------------------------------------------------------------------------
功能:构造无向网
参数:1、图指针 
输出:OK、ERROR
*/
/* 构造无向网CreateUDN(&G) */
Status CreateUDN(MGraph* G)
{
	int i = 0, j = 0, k = 0, w = 0;
	char temp = 0;//临时储存
	printf("请输入图的顶点个数\n");
	scanf("%d", &G->vexnum);
	printf("请输入图的弧数\n");
	scanf("%d", &G->arcnum);
	printf("请输入所有顶点\n");
	for (i = 0; i < G->vexnum; i++)
	{
		temp = getchar();        //储存回车符
		scanf("%c", &G->vexs[i]);//将所有的顶点读入数组vexs中进行存储
	}
	//进行初始化,赋初值 
	for (i = 0; i < G->vexnum; i++)
	{
		for (j = 0; j < G->vexnum; j++)
		{
			G->arcs[i][j].adj = INFINITY;
			G->arcs[i][j].info = NULL;
		}
	}
	char v1, v2;
	printf("请输入弧的两个顶点和权值\n");
	//对矩阵进行赋值 
	for (k = 0; k < G->arcnum; k++)
	{
		temp = getchar();
		scanf("%c%c%d", &v1, &v2, &w);
		i = LocateVex(*G, v1);
		j = LocateVex(*G, v2);
		G->arcs[i][j].adj = w;
		G->arcs[j][i].adj = w;//对称 
	}
	printf("无向网创建成功!!!\n");
	return OK;
}

3、构造无向图:

/*---------------------------------------------------------------------------------------
功能:构造无向图
参数:1、图指针
输出:OK、ERROR
*/
/* 构造无向图CreateUDG(&G) */
Status CreateUDG(MGraph* G)
{
	int i = 0, j = 0, k = 0, w = 0;
	char temp = 0;//临时储存
	printf("请输入图的顶点个数\n");
	scanf("%d", &G->vexnum);
	printf("请输入图的弧数\n");
	scanf("%d", &G->arcnum);
	printf("请输入所有顶点\n");
	for (i = 0; i < G->vexnum; i++) 
	{
		temp = getchar();        //储存回车符
		scanf("%c", &G->vexs[i]);//将所有的顶点读入数组vexs中进行存储
	}
	//进行初始化,赋初值 
	for (i = 0; i < G->vexnum; i++) 
	{
		for (j = 0; j < G->vexnum; j++) 
		{
			G->arcs[i][j].adj = INFINITY;
			G->arcs[i][j].info = NULL;
		}
	}
	char v1, v2;
	printf("请输入弧的两个顶点\n");
	//对矩阵进行赋值 
	for (k = 0; k < G->arcnum; k++) 
	{
		temp = getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(*G, v1);
		j = LocateVex(*G, v2);
		G->arcs[i][j].adj = 1;
		G->arcs[j][i].adj = 1;//对称 
	}
	printf("无向图创建成功!!!\n");
	return OK;
}

4、构造有向网:

/*---------------------------------------------------------------------------------------
功能:构造有向网
参数:1、图指针
输出:OK、ERROR
*/
/* 构造有向网CreateDN(&G) */
Status CreateDN(MGraph* G)
{
	int i = 0, j = 0, k = 0, w = 0;
	char temp = 0;//临时储存
	printf("请输入图的顶点个数\n");
	scanf("%d", &G->vexnum);
	printf("请输入图的弧数\n");
	scanf("%d", &G->arcnum);
	printf("请输入所有顶点\n");
	for (i = 0; i < G->vexnum; i++)
	{
		temp = getchar();        //储存回车符
		scanf("%c", &G->vexs[i]);//将所有的顶点读入数组vexs中进行存储
	}
	//进行初始化,赋初值 
	for (i = 0; i < G->vexnum; i++)
	{
		for (j = 0; j < G->vexnum; j++)
		{
			G->arcs[i][j].adj = INFINITY;
			G->arcs[i][j].info = NULL;
		}
	}
	char v1, v2;
	printf("请输入弧的两个顶点(起点-终点)和权值\n");
	//对矩阵进行赋值 
	for (k = 0; k < G->arcnum; k++)
	{
		temp = getchar();
		scanf("%c%c%d", &v1, &v2, &w);
		i = LocateVex(*G, v1);
		j = LocateVex(*G, v2);
		G->arcs[i][j].adj = w;
	}
	printf("有向网创建成功!!!\n");
	return OK;
}

5、构造有向图:

/*---------------------------------------------------------------------------------------
功能:构造有向图
参数:1、图指针
输出:OK、ERROR
*/
/* 构造有向图CreateDG(&G) */
Status CreateDG(MGraph* G)
{
	int i = 0, j = 0, k = 0, w = 0;
	char temp = 0;//临时储存
	printf("请输入图的顶点个数\n");
	scanf("%d", &G->vexnum);
	printf("请输入图的弧数\n");
	scanf("%d", &G->arcnum);
	printf("请输入所有顶点\n");
	for (i = 0; i < G->vexnum; i++)
	{
		temp = getchar();        //储存回车符
		scanf("%c", &G->vexs[i]);//将所有的顶点读入数组vexs中进行存储
	}
	//进行初始化,赋初值 
	for (i = 0; i < G->vexnum; i++)
	{
		for (j = 0; j < G->vexnum; j++)
		{
			G->arcs[i][j].adj = INFINITY;
			G->arcs[i][j].info = NULL;
		}
	}
	char v1, v2;
	printf("请输入弧的两个顶点(起点-终点)\n");
	//对矩阵进行赋值 
	for (k = 0; k < G->arcnum; k++)
	{
		temp = getchar();
		scanf("%c%c", &v1, &v2);
		i = LocateVex(*G, v1);
		j = LocateVex(*G, v2);
		G->arcs[i][j].adj = 1; 
	}
	printf("有向图创建成功!!!\n");
	return OK;
}

6、打印图:

/*---------------------------------------------------------------------------------------
功能:打印图
参数:1、图
输出:空
*/
/* 打印图PrintGraph(G) */
void PrintGraph(MGraph G)
{
	int i = 0, j = 0;
	for (i = 0; i < G.vexnum; ++i)
	{
		for (j = 0; j < G.vexnum; ++j)
		{
			printf("%d ", G.arcs[i][j].adj);
			if ((j + 1) % G.vexnum == 0)

				printf("\n");
		}
	}
}

7、销毁图:

扫描二维码关注公众号,回复: 15756250 查看本文章
/*---------------------------------------------------------------------------------------
功能:销毁图
参数:1、图指针
输出:OK、ERROR
*/
/* 销毁图DestroyGraph(&G) */
Status DestroyGraph(MGraph* G)
{
	int i = 0, j = 0;
	for (i = 0; i < G->vexnum; i++) 
	{
		for (j = 0; j < G->vexnum; j++) 
		{
			G->arcs[i][j].adj = INFINITY;
			G->arcs[i][j].info = NULL;
		}
	}
	G->vexnum = 0;
	G->arcnum = 0;
	return OK;
}

8、若图中存在顶点u,则返回该顶点在图中的位置:

/*---------------------------------------------------------------------------------------
功能:若图中存在顶点u,则返回该顶点在图中的位置
参数:1、图 2、顶点
输出:顶点位置、FALSE
*/
/* 若图中存在顶点u,则返回该顶点在图中的位置LocateVex(G, u) */
Status LocateVex(MGraph G, VertexType u)
{
	int i = 0;
	for (i = 0; i < G.vexnum; i++) {
		if (G.vexs[i] == u)
			return i;
	}
	return FALSE;
}

9、v是G的某个顶点,返回v的值:

/*---------------------------------------------------------------------------------------
功能:v是G的某个顶点,返回v的值
参数:1、图 2、顶点
输出:顶点的值、FALSWE
*/
/* v是G的某个顶点,返回v的值GetVex(G, v) */
Status GetVex(MGraph G, VertexType v)
{
	int i = 0;
	for (i = 0; i < G.vexnum; i++) 
	{
		if (G.vexs[i] == v)
			return i;
	}
	return FALSE;
}

10、对v赋值:

/*---------------------------------------------------------------------------------------
功能:对v赋值
参数:1、图指针 2、顶点 3、值
输出:OK、ERROR
*/
/* 对v赋值PutVex(&G, v, value) */
Status PutVex(MGraph* G, VertexType v, VertexType value)
{
	int i = 0;
	for (i = 0; i < G->vexnum; i++) 
	{
		if (G->vexs[i] == v)
			G->vexs[i] = value;
		return OK;
	}
	return ERROR;
}

11、返回v的第一个邻接顶点的值:

/*---------------------------------------------------------------------------------------
功能:返回v的第一个邻接顶点的值
参数:1、图 2、顶点
输出:顶点、FALSE
*/
/* 返回v的第一个邻接顶点FirstAdjVex(G, v) */
Status FirstAdjVex(MGraph G, VertexType v)
{
	int i = 0, j = 0;
	i = LocateVex(G, v);
	for (j = 0; j < G.vexnum; j++) 
	{
		if (G.arcs[i][j].adj != INFINITY || G.arcs[j][i].adj != INFINITY)
		{
			return j;
		}
	}
	return FALSE;
}

12、w是v的邻接顶点,返回v相对于w的下一个邻接顶点的值:

/*---------------------------------------------------------------------------------------
功能:w是v的邻接顶点,返回v相对于w的下一个邻接顶点的值
参数:1、图 2、顶点 3、顶点
输出:顶点、FALSE
*/
/* w是v的邻接顶点,返回v相对于w的下一个邻接顶点NextAdjVex(G, v, w) */
Status NextAdjVex(MGraph G, VertexType v, VertexType w)
{
	int i = 0, j = 0, n = 0;
	i = LocateVex(G, v);
	j = LocateVex(G, w);
	for (n = j + 1; n < G.vexnum; n++) 
	{
		if (G.arcs[i][n].adj != INFINITY || G.arcs[n][i].adj != INFINITY)
		{
			return n;
		}
	}
	return FALSE;
}

13、在图中增添新顶点:

/*---------------------------------------------------------------------------------------
功能:在图中增添新顶点
参数:1、图指针 2、顶点
输出:OK、ERROR
*/
/* 在图中增添新顶点InsertVex(&G, v) */
Status InsertVex(MGraph* G, VertexType v)
{
	int i = 0;
	G->vexnum++;
	//更改存储顶点的数组 
	G->vexs[G->vexnum - 1] = v;
	//更改矩阵
	for (i = 0; i < G->vexnum; i++) 
	{
		//为矩阵最外层行、列的元素赋初始值 
		G->arcs[G->vexnum - 1][i].adj = INFINITY;
		G->arcs[G->vexnum - 1][i].info = NULL;
		G->arcs[i][G->vexnum - 1].adj = INFINITY;
		G->arcs[i][G->vexnum - 1].info = NULL;
	}
	return OK;
}

14、删除G中顶点v及其相关的弧:

/*---------------------------------------------------------------------------------------
功能:删除G中顶点v及其相关的弧
参数:1、图指针 2、顶点
输出:OK、ERROR
*/
/* 删除G中顶点v及其相关的弧DeleteVex(&G, v) */
Status DeleteVex(MGraph* G, VertexType v)
{
	int i = 0, j = 0, temp = 0;
	i = LocateVex(*G, v);
	temp = i;
	//更改存储顶点的数组 
	for (temp; temp < G->vexnum; temp++) 
	{
		G->vexs[temp] = G->vexs[temp + 1];//存储顶点的数组中向前移一位,覆盖要删除的顶点 
	}
	G->vexnum--;
	//更改矩阵
	for (j = 0; j < G->vexnum + 1; j++) 
	{
		//使矩阵中靠后位置的顶点前移,覆盖被删除的顶点
		for (i; i < G->vexnum + 1; i++) 
		{
			G->arcs[j][i] = G->arcs[j][i + 1];
			G->arcs[i][j] = G->arcs[i + 1][j];
		}
	}
	for (i = 0; i < G->vexnum; i++) 
	{
		//上一步前移完成后矩阵的最外层的行、列的数据应被清除 
		G->arcs[G->vexnum][i].adj = INFINITY;
		G->arcs[G->vexnum][i].info = NULL;
		G->arcs[i][G->vexnum].adj = INFINITY;
		G->arcs[i][G->vexnum].info = NULL;
	}
	return OK;
}

15、在图中增添弧:

/*---------------------------------------------------------------------------------------
功能:在图中增添弧
参数:1、图指针 2、顶点 3、顶点 4、权值
输出:OK、ERROR
*/
/* 在图中增添弧InsertArc(&G, v, w, value) */
Status InsertArc(MGraph* G, VertexType v, VertexType w, VRType value)
{
	int i = 0, j = 0;
	i = LocateVex(*G, v);
	j = LocateVex(*G, w);
	G->arcs[i][j].adj = value;
	G->arcs[i][j].info = NULL;
	G->arcs[j][i].adj = value;
	G->arcs[j][i].info = NULL;
	return OK;
}

16、在图中删除弧:

/*---------------------------------------------------------------------------------------
功能:在图中删除弧
参数:1、图指针 2、顶点 3、顶点
输出:OK、ERROR
*/
/* 在图中删除弧DeleteArc(&G, v, w) */
Status DeleteArc(MGraph* G, VertexType v, VertexType w)
{
	int i = 0, j = 0;
	i = LocateVex(*G, v);
	j = LocateVex(*G, w);
	G->arcs[i][j].adj = INFINITY;
	G->arcs[i][j].info = NULL;
	G->arcs[j][i].adj = INFINITY;
	G->arcs[j][i].info = NULL;
	return OK;
}

17、从第n个顶点出发深度优先遍历图:

/*---------------------------------------------------------------------------------------
功能:从第n个顶点出发深度优先遍历图
参数:1、图 2、顶点位置
输出:空
*/
/* 从第n个顶点出发深度优先遍历图DFS(G, n) */
void DFS(MGraph G, int n)
{
	int i;
	printf("%c", G.vexs[n]);
	visited[n] = TRUE;
	for (i = 0; i < G.vexnum; i++) 
	{
		if (G.arcs[n][i].adj != INFINITY && visited[i] == FALSE)
		{
			DFS(G, i);
		}
	}
}

18、对图G进行深度优先遍历:

/*---------------------------------------------------------------------------------------
功能:对图G进行深度优先遍历
参数:1、图
输出:空
*/
/* 对图G进行深度优先遍历DFSTraverse(G) */
void DFSTraverse(MGraph G)
{
	int i = 0, n = 0;
	for (i = 0; i < G.vexnum; i++)
	{
		visited[i] = FALSE; //初始化标志数组 
	}
	for (n = 0; n < G.vexnum; n++) 
	{
		//因为图可能是非联通图,递归访问下一个顶点时可能会中断,因此需要从每一个顶点开始做深度优先遍历
		if (visited[n] == FALSE)//判断是否被访问过,未被访问过时访问 
		{
			DFS(G, n);
		}
	}
}

19、从第n个顶点出发广度优先遍历图:

/*---------------------------------------------------------------------------------------
功能:从第n个顶点出发广度优先遍历图
参数:1、图 2、顶点位置
输出:空
*/
/* 从第n个顶点出发广度优先遍历图BFS(G, n) */
void BFS(MGraph G, int n)
{
	int que[MAX_VERTEX_NUM], front = 0, rear = 0;
	int i = 0, w = 0;
	printf("%c", G.vexs[n]);
	visited[n] = TRUE;//访问 
	rear = (rear + 1) % MAX_VERTEX_NUM;//入队 
	que[rear] = n;
	while (front != rear) 
	{
		//队列不空时 
		front = (front + 1) % MAX_VERTEX_NUM;//出队 
		i = que[front];
		for (w = FirstAdjVex(G, G.vexs[i]); w != FALSE; w = NextAdjVex(G, G.vexs[i], G.vexs[w])) 
		{
			if (visited[w] == FALSE) 
			{
				visited[w] = TRUE;
				printf("%c", G.vexs[w]);//访问 
				rear = (rear + 1) % MAX_VERTEX_NUM;//入队 
				que[rear] = w;
			}
		}
	}
}

20、对图G进行广度优先遍历:

/*---------------------------------------------------------------------------------------
功能:对图G进行广度优先遍历
参数:1、图
输出:空
*/
/* 对图G进行广度优先遍历BFSTraverse(G) */
void BFSTraverse(MGraph G)
{
	int i = 0, n = 0;
	for (i = 0; i < G.vexnum; i++)
	{
		visited[i] = FALSE; //初始化标志数组 
	}
	for (n = 0; n < G.vexnum; n++) 
	{
		//因为图可能是非联通图,递归访问下一个顶点时可能会中断,因此需要从每一个顶点开始做深度优先遍历
		if (visited[n] == FALSE)//判断是否被访问过,未被访问过时访问 
		{
			BFS(G, n);
		}
	}
}

三、测试主程序(以无向网为例):

int main()
{
	MGraph G;
	int pos = 0,value = 0;
	VertexType v, w,p, q = 0;

	CreateGraph(&G);
	
	printf("邻接矩阵:\n");
	PrintGraph(G);

	v = 'a';
	pos = GetVex(G,v);
	printf("%c的位置是第%d个\n", v, pos);

	v = 'c';
	p = FirstAdjVex(G,v);
	printf("%c的第一个邻接顶点是%c\n", v, G.vexs[p]);

	v = 'c';
	w = 'b';
	p = NextAdjVex(G,v,w);
	printf("%c相对于%c的下一个邻接顶点是%c\n", v, w, G.vexs[p]);

	v = 'd';
	w = 'e';
	value = 1;
	if (InsertArc(&G, v, w, value))
	{
		printf("成功插入<%c,%c,%d>\n", v, w, value);
	}
	printf("邻接矩阵:\n");
	PrintGraph(G);

	v = 'd';
	w = 'e';
	if (DeleteArc(&G, v, w))
	{
		printf("成功删除弧<%c,%c>\n", v, w);
	}

	printf("邻接矩阵:\n");
	PrintGraph(G);

	printf("深度优先遍历DFS:\n");
	DFSTraverse(G);
	printf("\n");

	printf("广度优先遍历BFS:\n");
	BFSTraverse(G);
	printf("\n");

	if (DestroyGraph(&G))
	{
		printf("销毁成功!!!\n");
	}
	
	system("pause");
	return 0;
}

四、测试结果:

猜你喜欢

转载自blog.csdn.net/absorb2601078490/article/details/125526924