拓扑排序问题

拓扑排序问题

大学里,学生需要修完培养计划中的所有课程,才能毕业取得学位。例如计算机专业的学生要学习一系列课程,其中有些课程必须在其先修课程完成后才能学习,具体教学计划如下所示。
课程编号 课程名称 先修课程
假设每门课程的学习时间为一学期,试为计算机专业的学生设计课程的学习计划,使他们能在最短的时间内修完这些课程。设计算法求出每个学期的课程安排。
(1)用顶点表示课程,弧表示先决条件,则课程关系可用一有向无环图表示。
(2)基于邻接表存储结构实现。
(3)输出每学期的课程安排。
(4)在主函数中调用菜单函数调试程序。
代码如下:

#include <stdio.h>
#include <stdlib.h>
#define  MAX_VERTEX_NUM 20//最大顶点个数
typedef struct VertexType //课程信息
{
	int index; //课程的编号
	char name[32]; //课程名
} VertexType;
typedef enum {
	false, true
} bool;
typedef struct ArcNode {
	int adjvex; //邻接点在数组中的位置下标
	struct ArcNode * nextarc; //指向下一个邻接点的指针
} ArcNode;
typedef struct VNode {
	VertexType data; //顶点的数据域
	ArcNode * firstarc; //指向邻接点的指针
} VNode, AdjList[MAX_VERTEX_NUM]; //存储各链表头结点的数组
typedef struct {
	AdjList vertices; //图中顶点及各邻接点数组
	int vexnum, arcnum; //记录图中顶点数和边或弧数
} ALGraph;

int menu_select() {
	int sn;
	printf("-----------拓扑排序问题----------------------\n");
	printf("1构建图\n");
	printf("2输出拓扑排序\n");
	printf("3退出\n");
	printf("  请选择1--3:  ");

	for (;;)		//菜单功能选择
			{
		scanf("%d", &sn);
		getchar();
		if (sn < 1 || sn > 3)
			printf("\n\t 输入选择错误,请重新选择 1--3: ");
		else
			break;
	}
	return sn;
}

/*TODO: 创建AOV网
功能描述: 创建AOV网,通过scanf("%d,%d", 节点数, 弧数);scanf("%s", 课程名);来创建节点。节点index从0开始递增
                      通过输入scanf("%d,%d", 弧的开始节点下标, 弧的结束节点下标)来创建弧
 参数说明:G-ALGraph型指针参数
 返回值说明:无
*/
void CreateAOV(ALGraph **G) {
	*G = (ALGraph*) malloc(sizeof(ALGraph));

	scanf("%d,%d", &((*G)->vexnum), &((*G)->arcnum));
	for (int i = 0; i < (*G)->vexnum; i++) {
		scanf("%s", (*G)->vertices[i].data.name);
		(*G)->vertices[i].data.index = i;
		(*G)->vertices[i].firstarc = NULL;
	}
	int initial, end;
	for (int i = 0; i < (*G)->arcnum; i++) {
		scanf("%d,%d", &initial, &end);
		ArcNode *p = (ArcNode*) malloc(sizeof(ArcNode));
		p->adjvex = end;
		p->nextarc = NULL;
		p->nextarc = (*G)->vertices[initial].firstarc;
		(*G)->vertices[initial].firstarc = p;
	}
}
//结构体定义栈结构
typedef struct stack {
	VertexType data;
	struct stack * next;
} stack;
//初始化栈结构
void initStack(stack* *S) {
	(*S) = (stack*) malloc(sizeof(stack));
	(*S)->next = NULL;
}
//判断链表是否为空
bool StackEmpty(stack S) {
	if (S.next == NULL) {
		return true;
	}
	return false;
}
//进栈,以头插法将新结点插入到链表中
void push(stack *S, VertexType u) {
	stack *p = (stack*) malloc(sizeof(stack));
	p->data = u;
	p->next = NULL;
	p->next = S->next;
	S->next = p;
}
//弹栈函数,删除链表首元结点的同时,释放该空间,并将该结点中的数据域通过地址传值给变量i;
void pop(stack *S, VertexType *i) {
	stack *p = S->next;
	*i = p->data;
	S->next = S->next->next;
	free(p);
}
//统计各顶点的入度
void FindInDegree(ALGraph G, int indegree[]) {
	//初始化数组,默认初始值全部为0
	for (int i = 0; i < G.vexnum; i++) {
		indegree[i] = 0;
	}
	//遍历邻接表,根据各链表中结点的数据域存储的各顶点位置下标,在indegree数组相应位置+1
	for (int i = 0; i < G.vexnum; i++) {
		ArcNode *p = G.vertices[i].firstarc;
		while (p) {
			indegree[p->adjvex]++;
			p = p->nextarc;
		}
	}
}

/*TODO: 拓扑排序
 功能描述:通过调用FindInDegree计算各顶点的入度并存入本地变量数组,顺序查找度为0的顶点,作为起始点,通过栈操作完成拓扑排序,打印节点printf("%s ", 课程名);
           如果该图有回路则打印printf("该图有回路");
 参数说明:G-ALGraph型参数
 返回值说明:无
*/
void TopologicalSort(ALGraph G) {
	int indegree[G.vexnum];
	FindInDegree(G, indegree);
	stack *S;
	initStack(&S);
	for (int i = 0; i < G.vexnum; i++) {
		if (!indegree[i]) {
			push(S, G.vertices[i].data);
		}
	}
	int count = 0;
	while (!StackEmpty(*S)) {
		VertexType data;
		pop(S, &data);
		printf("%s ", data.name);
		count++;
		for (ArcNode *p = G.vertices[data.index].firstarc; p; p = p->nextarc) {
			int k = p->adjvex;
			if (!(--indegree[k])) {
				push(S,G.vertices[k].data);
			}
		}
	}
	if (count < G.vexnum) {
		printf("该图有回路");
		return;
	}
}
void main() {
	ALGraph *G;
	for (;;) {
		switch (menu_select()) {
		case 1:
			CreateAOV(&G);
			printf("\n");
			break;
		case 2:
			printf("拓扑排序:");
			TopologicalSort(*G);
			printf("\n");
			break;
		case 3:
			printf(" 再见!\n");
			return;
		} // switch语句结束
	} // for循环结束
} // main()函数结束
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值