用c语言设计一个基于DOS菜单的应用程序。内容如下:有向网的基本操作及应用 ① 创建有向网的邻接矩阵并打印 ② 创建有向网的邻接表并打印 ③ 关键路径 ④ 单源最短路径
时间: 2024-02-06 17:12:53 浏览: 78
DOS菜单系统(用C编写)
5星 · 资源好评率100%
好的,以下是一个简单的基于DOS菜单的应用程序的C代码,实现了有向网的基本操作及应用:
```
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define MAX_VERTEX_NUM 20 //最大顶点数
#define INFINITY 32767 //表示无穷大
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; //顶点数和弧数
int kind; //图的种类(本程序只考虑有向网)
}ALGraph;
void CreateGraph(ALGraph *G){
printf("请输入顶点数和弧数:");
scanf("%d%d",&G->vexnum,&G->arcnum);
printf("请输入每个顶点的数据:");
for(int i=0;i<G->vexnum;i++){
scanf(" %c",&G->vertices[i].data);
G->vertices[i].firstarc = NULL;
}
printf("请输入每条弧的起点、终点和权值:\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;
}
}
void PrintGraph(ALGraph G){
printf("邻接表如下:\n");
for(int i=0;i<G.vexnum;i++){
printf("%c -> ",G.vertices[i].data);
ArcNode *p = G.vertices[i].firstarc;
while(p != NULL){
printf("%c(%d) ",G.vertices[p->adjvex].data,p->weight);
p = p->nextarc;
}
printf("\n");
}
}
void CreateMatrix(ALGraph G,int A[][MAX_VERTEX_NUM]){
for(int i=0;i<G.vexnum;i++){
for(int j=0;j<G.vexnum;j++){
A[i][j] = INFINITY;
}
A[i][i] = 0;
ArcNode *p = G.vertices[i].firstarc;
while(p != NULL){
A[i][p->adjvex] = p->weight;
p = p->nextarc;
}
}
}
void PrintMatrix(ALGraph G,int A[][MAX_VERTEX_NUM]){
printf("邻接矩阵如下:\n");
for(int i=0;i<G.vexnum;i++){
for(int j=0;j<G.vexnum;j++){
if(A[i][j] == INFINITY){
printf("∞ ");
}
else{
printf("%d ",A[i][j]);
}
}
printf("\n");
}
}
void CriticalPath(ALGraph G,int ve[],int vl[]){
int *topo = (int*)malloc(sizeof(int)*G.vexnum); //拓扑序列
int *stack = (int*)malloc(sizeof(int)*G.vexnum);//存储入度为0的顶点
int top = -1; //栈顶指针
int count = 0; //统计已经输出的顶点数
//初始化
for(int i=0;i<G.vexnum;i++){
ve[i] = 0;
}
//统计每个顶点的入度
int *indegree = (int*)malloc(sizeof(int)*G.vexnum);
for(int i=0;i<G.vexnum;i++){
indegree[i] = 0;
}
for(int i=0;i<G.vexnum;i++){
ArcNode *p = G.vertices[i].firstarc;
while(p != NULL){
indegree[p->adjvex]++;
p = p->nextarc;
}
}
//将入度为0的顶点入栈
for(int i=0;i<G.vexnum;i++){
if(indegree[i] == 0){
stack[++top] = i;
}
}
//拓扑排序
while(top != -1){
int i = stack[top--];
topo[count++] = i;
ArcNode *p = G.vertices[i].firstarc;
while(p != NULL){
if(--indegree[p->adjvex] == 0){
stack[++top] = p->adjvex;
}
if(ve[i]+p->weight > ve[p->adjvex]){
ve[p->adjvex] = ve[i]+p->weight;
}
p = p->nextarc;
}
}
if(count < G.vexnum){ //存在环
printf("该图存在环,无法求关键路径!\n");
return;
}
//初始化
for(int i=0;i<G.vexnum;i++){
vl[i] = ve[G.vexnum-1];
}
//逆拓扑排序
for(int i=G.vexnum-1;i>=0;i--){
int k = topo[i];
ArcNode *p = G.vertices[k].firstarc;
while(p != NULL){
if(vl[p->adjvex]-p->weight < vl[k]){
vl[k] = vl[p->adjvex]-p->weight;
}
p = p->nextarc;
}
}
}
void PrintCriticalPath(ALGraph G,int ve[],int vl[]){
printf("关键路径如下:\n");
for(int i=0;i<G.vexnum;i++){
ArcNode *p = G.vertices[i].firstarc;
while(p != NULL){
int e = ve[i];
int l = vl[p->adjvex]-p->weight;
if(e == l){
printf("%c->%c ",G.vertices[i].data,G.vertices[p->adjvex].data);
}
p = p->nextarc;
}
}
printf("\n");
}
void ShortestPath(ALGraph G,int v,int dist[]){
int *s = (int*)malloc(sizeof(int)*G.vexnum); //已求出最短路径的顶点集合
int *path = (int*)malloc(sizeof(int)*G.vexnum); //存储最短路径的前驱结点
//初始化
for(int i=0;i<G.vexnum;i++){
s[i] = 0;
dist[i] = INFINITY;
path[i] = -1;
}
s[v] = 1;
dist[v] = 0;
//第一轮松弛操作
ArcNode *p = G.vertices[v].firstarc;
while(p != NULL){
dist[p->adjvex] = p->weight;
path[p->adjvex] = v;
p = p->nextarc;
}
//n-1轮松弛操作
for(int i=0;i<G.vexnum-1;i++){
int min = INFINITY;
int u = v;
//找到距离v最近的未标记顶点u
for(int j=0;j<G.vexnum;j++){
if(s[j] == 0 && dist[j] < min){
min = dist[j];
u = j;
}
}
s[u] = 1;
//对u的所有出边进行松弛操作
p = G.vertices[u].firstarc;
while(p != NULL){
if(s[p->adjvex] == 0 && dist[u]+p->weight < dist[p->adjvex]){
dist[p->adjvex] = dist[u]+p->weight;
path[p->adjvex] = u;
}
p = p->nextarc;
}
}
//输出结果
printf("从%c出发的最短路径如下:\n",G.vertices[v].data);
for(int i=0;i<G.vexnum;i++){
if(i != v){
printf("%c->%c:",G.vertices[v].data,G.vertices[i].data);
int k = i;
while(path[k] != v){
printf("%c<-",G.vertices[k].data);
k = path[k];
}
printf("%c,路径长度为%d\n",G.vertices[v].data,dist[i]);
}
}
}
void menu(){
printf("1.创建有向网的邻接矩阵并打印\n");
printf("2.创建有向网的邻接表并打印\n");
printf("3.求有向网的关键路径\n");
printf("4.求有向网从指定顶点出发的单源最短路径\n");
printf("0.退出\n");
}
int main(){
ALGraph G;
int A[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
int ve[MAX_VERTEX_NUM],vl[MAX_VERTEX_NUM]; //事件最早发生时间和最迟发生时间
int dist[MAX_VERTEX_NUM]; //最短路径长度
int choice,flag=0;
while(1){
if(flag == 0){
printf("请先创建有向网!\n");
}
menu();
printf("请输入操作序号:");
scanf("%d",&choice);
switch(choice){
case 1:
CreateGraph(&G);
CreateMatrix(G,A);
PrintMatrix(G,A);
flag = 1;
break;
case 2:
CreateGraph(&G);
PrintGraph(G);
flag = 1;
break;
case 3:
if(flag == 0){
printf("请先创建有向网!\n");
break;
}
CriticalPath(G,ve,vl);
PrintCriticalPath(G,ve,vl);
break;
case 4:
if(flag == 0){
printf("请先创建有向网!\n");
break;
}
char v;
printf("请输入起点:");
scanf(" %c",&v);
int i;
for(i=0;i<G.vexnum;i++){
if(G.vertices[i].data == v){
break;
}
}
if(i == G.vexnum){
printf("该顶点不存在!\n");
break;
}
ShortestPath(G,i,dist);
break;
case 0:
exit(0);
default:
printf("输入有误,请重新输入!\n");
}
printf("按任意键继续...\n");
getch();
system("cls");
}
return 0;
}
```
这个程序实现了以下功能:
1. 创建有向网的邻接矩阵并打印
2. 创建有向网的邻接表并打印
3. 求有向网的关键路径
4. 求有向网从指定顶点出发的单源最短路径
其中,关键路径算法使用了拓扑排序和动态规划的思想,单源最短路径算法使用了Dijkstra算法。
阅读全文