图的基本操作1【代码实现】

说明:本代码还有一定的改进空间,比如判断是否存在弧<a,b>,因为最开始写的时候,默认邻接数组索引结点和顶点数据域是一样,所有传入的是数字,后来觉得这样默认不太恰当,故又进行的改进,每次都获取数组下表,故有时候略显冗杂,但是,因为代码量过大,函数调用过多,故后期再去改动前期这个代码需要改动地方太多,故没有进行重新编写函数,但总体不影响代码的可理解性。如下所有代码都经过编译测试,可以保证完全正确,如有错误或改进空间,还望评论区指正,希望我们共同进步,加油!

主要实现函数如下:

//建立无向图
void createALGraph(ALGraph& G, VertexType* vList, int vListLength, int** arcList, int arcListLength);
//判断图G中是否存在边<x,y>
bool Adjacent(ALGraph G, int x, int y);
//得到索引下标
int getIndex(ALGraph G, VertexType x);
//列出图G中与节点x相邻接的结点
void Neighbors(ALGraph G, VertexType x);
//在图G中插入顶点x
bool insertVertex(ALGraph& G, VertexType x);
//在图G中插入弧<x,y>
bool insertArc(ALGraph& G, VertexType x,VertexType y);
//从图中删除弧<x,y>
bool delectArc(ALGraph& G, VertexType x, VertexType y);
//在G中删除顶点x
bool delectVertex(ALGraph& G, VertexType x);

代码如下:

(1)ALGraph.h

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_VERTEX_NUM 100
#define MAX_ARCLIST_LENGTH 100
/*顶点:vertex,边:edge,弧:arc*/
typedef char VertexType;//图顶点类型
//定义弧(边)结点数据结构类型
typedef struct ArcNode {
	int adjvex;//该弧所指向的顶点位置,即弧头结点在邻接表中的索引
	struct ArcNode* nextArc;//指向下一条弧的指针
	//int weight;//带权图中弧的权值,不带权图无该成员域
}ArcNode;
//定义头结点(顶点)数据结构类型
typedef struct VNode {
	VertexType data;//顶点数据
	ArcNode* firstArc;//指向链表中第一个弧结点
}VNode, AdjList[MAX_VERTEX_NUM];//AdjList表示邻接表类型
//例如:AdjList v;等价于VNode v[Max_VERTEX_NUM]

//定义图的数据结构类型
typedef struct {
	AdjList vertices;//所有结点和结点之间的关系
	int vexNum, arcNum;//图的定点数和弧数
	int kind;//图的类型
}ALGraph;//以邻接表存储的图类型

//输入数据并建图
void scanf1(ALGraph& G);
//建立无向图
void createALGraph(ALGraph& G, VertexType* vList, int vListLength, int** arcList, int arcListLength);
//输出顶点数据
void printf1(VertexType* vList, int vListLength);
//输出弧数据
void printf2(int** arcList, int arcListLength);
//输出图中顶点信息
void printf3(ALGraph G);
//判断图G中是否存在边<x,y>
bool Adjacent(ALGraph G, int x, int y);
//得到索引下标
int getIndex(ALGraph G, VertexType x);
//列出图G中与节点x相邻接的结点
void Neighbors(ALGraph G, VertexType x);
//在图G中插入顶点x
bool insertVertex(ALGraph& G, VertexType x);
//在图G中插入弧<x,y>
bool insertArc(ALGraph& G, VertexType x,VertexType y);
//从图中删除弧<x,y>
bool delectArc(ALGraph& G, VertexType x, VertexType y);
//在G中删除顶点x
bool delectVertex(ALGraph& G, VertexType x);

 (2)operateALGraph.cpp

#include"ALGraph.h"

void scanf1(ALGraph& G) {
	//顶点信息集合
	int vListLength;
	scanf("%d", &vListLength);
	char ch;
	scanf("%c", &ch);//处理换行符
	//编号从1开始编号
	VertexType* vList = (VertexType*)malloc(sizeof(VertexType) * (vListLength + 1));
	for (int i = 1; i <= vListLength; i++) {
		scanf("%c ", &vList[i]);//注意对空格的处理
	}
	//弧结点信息集合
	int arcListLength;
	scanf("%d", &arcListLength);
	//动态申请一个arcListLength行2列的二维数组
	int** arcList = (int**)malloc(sizeof(int*) * arcListLength);
	for (int i = 0; i < arcListLength; i++) {
		arcList[i] = (int*)malloc(sizeof(int) * 2);
	}
	//VertexType arcList[MAX_ARCLIST_LENGTH][2];
	//二维数组数据输入
	for (int i = 0; i < arcListLength; i++) {
		for (int j = 0; j < 2; j++) {
			scanf("%d", &arcList[i][j]);
		}
	}
	检查数据输入是否成功
	//printf1(vList, vListLength);
	//printf("\n");
	//printf2(arcList, arcListLength);
	注意函数传参,参数类型是否兼容
	createALGraph(G, vList, vListLength, arcList, arcListLength);
}
/*邻接表建立无向图算法思想:首先将顶点集合存入邻接数组。然后访问每一条边<vi,vj>,使用头查法在第i条链中插入一个邻接域为j的弧结点;
重复上述步骤,直到所有的边访问结束为止,最后将顶点数和边数记录到图的数据结构中。*/
void createALGraph(ALGraph &G,VertexType *vList,int vListLength,int** arcList,int arcListLength)
{
	//从第一个顶点开始,依次访问每一个顶点
	for (int i = 1; i <=vListLength; i++) {
		G.vertices[i].data = vList[i];//将顶点信息存入头节点,默认顶点为数字编号
		G.vertices[i].firstArc = NULL;//将头结点指针域置空,建立一个带头空表
	}
	//读取每一条弧的信息,使用头插法,构造数据结点(弧结点)插入链表中
	for (int i = 0; i < arcListLength; i++) {
		VertexType v = arcList[i][0];
		VertexType w = arcList[i][1];
		//无向图在第v条链插入弧<v,w>的弧结点
		ArcNode* pArcNode = (ArcNode*)malloc(sizeof(ArcNode));//申请表结点
		pArcNode->adjvex = w;//弧头写入表结点
		pArcNode->nextArc = G.vertices[v].firstArc;//头插法,插入生成的弧结点
		G.vertices[v].firstArc = pArcNode;
		//无向图在第w条链插入弧<w,v>的弧结点
		pArcNode = (ArcNode*)malloc(sizeof(ArcNode));
		pArcNode->adjvex = v;
		pArcNode->nextArc = G.vertices[w].firstArc;
		G.vertices[w].firstArc = pArcNode;
	}
	G.vexNum = vListLength;//G的顶点数
	G.arcNum = arcListLength;//G的弧数
	G.kind = 0;//0代表G为无向图
}
//判断图G中是否存在边<x,y>
/*算法思想:找到头节点邻接表中的索引为x的那条链,然后遍历链表,检验弧结点数据域是否存在为y的结点,若存在,则返回真,否则,返回假*/
bool Adjacent(ALGraph G, int x, int y) {
	ArcNode* pArcNode = G.vertices[x].firstArc;
	for (; pArcNode != NULL; pArcNode = pArcNode->nextArc) {
		if (pArcNode->adjvex == y) {
			return true;
			break;
		}
	}
	return false;
}
//得到索引下标
int getIndex(ALGraph G, VertexType x) {
	int i = 0;
	for (i = 1; i <=G.vexNum; i++) {
		if (G.vertices[i].data == x) {
			return i;
		}
	}
	return 0;
}
//列出图G中与节点x相邻接的结点
/*算法思想:首先遍历邻接数组,获取x在邻接数组中的索引下标;如果为无向图,则遍历头节点为x的那条链,输出所有邻接数组索引下标为该链弧结点数据域的顶点;
如果为有向图,则除了需要遍历头节点为x的那条链,输出所有邻接数组索引下标为该链弧结点数据域的顶点,还需要遍历其他链表,输出链表中数据域为x在邻接数组中的索引下标的链表头结点。*/
void Neighbors(ALGraph G, VertexType x)
{
	int index = getIndex(G,x);
	if (index == 0) {
		printf("图中不存在结点为%c的结点\n", x);
	}
	else {
		//G为无向图
		if (G.kind == 0) {
			ArcNode* pArcNode = G.vertices[index].firstArc;
			for (; pArcNode != NULL; pArcNode = pArcNode->nextArc) {
				printf("%c ", G.vertices[pArcNode->adjvex].data);
			}
		}
		//G为无向图
		if (G.kind == 1) {
			//遍历头节点为x的那条链,输出所有邻接数组索引下标为该链弧结点数据域的顶点
			ArcNode* pArcNode = G.vertices[index].firstArc;
			for (; pArcNode != NULL; pArcNode = pArcNode->nextArc) {
				printf("%c ", G.vertices[pArcNode->adjvex].data);
			}
			//需要遍历其他链表,输出链表中数据域为x在邻接数组中的索引下标的链表头结点
			for (int i = 1; i <= G.vexNum; i++) {
				pArcNode = G.vertices[i].firstArc;
				for (; pArcNode != NULL; pArcNode = pArcNode->nextArc) {
					if (pArcNode->adjvex == index) {
						printf("%c ", G.vertices[i].data);
					}
				}
			}
		}
		printf("\n");
	}
}
//在图G中插入顶点x
bool insertVertex(ALGraph& G, VertexType x) {
	if (getIndex(G,x)) {
		return false;//图中已经存在该节点,不需要插入
	}
	//为新顶点申请空间并初始化
	VNode* pnode = (VNode*)malloc(sizeof(VNode));
	pnode->data = x;
	pnode->firstArc = NULL;
	//图中顶点数+1
	G.vexNum += 1;
	//将新顶点插入邻接数组中
	G.vertices[G.vexNum] = *pnode;
}
//从图中删除弧<x,y>
/*算法思想:在第x条链中查找邻接域为y的弧结点,将其在链表中删除;如果该图为无向图,则还需要删除<y,x>的弧*/
bool delectArc(ALGraph& G, VertexType x, VertexType y) {
	int v = getIndex(G, x);
	int w = getIndex(G, y);
	//在第x条链中查找邻接域为y的弧结点,将其在链表中删除
	ArcNode* preNode = NULL;//注意无法直接设置指向表头,因为数据结构类型不一样
	ArcNode* pcurNode = G.vertices[v].firstArc;
	while (pcurNode != NULL && pcurNode->adjvex != w) {
		preNode = pcurNode;
		pcurNode = pcurNode->nextArc;
	}
	if (pcurNode == NULL || pcurNode->adjvex != w) {
		return false;
	}
	else {
		//链表中的第一个弧结点
		if (pcurNode == G.vertices[v].firstArc) {
			G.vertices[v].firstArc = pcurNode->nextArc;//更新表头中的指针域
		}
		else {//否则,利用前驱后继直接删除链表中结点
			preNode->nextArc = pcurNode->nextArc;
		}
		free(pcurNode);
		pcurNode = NULL;
		return true;
	}
}
//在G中删除顶点x
/*算法思想:首先删除以x为头节点的链表中所有弧结点,然后删除以x为弧头的所有弧结点,最后删除顶点x*/
bool delectVertex(ALGraph& G, VertexType x) {
	int index = getIndex(G,x);//获得x在邻接数组中的索引下表
	if (index == 0) {
		return false;
	}
	else {
		//删除以x为弧头的所有弧结点
		for (int i = 1; i <= G.vexNum; i++) {
			int index1 = getIndex(G,G.vertices[i].data);
			if (Adjacent(G, index1, index)) {
				delectArc(G, G.vertices[i].data, x);
			}
		}
		//删除以x为头节点的链表中所有弧结点
		ArcNode* pnode = G.vertices[index].firstArc;
		while (pnode != NULL) {
			ArcNode* ptemp = pnode;
			pnode = pnode->nextArc;
			G.vertices[index].firstArc = pnode;
			free(ptemp);
		}
		//删除顶点x(注意删除操作)
		G.vertices[index].data ='\0';
		return true;
	}
}
bool insertArc(ALGraph& G, VertexType x, VertexType y)
{
	int v = getIndex(G, x);
	int w = getIndex(G, y);
	if (Adjacent(G, v, w)) {//弧已经存在
		return false;
	}
	ArcNode* pnode = (ArcNode*)malloc(sizeof(ArcNode));
	pnode->adjvex = w;
	pnode->nextArc = G.vertices[v].firstArc;
	G.vertices[v].firstArc = pnode;
	return true;
}
//输出顶点数据
void printf1(VertexType* vList, int vListLength) {
	for (int i = 1; i <= vListLength; i++) {
		printf("%c ", vList[i]);
	}
}
//输出弧数据
void printf2(int** arcList, int arcListLength) {
	for (int i = 0; i < arcListLength; i++) {
		for (int j = 0; j < 2; j++) {
			printf("%d ", arcList[i][j]);
		}
		printf("\n");
	}
}
//输出图中顶点信息
void printf3(ALGraph G) {
	for (int i = 1; i <= G.vexNum; i++) {
		printf("%c ", G.vertices[i].data);
	}
}

(3)main.cpp

#include"ALGraph.h"
int main() {
	ALGraph G;//图
	scanf1(G);//输入数据并建图
	char ch;
	/*int x, y;
	scanf("%d %d", &x, &y);
	if (Adjacent(G, x, y))//判断图G中是否存在弧<x,y>
	{
		printf("存在<%d,%d>的弧\n", x, y);
	}
	else {
		printf("不存在<%d,%d>的弧\n", x, y);
	}*/
	/*
	scanf("%c", &ch);//处理换行符
	VertexType c;
	scanf("%c", &c);
	Neighbors(G, c);//列出图G中与节点c相邻接的结点
	*/
	/*
	scanf("%c", &ch);//处理换行符
	VertexType add;
	scanf("%c", &add);
	//在图G中插入顶点
	if (!insertVertex(G, add)) {
		printf("图中已经存在该顶点,插入失败\n");
	}
	else {
		printf3(G);//输出图G中顶点信息,检验插入是否成功
	}
	*/
	/*scanf("%c", &ch);//处理换行符
	VertexType v, w;
	scanf("%c %c", &v, &w);
	int v1 = getIndex(G, v);
	int w1 = getIndex(G, w);
	if (!delectArc(G, v, w)) {
		printf("不存在<%c,%c>的弧,删除失败\n", v, w);
		}
	else {
		if (!Adjacent(G, v1, w1)) {
			printf("删除成功\n");
		}
	}
	if (G.kind == 0) {//无向图则还需要删除<y,x>的弧
		{
			if (!delectArc(G, w, v)) {
				printf("不存在<%c,%c>的弧,删除失败\n", w, v);
			}
			else {
				if (Adjacent(G, w1, v1)) {
					printf("删除成功\n", v, w);
				}
			}
		}
	}
	*/
	/*scanf("%c", &ch);//处理换行符
	VertexType del;
	scanf("%c", &del);
	if (!delectVertex(G, del)) {
		printf("不存在%c这个结点,删除失败\n", del);
	}
	else {
		printf3(G);//输出图G中顶点信息,检验删除是否成功
	}*/

	scanf("%c", &ch);//处理换行符
	VertexType arc1, arc2;
	scanf("%c %c", &arc1, &arc2);
	int v2 = getIndex(G, arc1);
	int w2 = getIndex(G, arc2);
	if (!insertArc(G, arc1, arc2)) {
		printf("弧已经存在,插入弧<%c,%c>失败\n", arc1, arc2);
	}
	else {
		if (Adjacent(G, v2, w2))//判断图G中是否存在弧<v,w>
		{
			printf("插入<%c,%c>的弧成功\n", G.vertices[v2].data, G.vertices[w2]);
		}
	}
	if (G.kind == 0) {//无向图,还需要另外插入<arc2,arc1>
		if (!insertArc(G, arc2, arc1)) {
			printf("弧已经存在,插入弧<%c,%c>失败\n", arc2, arc1);
		}
		else {
			if (Adjacent(G, w2, v2))//判断图G中是否存在弧<v,w>
			{
				printf("插入<%c,%c>的弧成功\n", G.vertices[w2].data, G.vertices[v2]);
			}
		}
	}
	return 0;
}

(4)测试样例如下:

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值