【数据结构(C语言)】图论

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<time.h>
#define ERROR 0
#define OK 1
#define Overflow 2      //上溢
#define Underflow 3     //下溢
#define NotPresent 4    //元素不存在
#define Duplicate 5     //有重复元素
#define INFTY 10000     //路径的长度初始值
typedef int Status;
typedef int ElemType;
/***********************************************************************邻接矩阵的实现****************************************************************/
/*定义图结构体*/
typedef struct mGraph
{
	ElemType **a;       //邻接矩阵
	int n;              //图的当前顶点数
	int e;              //图的当前边数
	int noEdge;         //两顶点间无边时的值
}MGraph;
/*初始化*/
Status Init(MGraph *mg, int nSize, ElemType noEdgeValue)
{
	mg->n = nSize;
	mg->noEdge = noEdgeValue;
	mg->e = 0;
	mg->a = (ElemType**)malloc(nSize * sizeof(ElemType*));
	if (!(mg->a))  return ERROR;
	for (int i = 0; i < nSize; i++)                 //初始化邻接矩阵
	{
		mg->a[i] = (ElemType*)malloc(nSize * sizeof(ElemType));
		for (int j = 0; j < mg->n; mg->a[i][j++] = mg->noEdge);        
		mg->a[i][i] = 0;
	}
	return OK;
}
/*撤销*/
void Destory(MGraph *mg)
{
	for (int i = 0; i < mg->n; free(mg->a[i++]));    //释放n个一维数组的存储空间
	free(mg->a);                                     //释放一维指针数组的存储空间
}
/*查*/
Status Exist(MGraph *mg, int u, int v)
{
	if (u<0 || v<0 || u>mg->n - 1 || v>mg->n - 1 || u == v || mg->a[u][v] == mg->noEdge) return ERROR;
	return OK;
}
/*增*/
Status Insert(MGraph *mg, int u, int v, ElemType w)
{
	if (u<0 || v<0 || u>mg->n - 1 || v>mg->n - 1 || u == v ) return ERROR;   //验证插入位置
	if (mg->a[u][v] != mg->noEdge) return Duplicate;                         //验证插入边是否已存在
	mg->a[u][v] = w;                                                         //插入新边
	mg->e++;                                                                 //边数自增1
	return OK;
}
/*删*/
Status Remove(MGraph *mg,int u,int v)
{
	if (u<0 || v<0 || u>mg->n - 1 || v>mg->n - 1 || u == v) return ERROR;     //验证删除位置
	if (mg->a[u][v] == mg->noEdge) return NotPresent;                         //验证删除边是否存在
	mg->a[u][v] = mg->noEdge;                                                 //删除边
	mg->e--;                                                                  //边数自减1
	return OK;
}
/*DFS深度优先遍历*/
void DFS(int v, int visited[], MGraph *mg)
{
	printf("%d ", v);
	visited[v] = 1;                          //给访问过的顶点打标记
	for (int i = 0; i < (mg->n); i++)
		if (Exist(mg, v, i) && visited[i] == 0)
			DFS(i, visited, mg);            //递归调用
}
void DFSGraph(MGraph *mg)
{
	int *visited = (int *)malloc((mg->n) * sizeof(int));//动态创建标记数组的空间
	for (int i = 0; i < mg->n; visited[i++] = 0);   //初始化标记数组
	for (int i = 0; i < mg->n; i++)
		if (!visited[i])
			DFS(i, visited, mg);                    //更新起始遍历的顶点
	free(visited);                                  //释放临时空间
	printf("\n");
}
/*BFS宽度优先遍历*/
typedef struct queue    //队列结构体定义
{
	int front;          //队列首部元素的序号
	int rear;           //队列尾部元素的序号
	int maxSize;        //队列容纳的最大值
	ElemType *element;  //队列元素组成的数组
}Queue;
void Create(Queue *Q, int mSize)//队列初始化
{
	Q->maxSize = mSize;
	Q->front = Q->rear = 0;
	Q->element = (ElemType *)malloc(sizeof(ElemType)*mSize);
}
void DestoryQueue(Queue *Q)//队列撤销
{
	Q->maxSize = 0;
	free(Q->element);
	Q->rear = Q->front = 0;
}
int IsEmpty(Queue *Q)//判断队列是否为空
{
	return Q->front == Q->rear;
}
int IsFULL(Queue *Q)//判断队列是否已满
{
	return (Q->rear + 1) % Q->maxSize == Q->front;
}
Status EnQueue(Queue *Q, ElemType *x)//入队
{
	if (IsFULL(Q))  return ERROR;           //判断是否溢出
	Q->rear = (Q->rear + 1) % Q->maxSize;   //更新队尾元素序号
	Q->element[Q->rear] = x;                //插入的元素存入数组
	return OK;
}
Status DeQueue(Queue *Q)//出队
{
	if (IsEmpty(Q))  return ERROR;
	Q->front = (Q->front + 1) % Q->maxSize; //更新队头元素序号
	return OK;
}
Status Front(Queue *Q, ElemType *x)//获取队头元素
{
	if (IsEmpty(Q))  return ERROR;
	*x = Q->element[(Q->front + 1) % Q->maxSize];
	return OK;
}
void BFS(int v, int visited[], MGraph *mg)
{
	Queue q;
	Create(&q, mg->n);
	printf("%d ", v);
	visited[v] = 1;
	EnQueue(&q, v);
	while (!IsEmpty(&q))                       
	{
		Front(&q, &v);
		DeQueue(&q);
		for (int i = 0; Exist(mg, v, i); i++)   //遍历序号为v的顶点的所有邻接点
		{
			if (!visited[i])                    //如果某邻接点未被访问就入队,作为本轮循环之后的循环的队头元素
			{
				visited[i] = 1;
				printf("%d ", i);
				EnQueue(&q, i);
			}
		}
	}
}
void BFSGraph(MGraph *mg)
{
	int *visited = (int *)malloc((mg->n) * sizeof(int));//动态创建标记数组的空间
	for (int i = 0; i < mg->n; visited[i++] = 0);   //初始化标记数组
	for (int i = 0; i < mg->n; i++)
		if (!visited[i])  BFS(i, visited, mg);
	free(visited);
}
/***********************************************************************邻接表的实现*****************************************************************/
/*定义边结点结构体*/
typedef struct eNode  
{
	int adjVex;              //与任意顶点u相邻接的顶点
	ElemType w;              //边的权值
	struct eNode* nextArc;   //指向下一个边结点
}ENode;
/*定义图结构体*/
typedef struct lGraph  
{
	int n;                   //图当前结点数
	int e;                   //图当前边数
	ENode **a;               
}LGraph;
/*初始化*/
Status Init1(LGraph *lg, int nSize)
{
	lg->n = nSize;
	lg->e = 0;
	lg->a = (ENode**)malloc(sizeof(ENode*)*nSize);
	if (!lg->a)  return ERROR;
	else
	{
		for (int i = 0; i < lg->n; i++) lg->a[i] = NULL;
		return OK;
	}
}
/*撤销*/
void Destory1(LGraph *lg)
{
	ENode *p, *q;
	for (int i = 0; i < lg->n; i++)
	{
		p = lg->a[i];            //p指向顶点i的单链表的第一个边结点
		q = p;                   
		while (p)                //释放顶点i的单链表中的所有边结点
		{
			p = p->nextArc;
			free(p);
			q = p;
		}
	}
	free(lg->a);                  //释放一维数组指针的空间
}
/*查*/
Status Exist1(LGraph *lg, int u, int v)
{
	ENode *p;
	if (u<0 || v<0 || u>lg->n - 1 || v>lg->n - 1 || u == v)  return ERROR;
	p = lg->a[u];
	while (p&&p->adjVex != v) p = p->nextArc;
	if (!p) return ERROR;
	return OK;
}
/*插入以u(起始),v(中止)为顶点权值为w的边*/
Status Insert1(LGraph *lg,int u,int v,ElemType w)
{
	ENode *p;
	if(u<0 || v<0 || u>lg->n - 1 || v>lg->n - 1 || u == v)  return ERROR;
	if (Exist(lg, u, v)) return Duplicate;
	p = (ENode *)malloc(sizeof(ENode));
	/*新结点的初始化*/
	p->adjVex = v;                    
	p->w = w;
	/*插入操作*/
	p->nextArc = lg->a[u];    //新结点插入单链表最前面
	lg->a[u] = p;  
	/*数目更新*/
	lg->e++;
	return OK;
}
/*删*/
Status Remove1(LGraph *lg, int u, int v)
{
	ENode *p, *q;
	if (u<0 || v<0 || u>lg->n - 1 || v>lg->n - 1 || u == v)  return ERROR;
	p = lg->a[u], q = NULL;
	while (p&&p->adjVex != v)        //搜索以验证是否存在删除边
	{ 
		q = p;
		p = p->nextArc;
	}
	if (!p) return NotPresent;        //p为空则不存在待删除边
	if (q) q->nextArc = p->nextArc;   //从单链表中删除该边
	else lg->a[u] = p->nextArc;
	free(p);
	lg->e--;
	return OK;
}
/*DFS深度优先遍历*/
void DFS1(int v, int visited[], LGraph *lg)
{
	ENode *w;
	printf("%d ", v);
	visited[v] = 1;                          //给访问过的顶点打标记
	for (w = lg->a[v]; w; w = w->nextArc)
		if (!visited[w->adjVex])
			DFS(w->adjVex, visited, lg);
}
void DFSGraph1(LGraph *lg)
{
	int *visited = (int *)malloc((lg->n) * sizeof(int));//动态创建标记数组的空间
	for (int i = 0; i < lg->n; visited[i++] = 0);       //初始化标记数组
	for (int i = 0; i < lg->n; i++)
		if (!visited[i]) DFS(i, visited, lg);          //更新起始遍历的顶点
	free(visited);                                      //释放临时空间
}
/*BFS宽度优先遍历*/
void BFS1(int v, int visited[], LGraph *lg)
{
	ENode *w;
	Queue q;
	Create(&q, lg->n);
	printf("%d ", v);
	visited[v] = 1;
	EnQueue(&q, v);
	while (!IsEmpty(&q))
	{
		Front(&q, &v);
		DeQueue(&q);
		for (w = lg->a[v]; w;w=w->nextArc)   //遍历序号为v的顶点的所有邻接点
		{
			if (!visited[w->adjVex])        //如果某邻接点未被访问就入队,作为本轮循环之后的循环的队头元素
			{
				visited[w->adjVex] = 1;
				printf("%d ", w->adjVex);
				EnQueue(&q, w->adjVex);
			}
		}
	}
}
void BFSGraph1(LGraph *lg)
{
	int *visited = (int *)malloc((lg->n) * sizeof(int));//动态创建标记数组的空间
	for (int i = 0; i < lg->n; visited[i++] = 0);   //初始化标记数组
	for (int i = 0; i < lg->n; i++)
		if (!visited[i])  BFS(i, visited, lg);
	free(visited);
}
/***********************************************************************智能交通*********************************************************************/
int Choose(int *d, int *s, int n)
{
	ElemType min=INFTY;  //最小路径长度初始化为INITY
	int minpos=-1;       //前驱结点初始化序号为-1
	for (int i = 0; i < n; i++)    //选出最短的d[i]
		if (d[i] < min && !s[i])
		{
			min = d[i];
			minpos = i;
		}
	return minpos;       //返回序号
}
Status Dijkstra(int v,int u,MGraph *mg)
{
	int k, *s = (int*)malloc((mg->n) * sizeof(int)),*path= (int*)malloc((mg->n) * sizeof(int));
	ElemType *d = (ElemType*)malloc((mg->n) * sizeof(ElemType)), pass[20] = {0};
	if (v<0 || v>mg->n - 1)
		return ERROR;
	for (int i = 0; i < mg->n; i++)                  //初始化
	{
		s[i] = 0;                                    //s数组记录最短路径的确定状态
		d[i] = mg->a[v][i];                          //d数组存储v到下标对应序号的顶点的最短路径长度,如d[i]代表v到i的最短路径的长度
		//printf("%d ", d[i]);
		if (i != v && d[i] < INFTY) path[i] = v;     //设置前驱结点
		else path[i] = -1;                           //无前驱结点的值是-1
	}
	s[v] = -1;                                       
	d[v] = 0;                                        //v顶点到v顶点的距离是0
	for (int i = 1; i < mg->n-1; i++)
	{
		k = Choose(d, s, mg->n);                     //选出当前最短的d[i],并获取下标
		if (k == -1) continue; 
		s[k] = 1;
		for(int j=0;j<mg->n;j++)                     //每一轮外循环都要进行一次内循环来更新d和path
			if (!s[j] && d[k] + mg->a[k][j] < d[j])
			{
				d[j] = d[k] + mg->a[k][j];
				path[j] = k;
			}
	}
	k = 0;
	printf(">>>从%d号地点到%d号地点的最短路径是:", v, u);        //把路径输出
	for (int i = u; i != v; i = path[i])  pass[k++]=i;
	for(;k>0;k--)  printf("%d -> ", pass[k]);
	printf("%d", u);

	printf("\n>>>最短距离是:%d\n", d[u]);                      //最短距离输出
	free(s);                                                   //释放动态空间
	free(path); 
	free(d);
	return OK;
}
int main()
{
	MGraph *mg = (MGraph*)malloc(sizeof(MGraph));
	LGraph *lg = (LGraph*)malloc(sizeof(LGraph));
	int nSize = 0,
		noEdgeValue = 0,
		u, v, w, operation = 0;
	char judge,tmpbuf[] = { 0 };
	_tzset();                             // 初始化时区
	_strdate(tmpbuf);
	printf("当前时间: %s\n", tmpbuf);
	system("title MADE BY YQC");
label:
	printf("*1.邻接矩阵实现图\n*2.邻接表实现图\n*3.智能交通\n——请选择:");
	scanf("%d", &operation);
	switch (operation)
	{
	case 1:
		system("CLS");
		while (1)
		{
			u = 0; v = 0;
			printf("###请输入你要进行的操作(1.初始化 2.搜索 3.插入 4.删除 5.撤销 6.退出程序 7.DFS 8.BFS 9.返回首页):");
			scanf("%d", &operation);
			switch (operation)
			{
			case 1:
				printf("请输入要创建的顶点数目:");
				scanf("%d", &nSize);
				if (Init(mg, nSize, noEdgeValue))  printf("初始化成功……\n");
				else printf("WARNING:初始化失败\n");
				break;
			case 2:
				printf("请输入起始顶点的序号:");
				scanf("%d", &u);
				printf("请输入中止顶点的序号:");
				scanf("%d", &v);
				if (Exist(mg, u, v) == 1)  printf("从%d号顶点到%d号顶点存在边\n", u, v);
				else if (Exist(mg, u, v) == 4)
					printf("该边已经被删除");
				else printf("这两个结点不存在边\n");
				break;
			case 3:
				printf("请输入起始顶点的序号:");
				scanf("%d", &u);
				printf("请输入中止顶点的序号:");
				scanf("%d", &v);
				printf("请输入边的权值:");
				scanf("%d", &w);
				if (Insert(mg, u, v, w) == OK)  printf("插入成功\n");
				else if (Insert(mg, u, v, w) == Duplicate)  printf("已存在该边\n");
				else printf("WARNING:插入失败\n");
				break;
			case 4:
				printf("请输入起始顶点的序号:");
				scanf("%d", &u);
				printf("请输入中止顶点的序号:");
				scanf("%d", &v);
				if (Remove(mg, u, v)==OK)  printf("删除成功\n");
				else if (Remove(mg, u, v) == NotPresent)  printf("待删除边不存在\n");
				else printf("WARNING:删除失败\n");
				break;
			case 5:
				Destory(mg);
				break;
			case 6:
				exit(0);
			case 7:
				printf("深度遍历路径如下:\n");
				DFSGraph(mg);
				break;
			case 8:
				printf("宽度遍历路径如下:\n");
				BFSGraph(mg);
				printf("\n");
				break;
			case 9:
				while (1)
				{
					printf("当前图将会被注销,是否继续(Y/N):\n");
					scanf("%c", &judge);
					if (judge == 'y' || judge == 'Y')
					{
						system("CLS");
						if(mg->n)
							Destory(mg);
						goto label;
					}
					if (judge == 'n' || judge == 'N') break;
				}
				break;
			label1:
				break;
			default:
				printf("WARNING:输入异常!!!\n");
				break;
			}
		}
	case 2:
		system("CLS");
		while (1)
		{
			u = 0; v = 0;
			printf("###请输入你要进行的操作(1.初始化 2.搜索 3.插入 4.删除 5.撤销 6.退出程序 7.DFS 8.BFS 9.返回首页):");
			scanf("%d", &operation);
			switch (operation)
			{
			case 1:
				printf("请输入要创建的顶点数目:");
				scanf("%d", &nSize);
				if (Init1(lg, nSize))  printf("初始化成功……\n");
				else printf("WARNING:初始化失败\n");
				break;
			case 2:
				printf("请输入起始顶点的序号:");
				scanf("%d", &u);
				printf("请输入中止顶点的序号:");
				scanf("%d", &v);
				if (Exist1(lg, u, v) == 1)  printf("从%d号顶点到%d号顶点存在边\n", u, v);
				else printf("这两个结点不存在边\n");
				break;
			case 3:
				printf("请输入起始顶点的序号:");
				scanf("%d", &u);
				printf("请输入中止顶点的序号:");
				scanf("%d", &v);
				printf("请输入边的权值:");
				scanf("%d", &w);
				if (Insert1(lg, u, v, w)==OK)  printf("插入成功\n");
				else if (Insert1(lg, u, v, w) == Duplicate)  printf("已存在该边\n");
				else printf("WARNING:插入失败\n");
				break;
			case 4:
				printf("请输入起始顶点的序号:");
				scanf("%d", &u);
				printf("请输入中止顶点的序号:");
				scanf("%d", &v);
				if (Remove1(lg, u, v) == OK)  printf("删除成功\n");
				else if (Remove1(lg, u, v) == NotPresent)  printf("待删除边不存在\n");
				else printf("WARNING:删除失败\n");
				break;
			case 5:
				Destory1(lg);
				break;
			case 6:
				exit(0);
			case 7:
				printf("深度遍历路径如下:\n");
				DFSGraph1(lg);
				break;
			case 8:
				printf("宽度遍历路径如下:\n");
				BFSGraph1(lg);
				printf("\n");
				break;
			case 9:
				while (1)
				{
					printf("当前图将会被注销,是否继续(Y/N):\n");
					scanf("%c", &judge);
					if (judge == 'y' || judge == 'Y')
					{
						system("CLS");
						if (lg->a)
							Destory1(lg);
						goto label;
					}
					if (judge == 'n' || judge == 'N') break;
				}
				break;
			default:
				printf("WARNING:输入异常!!!\n");
				break;
			}
		}
	case 3:
		system("CLS");
	label3:
		printf(">在创建方案前需要获取一些数据~~~\n");
		printf(">请输入地点的数目:");
		scanf("%d", &nSize);
		if (Init(mg, nSize, INFTY))  printf(">初始化成功……\n");
		else printf(">WARNING:初始化失败\n");
		while (1)
		{
			printf("  1.插入路径\n  2.计算最短路径\n  3.显示当前图\n  4.重新初始化\n>>请选择你要进行的操作:");
			scanf("%d", &operation);
			switch (operation)
			{
			case 1:
				system("CLS");
				printf(">>>请输入起始地点的序号:");
				scanf("%d", &u);
				printf(">>>请输入中止地点的序号:");
				scanf("%d", &v);
				printf(">>>请输入两地点间的距离(km):");
				scanf("%d", &w);
				if (Insert(mg, u, v, w) == OK)  printf("——新添加从%d号地点到%d号地点的路径\n",u,v);
				else if (Insert(mg, u, v, w) == Duplicate)  printf("——已存在该路径\n");
				else printf("——WARNING:添加失败\n");
				break;
			case 2:
				system("CLS");
				printf("请输入起点的序号:");
				scanf("%d", &v);
				printf("请输入终点的序号:");
				scanf("%d", &u);
				Dijkstra(v, u, mg);
				break;
			case 3:
				system("CLS");
				printf("当前图遍历如下:\n");
				DFSGraph(mg);
				break;
			case 4:
				system("CLS");
				while (1)
				{
					printf("当前图将会被注销,是否继续(Y/N):\n");
					scanf("%c", &judge);
					if (judge == 'y' || judge == 'Y')
					{
						system("CLS");
						Destory(mg);
						goto label3;
					}
					if (judge == 'n' || judge == 'N') break;
				}
				break;
			default:
				system("CLS");
				printf("WARNING:输入异常!!!请输入合理代号\n");
				break;
			}
		}
	default:
		printf("WARNING:输入异常!!!\n");
		break;
	}
	return 0;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
数据结构是计算机科学中的一门重要基础课程,也是程序员必备的技能之一。数据结构主要研究数据的组织、存储和管理方式,以及对数据进行操作的算法和技巧。针对题目中的C语言版微课版答案,我将简要介绍一下相关内容。 首先,基本数据结构包括线性表、栈、队列、树、图等。线性表是最基本的数据结构,它包括顺序表和链表两种实现方式。顺序表通过数组实现,可以随机访问元素;链表则通过指针实现,适合频繁插入和删除操作。栈是一种先进后出的数据结构,常用于实现函数调用栈、表达式求值等场景。队列是一种先进先出的数据结构,常用于实现任务调度、消息队列等场景。树是由节点和边组成的非线性数据结构,常用于实现二叉树、平衡树、堆等。图是由边和节点组成的非线性数据结构,常用于解决图论问题。 其次,常用的数据结构算法包括查找、排序、图算法等。线性表的查找算法包括顺序查找和二分查找,前者按顺序逐个比较元素,后者通过二分法快速缩小查找范围。排序算法包括冒泡排序、插入排序、选择排序、快速排序、归并排序等,每种算法都有其适用的场景和优化策略。图算法包括广度优先搜索、深度优先搜索、最短路径算法、最小生成树算法等,用于解决与图相关的问题。 最后,C语言是一门广泛应用于系统编程的高级编程语言,也是实现数据结构和算法的常用语言。通过C语言可以实现各种数据结构,例如使用结构体实现链表、使用数组实现栈和队列等。同时,C语言提供了丰富的库函数和操作符,使得实现和操作数据结构变得更加便捷和高效。 综上所述,数据结构C语言版微课版答案主要涵盖了基本数据结构、常用算法以及使用C语言实现数据结构和算法的能力。掌握这些知识和技能,对于进一步学习和应用计算机科学领域具有重要意义。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Em0s_Er1t

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值