C++十字链表实现教学计划编制

本文介绍了一种基于图的拓扑排序的教学计划编制算法,通过十字链表实现课程之间的先修关系,旨在解决课程安排问题,确保课程先修顺序正确,同时提供两种编排策略:学习负担均匀分配与课程集中安排。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

教学计划编制问题(图的拓扑排序)


[问题描述]
大学的每个专业都要制定教学计划。假设任何专业都有固定的学习年限,每学年含两学期,每学期的时间长度和学分上限值均相等。每个专业开设的课程都是确定的,而且课程在开设时间的安排必须满足先修关系。每门课程有哪些先修课程是确定的,可以有任意多门,也可以没有。每门课恰好占一个学期。试在这样的前提下设计一个教学计划编制程序。用十字链表实现图的存储结构。
输入参数应包括:学期总数,一学期的学分上限,每门课的课程号、学分和直接先修课的课程号。
应允许用户指定下列两种编排策略之一:一是使学生在各学期中的学习负担尽量均匀;二是使课程尽可能地集中在前几个学期中。

[具体实现]

#include <iostream>
#include <string>
#include <stack>

using namespace std;

const int MAX_VERTEX_NUM=100;//最大课程总数

typedef struct ArcBox
{
    int tailvex;
    int headvex;
    ArcBox *headlink;
    ArcBox *taillink;
    ArcBox(int tailv, int headv, ArcBox *headl = nullptr, ArcBox *taill = nullptr) :tailvex(tailv), headvex(headv), headlink(headl), taillink(taill){}
}ArcNode;

typedef struct VexNode
{
    string classid; //课程号
    int credit;//学分
    int indegree;//入度
    int state;//1代表已学,0代表未学
    ArcBox *firstin;
    ArcBox *firstout;
}VNode,AdjList[MAX_VERTEX_NUM];

typedef struct
{
    AdjList vertices;
    int vexnum,arcnum;
}ALGraph;

int getPosition(string &el,ALGraph &G)
{
    int i;
    for (i = 1; i <= G.vexnum; i++)
    {
        if (G.vertices[i].classid==el)
            return i;
    }
    return -1;
}

void CreateGraph(ALGraph &G)//构建图
{
    int i,p1,p2;
    string m,n;
    ArcNode *enode;
    cout<<"请输入需要编排课程总数:"<<endl;
    cin>>G.vexnum;
    for( i=1;i<=G.vexnum;i++)
    {
        cout<<"请输入课程号:"<<endl;
        cin>>G.vertices[i].classid;
        cout<<"请输入该课程的学分:"<<endl;
        cin>>G.vertices[i].credit;
        G.vertices[i].indegree=0;
        G.vertices [i].state=0;//未学习
        G.vertices[i].firstin=nullptr;
        G.vertices[i].firstout=nullptr;
    }
    cout<<"请输入课程先修关系总数:"<<endl;
    cin>>G.arcnum;
    cout<<"请顺序输入每个课程先修关系(如输入C01 C02,表示<C01,C02>):"<<endl;
    for (i = 1; i <= G.arcnum; i++)
    {
        cout<<"第"<<i<<"条关系:"<<endl;
        cin>>n>>m;
        p1=getPosition(n, G);
        p2=getPosition(m, G);
        G.vertices[p2].indegree++;
        enode = new ArcBox(p1, p2, nullptr, nullptr);;
        if (G.vertices[p1].firstout==nullptr)
            G.vertices[p1].firstout = enode;
        else
        {
            ArcBox *move = G.vertices[p1].firstout;
            while (move->taillink != nullptr)
                move = move->taillink;
            move->taillink = enode;
        }
        if (G.vertices[p2].firstin==nullptr)
            G.vertices[p2].firstin = enode;
        else
        {
            ArcBox *move = G.vertices[p2].firstin;
            while (move->headlink != nullptr)
                move = move->headlink;
            move->headlink = enode;
        }
    }
}

/*
//利用十字链表的特性寻找节点的入度(为了简化,这里在输入的时候直接对入度进行统计)
void FindInDegree(ALGraph G, int indegree[])//求图中各节点的入度
{
    int i;
    for (i = 1; i <= G.vexnum; i++)
        indegree[i] = 0;
    for(i=1;i<=G.vexnum;i++){
        ArcBox *p=G.vertices[i].firstin;
        while(p){
            indegree[i]++;
            p=p->headlink;
        }
    }
}
*/

void TopologicalSort_1(ALGraph G,int numterm,int uplcredit)//课程尽可能集中到前几个学期
{
    struct ArcBox *p;
    stack<int> S;
    //int indegree[MAX_VERTEX_NUM];//存放各节点的入度
    int i,j,k;
    int count; //课程编括排数目计数器
    int sumcredit;//每个学期的课程学分累加器
    //FindInDegree(G,indegree);
    /*
    for(i=1;i<=G.vexnum;i++){
        G.vertices[i].indegree=indegree[i];
    }
     */
    count=0;
    k=0;
    while(count!=G.vexnum && k<=numterm)
    {
        sumcredit=0;
        for(i=1;i<=G.vexnum;i++)
            if((G.vertices[i].indegree==0)&&(G.vertices[i].state==0))//入度为零的节点入栈,即无先修的课程入栈
            {
                S.push(i);
                G.vertices[i].state =1;//避免入度为零节点重复入栈
            }
        if((!S.empty())&&(sumcredit<=uplcredit))
        {
            k= k+1;
            cout<<endl;
            cout<<"第"<<k<<"个学期学得课程有:"<<endl;
            sumcredit = 0;
            for(i=1;i<=G.vexnum;i++)
                if((G.vertices[i].indegree==0)&&(G.vertices[i].state==0))//入度为零的节点入栈,即无先修的课程入栈
                    S.push(i);
            while((!S.empty())&&(sumcredit<uplcredit))//栈非空&&学分总数小于总学分上限
            {
                j=S.top();
                S.pop();
                sumcredit = sumcredit + G.vertices[j].credit;
                if(sumcredit <= uplcredit)
                {
                    cout<<G.vertices[j].classid<<" ";
                    count++;
                    for(p=G.vertices[j].firstout;p;p=p->taillink)//对j号顶点每个邻接点的入度减一
                        G.vertices[p->headvex].indegree--;
                }
                else S.push(j);//将未输出的节点重新压入栈
            }
        }
    }
    cout<<endl;
    if(count<G.vexnum)
        cout<<"\n课程编排出错\n";
    else
    {
        cout<<endl<<"课程编排成功"<<endl;
    }
}

void TopologicalSort_2(ALGraph G,int numterm,int uplcredit)//课程尽量均匀分布
{
    struct ArcBox *p;
    stack<int> S;
    //int indegree[MAX_VERTEX_NUM];//存放各节点的入度
    int i,j,k;
    int maxnum;
    int sumnum;
    int count; //课程编排数目计数器
    int sumcredit;//每个学期的课程学分累加器
    //FindInDegree(G,indegree);
    /*
     for(i=1;i<=G.vexnum;i++){
     G.vertices[i].indegree=indegree[i];
     }
     */
    count=0;
    k=0;
    maxnum=G.vexnum/numterm+1;
    sumnum=0;
    while(count!=G.vexnum && k<=numterm)
    {
        sumcredit=0;
        for(i=1;i<=G.vexnum;i++)
            if((G.vertices[i].indegree==0)&&(G.vertices[i].state==0))//入度为零的节点入栈,即无先修的课程入栈
            {
                S.push(i);
                G.vertices[i].state =1;//避免入度为零节点重复入栈
            }
        if((!S.empty())&&(sumcredit<=uplcredit))
        {
            k= k+1;
            cout<<endl;
            cout<<"第"<<k<<"个学期学得课程有:"<<endl;
            sumcredit = 0;
            sumnum=0;
            for(i=1;i<=G.vexnum;i++)//入度为零的节点入栈,即无先修的课程入栈
                if((G.vertices[i].indegree==0)&&(G.vertices[i].state==0))
                    S.push(i);
            while((!S.empty())&&(sumcredit<uplcredit)&&(sumnum<maxnum))//栈非空&&学分总数小于学分上限&&不超过每学期课程上限
            {
                j=S.top();
                S.pop();
                sumcredit = sumcredit + G.vertices[j].credit;
                sumnum=sumnum+1;
                if((sumcredit<=uplcredit)&&(sumnum<=maxnum))
                {
                    cout<<G.vertices[j].classid<<" ";
                    count++;
                    for(p=G.vertices[j].firstout;p;p=p->taillink)//对j号顶点每个邻接点的入度减一
                        G.vertices[p->headvex].indegree--;
                }
                else S.push(j);//将未输出的节点重新压入栈
            }
        }
    }
    cout<<endl;
    if(count<G.vexnum)
        cout<<"\n课程编排出错\n";
    else
    {
        cout<<endl<<"课程编排成功"<<endl;
    }
}

int main()//主函数
{
    int CONTINUE=1;
    int numterm;//学期总数
    int uplcredit; //一个学期的学分上限
    int selectway;
    ALGraph G;
    cout<<"请输入学期总数:"<<endl;
    cin>>numterm;
    cout<<"请输入一个学期的学分上限:"<<endl;
    cin>>uplcredit;
    CreateGraph(G);
    while(CONTINUE != 0){
        cout<<"请选择编排策略:1.课程尽可能集中到前几个学期;2.课程尽量均匀分布"<<endl;
        cin>>selectway;
        if(selectway==1)
            TopologicalSort_1(G,numterm,uplcredit);
        if(selectway==2)
            TopologicalSort_2(G,numterm,uplcredit);
        cout<<endl<<"按1继续,按0结束:"<<endl;
        cin>>CONTINUE;
    }
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值