数据结构实践大作业(城市网点建设)

目录

1.题目

2.功能思维导图

3.网点图

5.函数调用关系

6.案例代码

7.代码测试


1.题目

问题描述:在几个城市之间建设网络(不少于15个),只需要保证联通即可,求最经济的架设方案

具体要求如下:

  1. 创建图:从文件中读入图的数据信息
  2. 管理图:增加新的城市结点,增加一条网络,删除一个城市结点(只有没有网络连线的城市才能删除),删除一条网络连线,保存图的信息到文件
  3. 利用prim或kruscal算法得到最小生成树
  4. 设计界面实现图以及最小生成树(加分项)

2.功能思维导图

3.网点图

4.流程图

5.函数调用关系

 

6.案例代码

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

#define MaxVertices 100 //假设包含100个顶点
#define MaxWeight 32767 //不邻接时为32767,但输出时用 "∞"
#define MAX_PASSWORD_LENGTH 20
#define MAX_SIZE 100
#define V 15

typedef struct { //包含权的邻接矩阵的的定义
	int Vertices[MaxVertices];  //顶点信息的数组
	int Edge[MaxVertices][MaxVertices]; //边的权信息的数组
	int numV; //当前的顶点数
	int numE; //当前的边数
}AdjMatrix;

void CreateGraph(AdjMatrix* G) //图的生成函数
{
	int spot[99] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
	int v1[99] = { 1,1,2,3,5,5,6,6,8,10,10,11,13,14 };
	int v2[99] = { 2,3,4,5,7,6,8,9,11,12,11,13,14,15 };
	int weight[15] = { 3,5,4,2,1,4,3,2,2,2,4,1,2,4 };
	int n, e, vi, vj, w, i, j;
	n = 15; e = 14;

	G->numV = n; G->numE = e;

	for (i = 0; i < n; i++) //图的初始化
		for (j = 0; j < n; j++) {
			if (i == j)
				G->Edge[i][j] = 0;
			else
				G->Edge[i][j] = MaxWeight;
		}

	for (i = 0; i < G->numV; i++) //将顶点存入数组中
		G->Vertices[i] = spot[i];

	printf("\n");

	for (i = 0; i < G->numE; i++) {
		vi = v1[i];
		vj = v2[i];
		w = weight[i];

		G->Edge[vi - 1][vj - 1] = w;//①
		G->Edge[vj - 1][vi - 1] = w;//②
	}
}

void DispGraph(AdjMatrix G) //输出邻接矩阵的信息
{
	int i, j;
	printf("\n输出顶点的信息(整型):\n");
	for (i = 0; i < G.numV; i++)
		printf("%8d", G.Vertices[i]);
	printf("\n");
	printf("\n输出邻接矩阵:\n");
	printf("\t");
	for (i = 0; i < G.numV; i++)
		printf("%8d", G.Vertices[i]);

	for (i = 0; i < G.numV; i++)
	{
		printf("\n%8d", i + 1);
		for (j = 0; j < G.numV; j++)
		{
			if (G.Edge[i][j] == 32767)
				//两点之间无连接时权值为默认的32767,
			
				printf("%8s", "∞");
			else
				printf("%8d", G.Edge[i][j]);
		}
		printf("\n");
	}
}
//查找节点信息函数
void SearchNet(AdjMatrix G) {
	int net;
	CreateGraph(&G);
	printf("请输入想要查询的网点:\n");
	scanf_s("%d",&net);
	printf("您输入的站点是%d\n", net);
	if (net == 1 || net == 2 || net ==3)
	{
		printf("所属城市---深圳\n");
	}
	else if (net == 4 || net == 5 || net == 6)
	{
		printf("所属城市---东莞\n");
	}
	else if (net == 7 || net == 8 || net == 9)
	{
		printf("所属城市---汕头\n");
	}
	else if (net == 10 || net == 11 || net == 12)
	{
		printf("所属城市---揭阳\n");
	}
	else if (net == 13 || net == 14 || net == 15)
	{
		printf("所属城市---广州\n");
	}
	else
	{
		printf("输入有误请重新输入");
		SearchNet(G);
	}
	
	net--;
	for (int i = 0; i < V-1; i++)
	{
		if (G.Edge[net][i]>0 && G.Edge[net][i]<32767)
		{
			printf("相邻网点");
			printf("%d", i+1);
			printf(" ");
			printf("站点距离为%dkm",G.Edge[net][i]);
			printf("\n");

		}
		
		
	}
	printf("\n");
	printf("\n");
	printf("\n");
}

//验证管理员函数
int Prove() {
	char password[MAX_PASSWORD_LENGTH + 1];
	int i = 0;
	char ch;

	printf("Please enter your password: ");

	while (i < MAX_PASSWORD_LENGTH && (ch = _getch()) != '\r') {
		if (ch == '\b') {
			if (i > 0) {
				putchar('\b');
				putchar(' ');
				putchar('\b');
				i--;
			}
		}
		else if (ch >= ' ' && ch <= '~') {
			putchar('*');
			password[i++] = ch;
		}
	}

	putchar('\n');

	password[i] = '\0';

	if (strcmp(password, "admin") == 0) {
		// 执行C函数
		system("cls");
		printf("Login success!\n");
		return 1;
	}
	else {
		system("cls");
		printf("Invalid password.\n");
		return 0;
	}
}
//最短路径
int minDistance(int dist[], bool sptSet[]) {
	int min = INT_MAX, min_index;
	for (int v = 0; v < V; v++)
	{
		if (sptSet[v] == false && dist[v] <= min)
		{
			min = dist[v];
			min_index = v;
		}
	}
	return min_index;
}
//缔结克拉斯最短路径算法
void dijkstra(AdjMatrix G, int src, int dest) {
	int dist[V];     // 存储最短距离
	bool sptSet[V];  // 存储已计算的顶点集合

	for (int i = 0; i < V; i++) {
		dist[i] = INT_MAX;
		sptSet[i] = false;
	}
	dist[src] = 0;

	for (int count = 0; count < V - 1; count++) {
		int u = minDistance(dist, sptSet);
		sptSet[u] = true;
		for (int v = 0; v < V; v++) {
			if (!sptSet[v] && G.Edge[u][v] && dist[u] != INT_MAX
				&& dist[u] + G.Edge[u][v] < dist[v])
				dist[v] = dist[u] + G.Edge[u][v];
		}
	}
	// 打印最短路径结果
	printf("\nShortest distance from %d to %d is: %d\n", src + 1, dest + 1, dist[dest]);
}


//普利姆算法实现最小生成树
int dist[MAX_SIZE];              // 用于存储每个节点到最小生成树的最小距离
bool visited[MAX_SIZE];          // 用于记录节点是否已经被访问
int parent[MAX_SIZE];            // 记录节点在最小生成树中的父节点
void prim(int n, int s, AdjMatrix G) {
	for (int i = 1; i <= n; i++) {
		visited[i] = false;
		dist[i] = MaxWeight;
		parent[i] = -1;
	}

	int ans = 0;
	dist[s] = 0;

	while (true) {
		int v = -1;
		for (int i = 1; i <= n; i++) {
			if (!visited[i] && (v == -1 || dist[i] < dist[v]))
				v = i;
		}

		if (v == -1)
			break;

		visited[v] = true;
		ans += dist[v];

		for (int i = 1; i <= n; i++) {
			if (!visited[i] && G.Edge[v - 1][i - 1] < dist[i]) {
				dist[i] = G.Edge[v - 1][i - 1];
				parent[i] = v;
			}
		}
	}

	printf("最小生成树边集合:\n");
	for (int i = 1; i <= n; i++) {
		if (parent[i] != -1) {
			printf("(%d, %d)\n", parent[i], i);
		}
	}
	printf("最小生成树的总权值为:%d\n", ans);
}


//文件读取函数
void FoldWriter() {
	FILE *fp;
	AdjMatrix G;
	CreateGraph(&G);
	if (fopen_s(&fp, "user.txt", "w") != 0)
	{
		printf("打开文件失败");
		return;
	}
	int i, j;
	fprintf(fp, "\n输出顶点的信息(整型):\n");
	for (i = 0; i < G.numV; i++)
		fprintf(fp, "%8d", G.Vertices[i]);
	fprintf(fp, "\n");
	fprintf(fp, "\n输出邻接矩阵:\n");
	fprintf(fp, "\t");
	for (i = 0; i < G.numV; i++)
		fprintf(fp, "%8d", G.Vertices[i]);

	for (i = 0; i < G.numV; i++)
	{
		fprintf(fp, "\n%8d", i + 1);
		for (j = 0; j < G.numV; j++)
		{
			if (G.Edge[i][j] == 32767)
				fprintf(fp, "%8s", "∞");
			else
				fprintf(fp, "%8d", G.Edge[i][j]);
		}
		fprintf(fp, "\n");
	}
	fclose(fp);
	printf("cpoy 成功已保存到user.txt文件中\n");
}

//删除网点之间的连线
void DeleteEdge() {
	AdjMatrix G;
	CreateGraph(&G);
	int netNo1;
	int Netno2;
	printf("原图为:");
	DispGraph(G);

	printf("输入你想删除的第一个edge的节点");
	scanf_s("%d",&netNo1);
	printf("输入你想删除的第二个edge的节点");
	scanf_s("%d",&Netno2);
	netNo1--;
	Netno2--;
	if (G.Edge[netNo1][Netno2]!=0 && G.Edge[netNo1][Netno2]!= 32767)
	{
		G.Edge[netNo1][Netno2] = 32767;
		G.Edge[Netno2][netNo1] = 32767;
	}
	else
	{
		printf("输入两点有误请重新输入");
		DeleteEdge();
	}
	DispGraph(G);

	//写入文件
	FILE *fp;
	if (fopen_s(&fp, "user.txt", "w") != 0)
	{
		printf("打开文件失败");
		return;
	}
	int i, j;
	fprintf(fp, "\n输出顶点的信息(整型):\n");
	for (i = 0; i < G.numV; i++)
		fprintf(fp, "%8d", G.Vertices[i]);
	fprintf(fp, "\n");
	fprintf(fp, "\n输出邻接矩阵:\n");
	fprintf(fp, "\t");
	for (i = 0; i < G.numV; i++)
		fprintf(fp, "%8d", G.Vertices[i]);

	for (i = 0; i < G.numV; i++)
	{
		fprintf(fp, "\n%8d", i + 1);
		for (j = 0; j < G.numV; j++)
		{
			if (G.Edge[i][j] == 32767)
				fprintf(fp, "%8s", "∞");
			else
				fprintf(fp, "%8d", G.Edge[i][j]);
		}
		fprintf(fp, "\n");
	}
	fclose(fp);
}
//增加节点连线
void AddEdge() {
	AdjMatrix G;
	CreateGraph(&G);
	int netNo1;
	int Netno2;
	int weight;
	printf("原图为");
	DispGraph(G);

	printf("输入你想增加的第一个edge的节点");
	scanf_s("%d", &netNo1);
	printf("输入你想增加的第二个edge的节点");
	scanf_s("%d", &Netno2);
	printf("输入连接节点的权值");
	scanf_s("%d", &weight);

	netNo1--;
	Netno2--;

	if (G.Edge[netNo1][Netno2]==0 || G.Edge[netNo1][Netno2]< 32767)
	{
		printf("输入节点有误请重新输入");
		AddEdge();
		
	}
	else
	{
		
		G.Edge[netNo1][Netno2] = weight;
		G.Edge[Netno2][netNo1] = weight;
		DispGraph(G);
	}

	//file writen 
	FILE *fp;
	if (fopen_s(&fp, "user.txt", "w") != 0)
	{
		printf("打开文件失败");
		return;
	}
	int i, j;
	fprintf(fp, "\n输出顶点的信息(整型):\n");
	for (i = 0; i < G.numV; i++)
		fprintf(fp, "%8d", G.Vertices[i]);
	fprintf(fp, "\n");
	fprintf(fp, "\n输出邻接矩阵:\n");
	fprintf(fp, "\t");
	for (i = 0; i < G.numV; i++)
		fprintf(fp, "%8d", G.Vertices[i]);

	for (i = 0; i < G.numV; i++)
	{
		fprintf(fp, "\n%8d", i + 1);
		for (j = 0; j < G.numV; j++)
		{
			if (G.Edge[i][j] == 32767)
				fprintf(fp, "%8s", "∞");
			else
				fprintf(fp, "%8d", G.Edge[i][j]);
		}
		fprintf(fp, "\n");
	}
	fclose(fp);

}
//Delete Node function 
void DeleteNode() {
	int Node;
	int i,j;
	AdjMatrix G;
	CreateGraph(&G);
	

	printf("please input which Node ");
	scanf_s("%d",&Node);
	Node--;

	printf("\n输出顶点的信息(整型):\n");
	for (i = 0; i < G.numV; i++) {
		if (i!= Node)
		{
			printf("%8d", G.Vertices[i]);
		}
		
	}
		
	printf("\n");
	printf("\n输出邻接矩阵:\n");
	printf("\t");
	
		
	for (i = 0; i < G.numV; i++)
	{
		
		for (j = 0; j < G.numV; j++)
		{
			if (i== Node || j==Node)
			{
				printf(" ");
			}
			else
			{
				printf("%8d", G.Edge[i][j]);
			}
		}
		printf("\n");
	}
	//将记录写入文件

}
//管理员UI系统
void manegeUI() {

	printf("	城市网点管理系统:\n");
	printf("\n");
	printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
	printf("\n");
	printf("	一。 -- 删除网点线路\n");
	printf("	二。 -- 增加网点线路\n");
	printf("	三。 -- 删除某一节点\n");
	
	printf("	0 — 退出\n");
	printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
	printf("\n");
	printf("请输入您所需要用的功能: ");
	int Mflag;
	scanf_s("%d", &Mflag);  // 读取用户输入
	switch (Mflag)
	{
	case 1:
		DeleteEdge();
		printf("成功执行函数,按0结束程序,按1则重新回到页面");
		scanf_s("%d", &Mflag);
		while (Mflag != 0 && Mflag != 1)
		{
			printf("输入有误请重新输入");
			scanf_s("%d", &Mflag);
		}
		if (Mflag == 1)
		{
			system("cls");
			manegeUI();
		}
		break;
	case 2:
		AddEdge();
		printf("成功执行函数,按0结束程序,按1则重新回到页面");
		scanf_s("%d", &Mflag);
		while (Mflag != 0 && Mflag != 1)
		{
			printf("输入有误请重新输入");
			scanf_s("%d", &Mflag);
		}
		if (Mflag == 1)
		{
			system("cls");
			manegeUI();
		}
		break;
	case 3:
		DeleteNode();
		printf("成功执行函数,按0结束程序,按1则重新回到页面");
		scanf_s("%d", &Mflag);
		while (Mflag != 0 && Mflag != 1)
		{
			printf("输入有误请重新输入");
			scanf_s("%d", &Mflag);
		}
		if (Mflag == 1)
		{
			system("cls");
			manegeUI();
		}
		break;
	case 0:
		break;
	default:
		system("cls");
		printf("输入无效参数,请重新输入");
		manegeUI();
		break;
	}
}

//实现用户UI系统
void Ui() {
	
		printf("	城市网点交通系统:\n");
		printf("\n");
		printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
		printf("\n");
		printf("	一。 -- 输出路线的邻接矩阵\n");
		printf("	二。 -- 最短路径功能\n");
		printf("	三。 -- 实现最小生成树功能\n");
		printf("	四。 -- 保存网点文件到用户目录\n");
		printf("	五。 -- 查询某网点的具体信息\n");
		printf("	六。 -- 进入管理员系统\n");
		printf("	0 — 退出\n");
		printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
		printf("\n");
		printf("请输入您所需要用的功能: ");
		int flag;
		scanf_s("%d", &flag);  // 读取用户输入

		switch (flag) {
		case 0://退出
			break;
			
		case 1://输出map
			AdjMatrix G;
			CreateGraph(&G);
			
			int flags;
			system("cls");
			DispGraph(G);
			printf("成功执行函数,按0结束程序,按1则重新回到页面");
			scanf_s("%d", &flags);
			while (flags!= 0 && flags!=1)
			{
				printf("输入有误请重新输入");
				scanf_s("%d", &flags);
			}
			if (flags == 1)
			{
				system("cls");
				Ui();
			}
			break;
			
		case 2://input minest road
			
			int src, dest;
			printf("请输入起点");
			scanf_s("%d", &src);
			printf("请输入终点");
			scanf_s("%d", &dest);
			src--; dest--;
			//AdjMatrix G;
			CreateGraph(&G);
			dijkstra(G, src, dest);
			

			printf("成功执行函数,按0结束程序,按1则重新回到页面");
			scanf_s("%d", &flags);
			while (flags != 0 && flags != 1)
			{
				printf("输入有误请重新输入");
				scanf_s("%d", &flags);
			}
			if (flags == 1)
			{
				system("cls");
				Ui();
			}
			break;
		case 3: //minest tree

	
			CreateGraph(&G);
			prim(V, 1, G);

			memset(dist, 0, sizeof(dist));
			memset(visited, false, sizeof(visited));
			memset(parent, -1, sizeof(parent));


			printf("成功执行函数,按0结束程序,按1则重新回到页面");
			scanf_s("%d", &flags);
			while (flags != 0 && flags != 1)
			{
				printf("输入有误请重新输入");
				scanf_s("%d", &flags);
			}
			if (flags == 1)
			{
				system("cls");
				Ui();
			}
			break;
		case 4: 
			//folder woriting
			FoldWriter();

			printf("成功执行函数,按0结束程序,按1则重新回到页面");
			scanf_s("%d", &flags);
			while (flags != 0 && flags != 1)
			{
				printf("输入有误请重新输入");
				scanf_s("%d", &flags);
			}
			if (flags == 1)
			{
				system("cls");
				Ui();
			}
			break;
			break;
		case 5:
			system("cls");
			SearchNet(G);
			printf("成功执行函数,按0结束程序,按1则重新回到页面");
			scanf_s("%d", &flags);
			while (flags != 0 && flags != 1)
			{
				printf("输入有误请重新输入");
				scanf_s("%d", &flags);
			}
			if (flags == 1)
			{
				system("cls");
				Ui();
			}
			break;
			break;
		case 6:
			int sentense;

			sentense = Prove();
			if (sentense == 1)
			{
				manegeUI();
			}
			else
			{
				Ui();
			}
			break;
		default:
			system("cls");
			printf("选择无效,请重新输入。\n");
			Ui();
			break; // 跳出switch语句
		}
	}

int main()
{
	Ui();
}

7.代码测试

1.用户

 

 2.网点信息

最短路径

最小生成树

文件保存

猜你喜欢

转载自blog.csdn.net/dogxixi/article/details/130302102