C语言数据结构 图 数组表示法 邻接表 以及用邻接表实现图的基础操作(删除添加顶点和弧,深度优先遍历等)

IDE:Visual Studio 2019
声明:为了方便书写代码,用到了C++的引用调用特性和iostream作为输入输出,读者可以使用指针调用和scanf_s/print语句实现相同效果
tips:有疑问可以在下面交流,我会尽量回复的

头文件heads.h

#pragma once
#include "stdio.h"
#include "iostream"
#define OK 1
#define TRUE 1
#define FALSE 0
#define ERROR 0
#define OVERFLOW -1
using namespace std;
typedef short int Status;

头文件Graph.h

#include "heads.h"
typedef int VRType;//顶点关系类型
typedef int InfoType;//弧相关信息
typedef int VertexType;//顶点信息
enum GraphKind{ DG, DN, UDG, UDN };
//数组表示法
#define INFINITY INT_MAX;
#define MAX_VERTEX_NUM 20
typedef struct ArcCell {
	VRType adj;
	InfoType* info;
}AreCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
	VertexType vexs[MAX_VERTEX_NUM];
	AdjMatrix arcs;
	int vexnum, arcnum;//图当前顶点数和弧数
	enum GraphKind Kind;
}MGraph;
//MGraph
//创造邻接矩阵
Status CreateMGraph(MGraph& G);
//邻接表
typedef struct ArcNode {
	int adjvex;
	struct ArcNode* nextarc;
	InfoType* info;
}ArcNode,*Arc;
typedef struct VNode {
	VertexType data;
	ArcNode* firstarc;
}VNode,AdjList[MAX_VERTEX_NUM];
typedef struct {
	AdjList vertices;
	int vexnum, arcnum;
	enum GraphKind Kind;
}AlGraph;
//结点在图中的定位
int LocateVex(AlGraph G, VertexType e);
//创建邻接表
Status CreateAlGraph(AlGraph& G);
//删除邻接表
Status DestoryAlGraph(AlGraph& G);
//顶点赋值 
Status PutVex(AlGraph& G, int i, VertexType e);
//返回第一个邻接点
int FirstAdjVex(AlGraph G, int v);
//返回下一个邻接点
int NextAdjVex(AlGraph G, int v, int w);
//增加结点
Status InsertVex(AlGraph& G, VertexType e);
//删除结点和依附的弧
Status DeleteVex(AlGraph& G, VertexType e);
//插入弧
Status InsertArc(AlGraph& G, int v, int w, InfoType e);
//删除弧
Status DeleteArc(AlGraph& G, int v, int w);
//深度优先遍历
Status visit(AlGraph G, int v);
void DFS(AlGraph G, int v);
void DFSTraverse(AlGraph G, Status(*visit)(AlGraph G, int v));

源文件ALGraph.cpp

#include "Graph.h"
bool visited[MAX_VERTEX_NUM];
Status(*VisitFunc)(AlGraph G, int v);
//弧的初始化
Status InitArc(AlGraph &G,int a,int b,InfoType e) {
	Arc q=G.vertices[a].firstarc;
	Arc p = (Arc)malloc(sizeof(ArcNode));
	p->info = (InfoType*)malloc(sizeof(InfoType));
	if (!p)return ERROR;
	p->nextarc = NULL;
	*(p->info) = e;
	p->adjvex = b;
	if (q == NULL) {
		G.vertices[a].firstarc = p;
	}
	else {
		while (q->nextarc)q = q->nextarc;
		q->nextarc = p;
	}
	return OK;
}//InitArc
//结点在图中的定位
int LocateVex(AlGraph G, VertexType e) {
	int i = 0;
	for (; i < G.vexnum; i++) {
		if (e == G.vertices[i].data)break;
	}
	return i;
}//LocateVex
//创建有向网
Status CreateDNAlGraph(AlGraph& G) {
	cout << "有向网图开始初始化..." << endl;
	VertexType v1, v2;
	VRType w;
	int i, j;
	cout << "依次输入顶点数,弧数" << endl;
	cin >> G.vexnum >> G.arcnum;
	for (i = 0; i < G.vexnum; ++i) {
		cout << "输入第" << i + 1 << "个顶点的元素" << endl;
		cin >> G.vertices[i].data;
		G.vertices[i].firstarc = NULL;
	}
	for (int k = 0; k < G.arcnum; k++) {
		cout << "依次输入第" << k + 1 << "条弧依附的两个顶点的元素以及弧的权值" << endl;
		cin >> v1 >> v2 >> w;
		i = LocateVex(G, v1); j = LocateVex(G, v2);
		InitArc(G, i, j, w);
	}
	return OK;
}//CreateDNAlGraph
//创建邻接表
Status CreateAlGraph(AlGraph& G) {
	cout << "请输入邻接表的样式" << endl;
	scanf_s("%u", &G.Kind);
	switch (G.Kind)
	{
	case DN:return CreateDNAlGraph(G);
	case UDN:break;
	default:return ERROR;
	}
}//CreateAlGraph
//删除邻接表
Status DestoryAlGraph(AlGraph& G) {
	for (int i = 0; i < G.vexnum; ++i) {
		Arc p = G.vertices[i].firstarc, q = p->nextarc;
		if (p == NULL)continue;
		while (p) {
			free(p->info);
			free(p);
			p = q;
			if(q->nextarc)q = q->nextarc;
		}
	}
	free(&G);
	return OK;
}//DeatoryAlGraph
//顶点赋值 
Status PutVex(AlGraph& G, int i, VertexType e) {
	G.vertices[i].data = e;
	return OK;
}//PutVex
//返回第一个邻接点
int FirstAdjVex(AlGraph G, int v) {
	if (G.vertices[v].firstarc)return G.vertices[v].firstarc->adjvex;
	return -1;
}//FirstAdjVex
//返回下一个邻接点
int NextAdjVex(AlGraph G, int v, int w) {
	Arc p = G.vertices[v].firstarc;
	while (p) {
		if (p->adjvex == w)break;
		p = p->nextarc;
	}
	if (p == NULL || p->nextarc == NULL)return -1;
	return p->nextarc->adjvex;
}//NextAdjVex
//增加结点
Status InsertVex(AlGraph& G, VertexType e) {
	G.vertices[G.vexnum].data = e;
	G.vertices[G.vexnum].firstarc = NULL;
	G.vexnum++;
	return OK;
}//InsertVex
//删除结点和依附的弧
Status DeleteVex(AlGraph& G, VertexType e) {
	int i = LocateVex(G, e), j = 0;
	Arc p = G.vertices[i].firstarc, q = p;
	G.vertices[i].firstarc = NULL;
	while (p) {
		q = p->nextarc;
		free(p->info);
		free(p);
		p = q;
		j++;
	}
	for (int z = i; z < G.vexnum; z++) {
		G.vertices[z].data = G.vertices[z + 1].data;
		G.vertices[z].firstarc = G.vertices[z + 1].firstarc;
	}
	G.vexnum--;
	for (int z = 0; z < G.vexnum; z++) {
		p=G.vertices[z].firstarc;
		if (p) {
			if (p->adjvex == i) {
				G.vertices[z].firstarc = p->nextarc;
				free(p->info);
				free(p);
				j++;
				p = G.vertices[z].firstarc;
			}
			while (p) {
				if (p->adjvex == i) {
					q->nextarc = p->nextarc;
					free(p->info);
					free(p);
					j++;
					p = q->nextarc;
					continue;
				}
				if (p->adjvex > i) {
					p->adjvex--;
				}
				q = p;
				p = p->nextarc;
			}
		}
	}
	G.arcnum -= j;
	return OK;
}//DeleteVex
//插入弧
Status InsertArc(AlGraph& G, int v, int w,InfoType e){
	InitArc(G, v, w, e);
	++G.arcnum;
	return OK;
}//InsertArc
//删除弧
Status DeleteArc(AlGraph& G, int v, int w) {
	int a, b;
	a = LocateVex(G, v);
	b = LocateVex(G, w);
	Arc p = G.vertices[a].firstarc, q = p;
	if (G.vertices[a].firstarc->adjvex == b) {
		G.vertices[a].firstarc = p->nextarc;
		free(p->info);
		free(p);
		G.arcnum--;
		return OK;
	}
	else {
		while (p) {
			if (p->adjvex == b) {
				q->nextarc = p->nextarc;
				free(p->info);
				free(p);
				G.arcnum--;
				return OK;
			}
			q = p;
			p = p->nextarc;
		}
	}
	return ERROR;
}//DeleteArc
//深度优先遍历
Status visit(AlGraph G, int v) {
	cout<<G.vertices[v].data<<" ";
	return OK;
}
void DFS(AlGraph G, int v) {
	visited[v] = TRUE; VisitFunc(G, v);
	for (int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
		if (!visited[w])DFS(G, w);
	}
}
void DFSTraverse(AlGraph G, Status(*visit)(AlGraph G, int v)) {
	VisitFunc = visit;
	for (int v = 0; v < G.vexnum; ++v)visited[v] = FALSE;
	for (int v = 0; v < G.vexnum; v++) {
		if (!visited[v])DFS(G, v);
	}
	cout << endl;
}//DFSTraverse

MGraph.cpp

#include "Graph.h"
//结点在图中的定位
int LocateVex(MGraph G, VertexType e) {
	int i = 0;
	for (; i < G.vexnum; i++) {
		if (e == G.vexs[i])break;
	}
	return i;
}
//弧相关信息输入
void Input(InfoType &e) {
	cin >> e;
}
//无向网图的初始化
Status CreateMUDG(MGraph& G) {
	cout << "无向网图开始初始化..." << endl;
	bool IncInfo;
	VertexType v1, v2;
	VRType w;
	int i, j;
	cout << "依次输入顶点数,弧数以及是否有弧的相关信息" << endl;
	cin >> G.vexnum >> G.arcnum >> IncInfo;
	for (i = 0; i < G.vexnum; ++i) {
		cout << "输入第"<<i+1<<"个顶点的元素" << endl;
		cin >> G.vexs[i];
	}
	for (i = 0; i < G.vexnum; i++) {
		for (int j = 0; j < G.vexnum; j++) {
			G.arcs[i][j].adj = INFINITY;
			G.arcs[i][j].info = NULL;
		}
	}
	for (int k = 0; k < G.arcnum; k++) {
		cout << "依次输入第"<<k+1<<"条弧依附的两个顶点的元素以及弧的权值" << endl;
		cin >> v1 >> v2 >> w;
		i = LocateVex(G, v1); j = LocateVex(G, v2);
		G.arcs[i][j].adj = w;
		if (IncInfo)Input(*G.arcs[i][j].info);
		G.arcs[j][i] = G.arcs[i][j];
	}
	return OK;
}//CreateMUDG
//创造邻接矩阵
Status CreateMGraph(MGraph& G) {
	cout << "输入矩阵类型,0:有向图;1:有向网;2:无向图;3:无向网;" << endl;
	scanf_s("%u", &G.Kind);
	switch(G.Kind)
	{
	//case DG:return CreateMDG(G);
	//case DN:return CreateMDN(G);
	//case UDG:return CreateMUDG(G);
	case UDN:return CreateMUDG(G);
	default:return ERROR;
	}
}//CreateMGraph

Main.cpp

#include "Graph.h"
int main(void) {
	AlGraph G;
	CreateAlGraph(G);
	DFSTraverse(G, visit);
	DeleteVex(G, 8);
	DFSTraverse(G, visit);
	DeleteArc(G, 4, 6);
	DFSTraverse(G, visit);
	InsertVex(G, 1);
	InsertArc(G, 1, 6, 1);
	DFSTraverse(G, visit);
}

结果

结果
指针!指针!还是指针!
注意从顶点元素到元素在邻接表数组内的下标的映射

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮你回答这个问题。 首先,我们需要定义数据结构。采用邻接表表示法,可以使用以下结构体来存储一个无向网 G: ```c #define MAX_VERTEX_NUM 100 typedef struct ArcNode { int adjvex; // 邻接点下标 int weight; // 权值 struct ArcNode *nextarc; // 指向下一条边的指针 } ArcNode; typedef struct VNode { char data; // 顶点数据 ArcNode *firstarc; // 指向第一条边的指针 } VNode, AdjList[MAX_VERTEX_NUM]; typedef struct { AdjList vertices; // 邻接表 int vexnum, arcnum; // 顶点数和边数 } ALGraph; ``` 接下来,我们可以编写一个函数来构造 G。假设顶点数据为字符型,边权值为整型,则可以使用以下函数来构造 G: ```c void CreateGraph(ALGraph *G) { printf("Enter the number of vertices and edges: "); scanf("%d%d", &G->vexnum, &G->arcnum); getchar(); // 消耗多余的换行符 printf("Enter the vertices (one character each):\n"); for (int i = 0; i < G->vexnum; ++i) { scanf("%c", &G->vertices[i].data); G->vertices[i].firstarc = NULL; } getchar(); // 消耗多余的换行符 printf("Enter the edges (format: Vi Vj W):\n"); for (int k = 0; k < G->arcnum; ++k) { int i, j, w; scanf("%d%d%d", &i, &j, &w); ArcNode *p = (ArcNode *)malloc(sizeof(ArcNode)); p->adjvex = j; p->weight = w; p->nextarc = G->vertices[i].firstarc; G->vertices[i].firstarc = p; p = (ArcNode *)malloc(sizeof(ArcNode)); p->adjvex = i; p->weight = w; p->nextarc = G->vertices[j].firstarc; G->vertices[j].firstarc = p; } } ``` 现在,我们可以编写一个递归的深度优先遍历函数来遍历 G。假设起始顶点下标为 v,则可以使用以下函数来递归地深度优先遍历 G: ```c void DFS(ALGraph *G, int v, int *visited) { printf("%c ", G->vertices[v].data); visited[v] = 1; ArcNode *p = G->vertices[v].firstarc; while (p != NULL) { int w = p->adjvex; if (!visited[w]) { DFS(G, w, visited); } p = p->nextarc; } } ``` 最后,我们可以在主函数中调用上述函数来构造 G 并进行深度优先遍历。例如,下面的代码将从第一个顶点开始遍历 G: ```c int main() { ALGraph G; CreateGraph(&G); int visited[MAX_VERTEX_NUM] = {0}; printf("Depth-first order: "); DFS(&G, 0, visited); return 0; } ``` 希望这个例子能够帮助你了解如何使用 C 语言构造并进行深度优先遍历

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值