数据结构课程设计 最小生成树,拓扑排序以及最短路径

2023-10-26

通信网络的架设问题

【问题描述】

若要在n(≥10)个城市之间建设通信网络,只需要架设n-1条线路即可,如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。

【基本要求】

(1)利用二种方法(Prim算法和克鲁斯卡尔(Kruskual)生成网中的最小生成树。

(2)求出任意两个城市之间通信的最短距离。

(3)将n个城市设计为一个DAG图,求出一组拓扑排序序列和关键路径。

#include<stdio.h>
#include<malloc.h>
#define inf 999
#define MVNum 100

//首先创建邻接矩阵
typedef struct amgraph{
	int vexnum,edgenum;//图中顶点和边
	int juzhen[20][20];// 邻矩阵
	int vexs[20];//顶点表 
}amgraph; 




int topo[20];        //定义拓扑排序数组 
//创建邻接表结构
typedef struct ArcNode{       //边表 
 int adjvex;//该边所指向的顶点位置 
 struct ArcNode *nextarc;//指向下一条边的指针 
 char info;    //和边相关信息,权值 
}ArcNode;


typedef struct VNode{       //表头结点表 
 char data;
 ArcNode *firstarc;
}VNode,AdjList[MVNum];


typedef struct{         //邻接表,带权有向图 
 AdjList vertices;
 int vexnum,arcnum;
}ALGraph;
//拓扑排序创建链栈,以度为零作为判断条件 

typedef struct StackLink{
 int data;
 struct StackLink *next;
}StackLink,*StackNode;

//栈的基本操作 
int InitStack(StackNode &S){
 S = NULL;
 return 1;
}
int Push(StackNode &S,int e){
 StackNode p;
 p = (StackLink*)malloc(sizeof(StackLink));
 p->data = e;
 p->next = S;
 S = p;
 return 1;
}
int Pop(StackNode &S,int &e){
 StackNode p;
 p = (StackLink*)malloc(sizeof(StackLink));
 if(S==NULL)
  return  0;
 e = S->data;
 p = S;      //用P临时存放栈顶元素
 S = S->next; 
 free(p);
 return 1; 
}
int GetTop(StackNode S){
 if(S!=NULL)
  return S->data;
}
int StackEmpty(StackNode S){
 if(S!=NULL)
  return 0;
 else 
  return 1;
}
int LocateVex(ALGraph G,char c){
 int i;
 for(i=0;i<G.vexnum;++i){
  if(c==G.vertices[i].data)
   return i;
 }
 return -1;
}
//邻接表的创建 
int CreateDAG(ALGraph &G){
 int i,j,k,weight;
 char v1,v2;
 ArcNode* p;
 printf("[请输入总顶点与总边数]:\n>>>");
 scanf("%d %d",&G.vexnum,&G.arcnum);
 for(i=0;i<G.vexnum;i++){         //输入各点,构造表头结点表 
  printf("\n[请依次输入顶点信息]:\n>>>");
  getchar();
  scanf("%c",&G.vertices[i].data);
  G.vertices[i].firstarc = NULL;
 }
 for(k=0;k<G.arcnum;k++){
  printf("\n[请输入各边及权值构造邻接表]:\n>>>");
  getchar();
  scanf("%c %c %d",&v1,&v2,&weight);
  i = LocateVex(G,v1);
  j = LocateVex(G,v2);
  p = (ArcNode*)malloc(sizeof(ArcNode));
  p->adjvex = j;
  p->info = weight;
  p->nextarc = G.vertices[i].firstarc;
  G.vertices[i].firstarc = p;
 }
 return  1;
}

void FindInDegree(ALGraph G,int indegree[]){//遍历邻接表求出入度 并放入indegree数组中 
 ArcNode *p;
 int i;
 for(i=0;i<G.vexnum;i++)    //入度初始化为零 
  indegree[i] = 0;
 for(i=0;i<G.vexnum;i++){   //遍历邻接表 
  p = G.vertices[i].firstarc;
  while(p!=NULL){
   indegree[p->adjvex]++;
   p = p->nextarc;
  }
 }
}

int TopologicalSort(ALGraph G,int topo[]){
 int i;
 ArcNode *p; 
 StackNode S;        //定义链栈 
 int indegree[MVNum];
 FindInDegree(G,indegree);     //求出各顶点入度,存入数组indegree中
 
 InitStack(S);        
 for(i=0;i<G.vexnum;i++){
  if(indegree[i]==0)
   Push(S,i);       //入度为零,则入栈 
 }
 int m=0;
 while(!StackEmpty(S)){
  Pop(S,i);        //将栈顶顶点vi出栈 
  topo[m] = i;       //将vi保存在拓扑序列数组topo,便于后序的输出 
  m++;         //对输出顶点计数 
  p=G.vertices[i].firstarc; 
     
  while(p!=NULL){
   int k = p->adjvex;     //vk为vi的邻接点 
   indegree[k]--;      //vi的每个邻接点入度减1 
   if(indegree[k]==0)
    Push(S,k);      //若入度为0则入栈 
   p = p->nextarc;      // 
  }
  
 }
 if(m<G.vexnum)        //通过m和顶点总数判断有无回路 
  return 0;
 else
  return 1;
}


int CriticalPath(ALGraph G){
 ArcNode *p;
 int ve[MVNum];     //最早发生时间 
 int vl[MVNum];     //最迟发生时间 
 int i,j,k,e,l;
 if(!TopologicalSort(G,topo))
  return 0;    
 int n = G.vexnum;    //n为顶点个数
 
 for(i=0;i<n;i++)
  ve[i] = 0;     //个每个事件的最早发生时间置初值0
 
 
 for(i=0;i<n;i++){
  k=topo[i];     //取得拓扑排序序列中顶点序号k 
  p = G.vertices[k].firstarc; //p指向k的第一个邻接顶点 
  while(p!=NULL){    //依次更新k的所有邻接顶点的最早发生时间 
   j = p->adjvex;   //j为邻接顶点的序号 
   if(ve[j]<ve[k]+p->info) //更新顶点j的最早发生时间ve[j] 
    ve[j] = ve[k]+p->info;
   p = p->nextarc;   //p指向k的下一个邻接顶点 
  }
 }
 for(i=0;i<n;i++)    //给每个事件的最迟发生时间置初值ve[n-1] 
  vl[i] = ve[n-1];
 
 for(i=n-1;i>=0;i--){//按逆拓扑次序求每个事件最迟发生时间
  k = topo[i];   //i已调整,逆序 
  p = G.vertices[k].firstarc; //p指向k的第一个邻接顶点
  while(p!=NULL){    //根据k的邻接点,更新k的最迟发生时间 
   j = p->adjvex;   //j为邻接顶点的序号 
   if(vl[k]>vl[j]-p->info) //更新顶点k的最早发生时间vl[k] 
    vl[k] = vl[j]-p->info;
   p = p->nextarc;   //p指向k的下一个邻接顶点 
  }
 }
 
 printf("关键路径如下:\n\n");
 for(i=0;i<n;i++){
  p = G.vertices[i].firstarc; //p指向k的第一个邻接顶点
  while(p!=NULL){
   j = p->adjvex;   //j为i的邻接顶点的序号 
   e = ve[i];    //最早开始时间 
   l = vl[j]-p->info;  //计算活动<vi,vj>的最迟开始时间 
   if(e==l)     //若为关键活动则输出<vi,vj> 
    printf("<%c,%c>",G.vertices[i].data,G.vertices[j].data);
   p = p->nextarc;   //p指向i的下一个邻接顶点 
  } 
 }
 
 return 1;
}



void creat(amgraph &g){//邻接矩阵的创建 
printf("请输入城市数目和线路数目");
scanf("%d %d",&g.vexnum ,&g.edgenum);
for(int i=0;i<g.vexnum;i++){
	g.vexs[i]=i;
}	
for(int i=0;i<g.vexnum;i++){
	for(int j=0;j<g.vexnum;j++){
		g.juzhen[i][j]=inf;
		if(i==j) g.juzhen[i][j]=0;
	}
} 
printf("请输城市的信息和线路的权值");
printf("\n"); 
for(int i=0;i<g.edgenum;i++){
	int x,y,w;
	scanf("%d%d%d",&x,&y,&w);
	g.juzhen[x][y]=w;
	g.juzhen[y][x]=w;
} 
}

int GetRoot(int v[],int p){
	while(p!=v[p]){//依据根节点的数组下标和 里面的值相同来找到根节点 
		p=v[p];//若两个元素的根节点相同则属于同一颗树 
	}
}


 
void Kruskal(amgraph g){//卡鲁索算法 
	int v[g.vexnum];
	for(int i=0;i<g.vexnum;i++) v[i]=i;//初始化并查集 
	int sum=0;
	for(int q=0;q<g.vexnum-1;q++){//连通一个图需要n-1条边,(n为顶点数) 
	int x,y;
	int  min=inf;
	for(int i=0;i<g.vexnum;i++){	
		for(int j=0;j<g.vexnum;j++){ 	
			if(g.juzhen[i][j] <min&&g.juzhen[i][j]>0&&GetRoot(v,i)!=GetRoot(v,j)){//getroot不相等说明不形成回路 
				min=g.juzhen[i][j];                                          
				x=i;
				y=j;
 
			}
		} 
	}
				printf("[%d %d]\n",x,y); 
			
				g.juzhen[x][y]=0;//将这条边置零,以便选出次小边 
				g.juzhen[y][x]=0;//无向图 
				v[y]=x;//将两个结点挂在一棵树上
	}

} 




void prim(amgraph g,int v){//普利姆算法 
	int lowcost[20];
	int min;
	int closest[20],i,j,k;
	for(i=0;i<g.vexnum;i++){
		lowcost[i]=g.juzhen[v][i];
		closest[i]=v;
	}
	for(i=1;i<g.vexnum;i++){
	min=inf;
	for(j=0;j<g.vexnum;j++)//通过比较,找出到该顶点的最小权值,但只能选中有通路部分 
		if(lowcost[j]!=0 && lowcost[j]<min){
			min=lowcost[j];
			k=j;
		}	
		printf("[%d %d]\n",closest[k],k);
		lowcost[k]=0;//此处置零表示顶点k已经加入到了集合中 
		for(j=0;j<g.vexnum;j++)
			if(g.juzhen[k][j]!=0&&g.juzhen[k][j]<lowcost[j]){
				lowcost[j]=g.juzhen[k][j];
				closest[j]=k;
			}
	}
} 





void dispallpath(amgraph g,int a[][20],int path[][20]){
	int i,j,k,s;
	int apath[20],d;//apath中存放着一条最短路径 
	for(i=0;i<g.vexnum;i++)
		for(j=0;j<g.vexnum;j++){
			if(a[i][j]!=inf &&i!=j){//判断条件,i,j之间存在路径 
				printf("顶点%d到%d的最短路径长度:%d路径:",i,j,a[i][j]);
				k=path[i][j];
				d=0;apath[d]=j;
				while(k!=-1&&k!=i){
					d++;
					apath[d]=k;
					k=path[i][k];
				}	
				d++;
				apath[d]=i;
				printf("%d",apath[d]);
				for(s=d-1;s>=0;s--)
					printf("->%d",apath[s]);
					printf("\n");
						}
		}
		
}

void Floyd(amgraph g){//关键在于建立两个数组以及数组如何更新 
	int a[20][20];
	int path[20][20];
	int i,j,k;
	for( i=0;i<g.vexnum;i++)//求出每对顶点的最短路径 
		for(j=0;j<g.vexnum;j++){
			a[i][j]=g.juzhen[i][j];
				if(i!=j&& g.juzhen[i][j] <inf)
		 	path[i][j]=i;//要是顶点之间有边则置为i 
				else
			path[i][j]==-1;//顶点之间没有边则置为-1 
		}
	for(k=0;k<g.vexnum;k++){
		for(i=0;i<g.vexnum;i++)
			for(j=0;j<g.vexnum;j++)//遍历两个数组 
				if(a[i][j]>a[i][k]+a[k][j]){
					a[i][j]=a[i][k]+a[k][j];
					path[i][j]=path[k][j];//修改最短路径为经过k 
				}
	}
	dispallpath(g,a,path);//输出最短路径的长度 
} 




int main(){
int a,b;
amgraph g;
creat(g);
printf("Kruskal生成的最小生成树为\n"); 
Kruskal(g);
printf("prim生成的最小生成树为\n");	
prim(g,0);
Floyd(g);
int i,user;
 ALGraph G;
  scanf("%d",&user);
   CreateDAG(G);
  TopologicalSort(G,topo);
   printf("拓扑排序结果如下:\n");
   for(i=0;i<G.vexnum;i++)
    printf("%c->",G.vertices[topo[i]].data);
    CriticalPath(G);
   
   
  
 

}
	
	

测试用例以及结果显示 (已在DEV C++等编译器上通过)

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构课程设计 最小生成树,拓扑排序以及最短路径 的相关文章

随机推荐

  • java jsch 密钥登陆_java – 使用JSch时“无效的私钥”

    我正在使用以下代码在 Java应用程序中使用 Git 我有一个有效的密钥 一直使用它 这个特定的代码以前使用相同的密钥和git存储库 但现在我得到以下异常 invalid privatekey B 59c40796 在这一行 jSch ad
  • 深度学习概念(术语):Fine-tuning、Knowledge Distillation, etc

    文章目录 1 Fine tuning 微调 2 Transfer Learning 迁移学习 3 Knowledge Distillation 知识蒸馏 4 Meta Learning 元学习 这里的相关概念都是基于已有预训练模型 就是模型
  • cmake简洁教程 - 第一篇

    由于cmake内容较多 篇幅较长 为了不让人疲倦 分成了多篇博客 全部博客链接如下 cmake简洁教程 第一篇 YZF Kevin的博客 CSDN博客 cmake简洁教程 第二篇 YZF Kevin的博客 CSDN博客 cmake简洁教程
  • mt19937 随机数

    https blog csdn net real myth article details 53893854 https blog csdn net calmreason article details 72655060 https blo
  • 数字图像处理-python基于opencv代码实现 反转变换、对数变换和幂律(伽马)变换

    本文主要介绍对 数字图像处理 第三章书中示例图片实现 反转变换 对数变换以及伽马变换的代码 若要获取更多数字图像处理 python 深度学习 机器学习 计算机视觉等高清PDF以及 更多有意思的 分享 可搜一搜 微信公共号 分享猿 免费获取资
  • typescript基础之object和Object

    TypeScript 的 object 和 Object 是两种不同的类型 它们的区别和用途如下 object 类型是 TypeScript 2 2 引入的新类型 它表示非原始对象 也就是除了 number string boolean s
  • 实时时钟电路DS1302的原理及应用

    2006 05 11 10 10 39 实时时钟电路DS1302的原理及应用
  • 使用windeployqt.exe打包QT工程,windows系统可执行程序

    前言 因为自己打包qt程序遇到点问题 提示0xc000007b错误 发现是因为打包工具和工程编译工具不对应导致 于是为了记录打包方法 有了此篇文章 记录使用windeployqt exe打包qt工程在windows系统的可执行文件 一 确定
  • adb install 命令参数

    adb install 6个参数描述 t 允许测试包 l 锁定该应用程序 s 把应用程序安装到sd卡上 g 为应用程序授予所有运行时的权限 r 替换已存在的应用程序 也就是说强制安装 d 允许进行将见状 也就是安装的比手机上带的版本低
  • activiti-serviceTask(服务任务)

    Activiti服务任务 serviceTask Activiti服务任务 serviceTask 作者 邓家海 都有一段沉默的时间 等待厚积薄发 应用场景 当客户有这么一个需求 下一个任务我需要自动执行一些操作 并且这个节点不需要任何的人
  • 一文让你深刻理解异步请求池-DNS解析与实现

    一 DNS概念简述 DNS Domain Name Service 域名解析服务 工作在应用层 是互联网的一项服务 它作为将域名和IP地址相互映射的一个分布式数据库 能够使人更方便地访问互联网 DNS监听在TCP和UDP端口53 FQDN
  • SpringMVC系列(十)(处理静态资源)和...

  • 通俗理解泰勒公式

    本博客只用于自身学习 如有错误 虚心求教 在维基百科上的解释 在数学中 泰勒公式 英语 Taylor s Formula 是一个用函数在某点的信息描述其附近取值的公式 这个公式来自于微积分的泰勒定理 Taylor s theorem 泰勒定
  • 计算方法——C语言实现——迭代法求解线性方程组

    最近在上计算方法这门课 要求是用MATLAB做练习题 但是我觉得C语言也很棒棒啊 题目 和直接法不同 迭代法是一种逐次逼近的方法 将复杂问题简单化 求比较大的方程组时一般都不会用直接法 迭代法有好几种 这里使用了Jacobi迭代与Gauss
  • 8.4收官之战非农蓄力能否引爆黄金单边行情?

    近期有哪些消息面影响黄金走势 黄金多空该如何研判 黄金消息面解析 周五 8月4日 亚洲时段 现货黄金在近三周低位窄幅震荡 目前交投于1937 60美元 盎司附近 美联储7月决策符合预期 如期加息25个基点 虽然美国通胀增速放缓 但仍高于美联
  • Git 大文件push失败

    目录 1 下载并安装Git Large File Storage命令行扩展 2 配置lfs跟踪的文件 3 commit 并push到远程仓库 由于git有push文件的大小限制 100MB 因此如果push操作中右超过100MB的文件 就会
  • 抽签小程序(C语言随机数),C# 抽签小程序

    设计背景 设置一个Excel名单表 对名单进行随机抽取 设计思路 使用Timer定时器 运行定时器进行名单随机滚动 停止定时器获得抽签结果 相关技术 随机数 Excel读取 导出 XML文档读写 相关类库 C1 C1Excel Excel操
  • 《深入浅出话数据结构》系列之什么是B树、B+树?为什么二叉查找树不行?

    本文将为大家介绍B树和B 树 首先介绍了B树的应用场景 为什么需要B树 然后介绍了B树的查询和插入过程 最后谈了B 树针对B树的改进 在谈B树之前 先说一下B树所针对的应用场景 那么B树是用来做什么的呢 B树是一种为辅助存储设计的一种数据结
  • 达梦DCA认证培训和考试

    本人有幸参加了达梦DCA认证培训并参加了认证考试 培训内容包括 第一天 国产数据库现状及未来 DM8企业版安装 创建数据库及数据库实例管理 DM8体系结构 第二天 表空间管理 用户管理 DMSQL 第三天 模式对象管理 备份还原 配置作业
  • 数据结构课程设计 最小生成树,拓扑排序以及最短路径

    通信网络的架设问题 问题描述 若要在n 10 个城市之间建设通信网络 只需要架设n 1条线路即可 如何以最低的经济代价建设这个通信网 是一个网的最小生成树问题 基本要求 1 利用二种方法 Prim算法和克鲁斯卡尔 Kruskual 生成网中