数据结构:图的应用之课程选修问题

任务描述

本关任务:学生需要选修一定数目的课程才能毕业,这些课程之间有先导关系。假设所有的课程在每学期都能提供学生选修,学生每学期可以选修的课程不限。给出一些课程以及课程之间的关系,安排一个计划,用最少的学期修完所有的课程。

问题解析

可以将该问题转化成拓扑排序问题,在拓扑排序时按批输出满足条件的结点,即入度为0的结点。具体流程如下:

  1. 每一批就是一个学期可以选修的课程;
  2. 可以设置两个队列q1和q2,一个队列保存一个学期的课。
  3. 没有先导课程的课在第一学期都可以选,因此先让入度为0的所有结点进入队列q1,这是第一学期可以选修的课。
  4. 将q1的元素依次出队,将它们的后继的入度减1。
  5. 如果后继的入度减到0,则让它进入队列q2,表示是第二学期可以选修的课。
  6. 将q2中的元素依次出栈,将它们后继的入度减1。
  7. 如果后继结点的入度减到了0,则让它进入队列q1,表示第三学期可以选修的课。
  8. 重复上述过程,直到所有的课程都已经被选修。

编程要求

根据提示,在编辑器补充代码,完成课程选修问题。

#include <iostream>
using namespace std;
#include"LQueue.h"
template<class TypeOfEdge>
class graph{
	public:
		virtual bool insert(int u,int v,TypeOfEdge w)=0;
		virtual bool remove(int u,int v)=0;
		virtual bool exist(int u,int v) const=0;
		int numOfVer() const{return Vers;}
		int numOfEdge() const{return Edges;}	
	protected:
		int Vers,Edges;	
};

template<class TypeOfVer,class TypeOfEdge>
class adjListGraph:public graph<TypeOfEdge>{
	public:
		int Vers,Edges;	
		adjListGraph(int vSize,const TypeOfVer d[]);
		bool insert(int u,int v,TypeOfEdge w);
		bool remove(int u,int v);
		bool exist(int u,int v)const;
		~adjListGraph();
		void findLessTime()const;
	private:
		struct edgeNode{
			int end;
			TypeOfEdge weight;
			edgeNode *next;
			
			edgeNode(int e,TypeOfEdge w,edgeNode *n=NULL){end=e;weight=w;next=n;}
		};
		struct verNode{
			TypeOfVer ver;
			edgeNode *head;
			verNode(edgeNode *h=NULL){head=h;}
		};
		verNode *verList;
		
};
//构造函数和折构函数
template<class TypeOfVer,class TypeOfEdge>
adjListGraph<TypeOfVer,TypeOfEdge> :: adjListGraph(int vSize,const TypeOfVer d[])
{
	Vers=vSize;
	verList=new verNode[vSize];
	for(int i=0;i<Vers;++i)verList[i].ver=d[i];
}

template<class TypeOfVer,class TypeOfEdge>
adjListGraph<TypeOfVer,TypeOfEdge> ::~adjListGraph(){
	int i;
	edgeNode *p;
	for(i=0;i<Vers;++i)
		while((p=verList[i].head)!=NULL){
		verList[i].head=p->next;
		delete p; 
	}
	delete[]verList;
}


template<class TypeOfVer,class TypeOfEdge>
bool adjListGraph<TypeOfVer,TypeOfEdge> :: insert(int u,int v,TypeOfEdge w){
	verList[u].head=new edgeNode(v,w,verList[u].head);
	++Edges;
	return true;
}


template<class TypeOfVer,class TypeOfEdge>
bool adjListGraph<TypeOfVer,TypeOfEdge> :: remove(int u,int v){
	edgeNode *p=verList[u].head, *q;
	if(p==NULL)return false;
	if(p->end==v){
	verList[u].head=p->next;
	delete p;--Edges;
	return true; 
	}
	while(p->next!=NULL&&p->next->end!=v)p=p->next;
	if(p->next==NULL)return false;
	q=p->next;p->next=q->next;delete q;
	--Edges;
	return true;
}

template<class TypeOfVer,class TypeOfEdge>
bool adjListGraph<TypeOfVer,TypeOfEdge> :: exist(int u,int v)const{
	edgeNode *p=verList[u].head;
	while(p!=NULL&&p->end!=v)p=p->next;
	if(p==NULL)return false;else return true;

}
template<class TypeOfVer,class TypeOfEdge>
void adjListGraph<TypeOfVer,TypeOfEdge>::findLessTime()const
//Insert Your Code
{
	cout<<"课程安排为:"<<endl;
LQueue<int>q1,q2;
edgeNode*p;
int current,semester=1;
int *inDegree=new int [Vers];
for(int i=0;i<Vers;++i)
{
	inDegree[i]=0;
}
for( int i=0;i<Vers;++i)
	    for(p=verList[i].head;p!=NULL;p=p->next)
	    ++inDegree[p->end];

	for(int i=0;i<Vers;++i)
		if(inDegree[i]==0) q1.enQueue(i);
		
		while(true){
			if(semester==1)cout<<"第"<<semester<<"学期的课为:";
		while(!q1.isEmpty())
		{
			current=q1.deQueue();
			cout<<verList[current].ver<<" ";
			for(p=verList[current].head;p!=NULL;p=p->next)
			if(--inDegree[p->end]==0)
			q2.enQueue(p->end);
		}
		cout<<endl;

		if(q2.isEmpty()) break;
		++semester;

        cout<<"第"<<semester<<"学期的课为:";

		while(!q2.isEmpty())
		{
			current=q2.deQueue();
			cout<<verList[current].ver<<" ";
			for(p=verList[current].head;p!=NULL;p=p->next)
			if(--inDegree[p->end]==0)
			q1.enQueue(p->end);
		}
		if(q1.isEmpty())break;
		++semester;
		cout<<endl;

		if(semester>1)
		{cout<<"第"<<semester<<"学期的课为:";}
		}






/*//尝试用1个队列解决问题,fail
template<class TypeOfVer,class TypeOfEdge>
void adjListGraph<TypeOfVer,TypeOfEdge>::findLessTime()const
//Insert Your Code
{
	cout<<"课程安排为:"<<endl;
LQueue<int>q1,q2;
edgeNode*p;
int current,semester=1;
int *inDegree=new int [Vers];
for(int i=0;i<Vers;++i)
{
	inDegree[i]=0;
}
for( int i=0;i<Vers;++i)
	    for(p=verList[i].head;p!=NULL;p=p->next)
	    ++inDegree[p->end];

	for(int i=0;i<Vers;++i)
		if(inDegree[i]==0) q1.enQueue(i);
		
		while(true){
			cout<<"第"<<semester<<"学期的课为:";
		while(!q1.isEmpty())
		{
			current=q1.deQueue();
			cout<<verList[current].ver<<" ";
		}
		for(p=verList[current].head;p!=NULL;p=p->next)
			if(--inDegree[p->end]==0)
			q1.enQueue(p->end);
		cout<<endl;

		if(q1.isEmpty()) break;
		++semester;
		}
*/


/*
        cout<<"第"<<semester<<"学期的课为:";

		while(!q2.isEmpty())
		{
			current=q2.deQueue();
			cout<<verList[current].ver<<" ";
			for(p=verList[current].head;p!=NULL;p=p->next)
			if(--inDegree[p->end]==0)
			q1.enQueue(p->end);
		}
		if(q1.isEmpty())break;
		++semester;
		cout<<endl;

		if(semester>1)
		{cout<<"第"<<semester<<"学期的课为:";}
		}




/*
template<class TypeOfVer,class TypeOfEdge>
void adjListGraph<TypeOfVer,TypeOfEdge>::findLessTime()const
//Insert Your Code
{
	cout<<"课程安排为:"<<endl;
LQueue<int>q1,q2;
edgeNode*p;
int current,semester=1;
int *inDegree=new int [Vers];
for(int i=0;i<Vers;++i)
{
	inDegree[i]=0;
}
for( int i=0;i<Vers;++i)
	    for(p=verList[i].head;p!=NULL;p=p->next)
	    ++inDegree[p->end];

	for(int i=0;i<Vers;++i)
		if(inDegree[i]==0) q1.enQueue(i);
		
		while(true){
			if(semester==1)cout<<"第"<<semester<<"学期的课为:";
		while(!q1.isEmpty())
		{
			current=q1.deQueue();
			cout<<verList[current].ver<<" ";
			for(p=verList[current].head;p!=NULL;p=p->next)
			if(--inDegree[p->end]==0)
			q2.enQueue(p->end);
		}
		cout<<endl;

		if(q2.isEmpty()) break;
		++semester;

        cout<<"第"<<semester<<"学期的课为:";

		while(!q2.isEmpty())
		{
			current=q2.deQueue();
			cout<<verList[current].ver<<" ";
			for(p=verList[current].head;p!=NULL;p=p->next)
			if(--inDegree[p->end]==0)
			q1.enQueue(p->end);
		}
		if(q1.isEmpty())break;
		++semester;
		cout<<endl;

		if(semester>1)
		{cout<<"第"<<semester<<"学期的课为:";}
		}
*/




/*{
	cout<<"课程安排为:"<<endl;
	int tmp=1;
	int i;
	LQueue<int>q;
	edgeNode *p;
	int current,*inDegree;
	inDegree=new int [Vers];
	for(i=0;i<Vers;++i) inDegree[i]=0;
	for(i=0;i<Vers;++i)
	    for(p=verList[i].head;p!=NULL;p=p->next)
	    ++inDegree[i];

		/*for(i=0;i<Vers;++i) if(inDegree[i]==0)
		q.enQueue(i);*/
   
   /* int y;
	int num=Vers;
	while(num!=0)
	{
    y=0; 
    for(i=0;i<Vers;i++)
    {
		if(inDegree[i]==tmp-1)
		{
			q.enQueue(i);
		    num--;
	        y++;
		}
	}

	cout<<"第"<<tmp<<"学期的课为:";
	
	for(i=0;i<y+1;i++)
		{
			current=q.deQueue();
			cout<<verList[current].ver<<" ";
		}

	tmp=tmp+1;
	
	}
*/



	/*
	    while(!isEmpty())
		{
			cout<<"第"<<tmp<<"学期的课为:";
			current=q.deQueue();
			cout<<verList[current].ver<<" ";
			cout<<endl;
			for(p=verList[current].head;p!=NULL;p=p->next)
			if(--inDegree[p->end]==0) 
			{
				q.enQueue(p->end);
		    }
			tmp=tmp+1;

			}
*/
return ;
}

被注释符号注释掉的区域为思路历程,欢迎大家探讨!

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
先前提醒一下,由于我并不知道你的数据库表构和数据,以下的语句只是一个参考,需要根据实际情况进行改和调整。 4. 嵌套查询: (1) 查询选修了“离散数学”的学生的学号和姓名。 ```sql SELECT 学号, 姓名 FROM 学生 WHERE 学号 IN (SELECT 学号 FROM 成绩 WHERE 课程号 = 'C1'); ``` (2) 查询课程号为C2的课程的成绩高于张林的学生的学号和成绩。 ```sql SELECT 学号, 成绩 FROM 成绩 WHERE 课程号 = 'C2' AND 成绩 > (SELECT 成绩 FROM 成绩 WHERE 学号 = '张林' AND 课程号 = 'C2'); ``` (3) 查询其他系中年龄小于计算机科学系(CS)中年龄最大者的学生。 ```sql SELECT 学号, 姓名, 年龄, 所在系 FROM 学生 WHERE 年龄 < (SELECT MAX(年龄) FROM 学生 WHERE 所在系 = 'CS') AND 所在系 <> 'CS'; ``` (4) 查询其他系中比计算机科学系(CS)的学生年龄都小的学生。 ```sql SELECT 学号, 姓名, 年龄, 所在系 FROM 学生 WHERE 年龄 < (SELECT MIN(年龄) FROM 学生 WHERE 所在系 = 'CS') AND 所在系 <> 'CS'; ``` (5) 查询和“王洪敏”的“数据库原理及应用课程分数相同的学生的学号。 ```sql SELECT 学号 FROM 成绩 WHERE 成绩 = (SELECT 成绩 FROM 成绩 WHERE 学号 = '王洪敏' AND 课程号 = 'C3') AND 课程号 = 'C3' AND 学号 <> '王洪敏'; ``` (6) 查询没有选修C2课程学生的姓名。 ```sql SELECT 姓名 FROM 学生 WHERE 学号 NOT IN (SELECT 学号 FROM 成绩 WHERE 课程号 = 'C2'); ``` 5. 组合查询和统计查询: (1) 查找选修“计算机基础”课程学生成绩比此课程的平均成绩高的学生的学号和成绩。 ```sql SELECT 学号, 成绩 FROM 成绩 WHERE 课程号 = 'C1' AND 成绩 > (SELECT AVG(成绩) FROM 成绩 WHERE 课程号 = 'C1'); ``` (2) 查询选修“计算机基础”课程学生的平均成绩。 ```sql SELECT AVG(成绩) FROM 成绩 WHERE 课程号 = 'C1'; ``` (3) 查询年龄大于女同学平均年龄的男同学的姓名和年龄。 ```sql SELECT 姓名, 年龄 FROM 学生 WHERE 性别 = '男' AND 年龄 > (SELECT AVG(年龄) FROM 学生 WHERE 性别 = '女'); ``` (4) 列出各系学生的总人数,并按人数进行降序排列。 ```sql SELECT 所在系, COUNT(*) AS 总人数 FROM 学生 GROUP BY 所在系 ORDER BY 总人数 DESC; ``` (5) 统计各系各门课程的平均成绩。 ```sql SELECT 所在系, 课程号, AVG(成绩) AS 平均成绩 FROM 成绩 JOIN 学生 ON 成绩.学号 = 学生.学号 GROUP BY 所在系, 课程号; ``` (6) 查询选修“计算机基础”和“离散数学”的学生的学号和平均成绩。 ```sql SELECT 学号, AVG(成绩) AS 平均成绩 FROM 成绩 WHERE 课程号 IN ('C1', 'C2') GROUP BY 学号 HAVING COUNT(*) = 2; ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

少年与白日梦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值