目录
项目一:计算机设计大赛赛事统计
一、设计主要要求
【 问题描述】
参加计算机设计大赛的n个学校编号为1~n,赛事分成m个项目,项目的编号为1~m.比赛获奖按照得分降序,取前三名,写一个统计程序产生各种成绩单和得分报表。
【基本要求】
1)每个比赛项目至少有10支参赛队;每个学校最多有6支队伍参赛;
2)能统计各学校的总分;
3)可以按照学校编号或名称,学校的总分、各项目的总分排序输出;
4)可以按学校编号查询学校某个项目的获奖情况;可以按项目编号查询取得前三名的学校;
5)数据存入文件并能随时查询
【设计要求】
1)输入数据形式和范围:可以输入学校的名称,赛事项目的名称。
2)输出形式:有中文提示,各学校分数为整数
3)界面要求:交互设计要合理,每个功能可以设立菜单,根据提示,可以完成相关功能的要求。
4)存储结构:学生自己根据系统功能要求自己设计,但是赛事相关数据要存储在文件中。
【测试数据】
要求使用全部合法数据,整体非法数据,局部非法数据。进行程序测试,以保证程序的稳定。
【实现提示】
假设3<赛事项目数量<=10,学校名称长度不超过20个字符。每个赛事结束时,将其编号、名称输入,并依次输入参赛学校编号、学校名称和成绩。
二、问题的分析与任务定义
根据项目要求,要实行交互设计,输入各学校名称和该校所参加的赛事名称以及在各项目中各学校所获得的分数,并根据不同的要求进行输出排序,如果按照分数就输出排名前三的学校。如果根据学校编号就输出该编号学校中某项目的分数和排名。
三、逻辑设计
3.1数据结构
数据类型定义:为了实现各学校和各项目的赛事统计情况,需要设计两个结构体来存放各项的信息,项目类的结构体所存放的是项目的名称,项目编号,参加该项目的数量,该队在该项目所获得的名词和分数。学校类结构体是用来存放学校的编号,学校的名称,各学校所得的总分,各学校在各项目上所获得的总分和比赛项目的数组。
typedef struct
{
int project_id;//项目id
char project_name[20];//项目名称
int project_team;//参加该项目的队伍数量
int score[6];//获得的分数
int rank[6];//获得的名次
}Project;
typedef struct
{
int sch_id;//学校id
char sch_name[20];//学校名称
int all_score;//学校总分
int pro_score[project_maxnum];//学校在各项目里的总分
Project p[project_maxnum];//比赛项目数组
}School;
3.2算法描述
程序中所主要运用的算法有:
void init();//初始界面及赛事系统信息读入
void input();//输入信息
void allscore();//统计各个学校的总分
void sortout();//排序输出:
void idout();// 按学校编号排序
void scoreout(); //按学校总分排序
void projectout();//按各项目总分排序
void seek();// 信息查询:
void idseek();// 按学校编号查询某个项目的获奖情况
void projectseek();//按项目编号查询取得前三名的学校
bool istrue();//检验信息输入是否符合规定
void writetofile();//数据存入文件并随时查询
void readfromfile();//数据已经存入文档之后,再次运行也可以直接运用此函数直接读取文档里的学校和项目信息
四、物理设计
1.文件的读写
void writetofile()
{
std::ofstream out;
out.open("D:\\Test.txt");
for (int i = 0; i < school_num; i++)
{
out << s[i].sch_id << endl;
out << s[i].sch_name << endl;
}
for (int i = 0; i < project_num; i++)
{
out << s[0].p[i].project_id << endl;
out << s[0].p[i].project_name << endl;
}
for (int i = 0; i < school_num; i++)
{
for (int j = 0; j < project_num; j++)
{
out << s[i].p[j].project_team << endl;
if (s[i].p[j].project_team)
{
for (int k = 0; k < s[i].p[j].project_team; k++)
{
out << s[i].p[j].rank[k] << ' ';
}
out << endl;
}
}
}
out.close();
cout << "信息已自动保存到本地txt文件!!!" << endl;
}
void readfromfile()
{
std::ifstream in;
//打开文件
in.open("D:\\Test.txt");
for (int i = 0; i < school_num; i++)
{
char id[2];
char name[20];
in.getline(id, 2, '\n');
in.getline(name, 20, '\n');
s[i].sch_id = id[0] - '0';
strcpy(s[i].sch_name, name);
}
for (int i = 0; i < project_num; i++)
{
char id[2];
char name[20];
in.getline(id, 2, '\n');
in.getline(name, 20, '\n');
for (int j = 0; j < school_num; j++)
{
s[j].p[i].project_id = id[0] - '0';
strcpy(s[j].p[i].project_name, name);
}
}
for (int i = 0; i < school_num; i++)
{
for (int j = 0; j < project_num; j++)
{
char str[2];
in.getline(str, 2, '\n');
s[i].p[j].project_team = str[0] - '0';
if (s[i].p[j].project_team)
{
int t = 0;
char str2[20];
in.getline(str2, 20, '\n');
for (int k = 0; k < strlen(str2); k++)
{
if (str2[k] >= '1' && str2[k] <= '9')
{
s[i].p[j].rank[t] = str2[k] - '0';
switch (s[i].p[j].rank[t])
{
case 0:
s[i].p[j].score[t] = 0;
break;
case 1:
s[i].p[j].score[t] = 10;
break;
case 2:
s[i].p[j].score[k] = 9;
break;
case 3:
s[i].p[j].score[k] = 8;
break;
case 4:
s[i].p[j].score[k] = 7;
break;
case 5:
s[i].p[j].score[k] = 6;
break;
case 6:
s[i].p[j].score[k] = 5;
break;
case 7:
s[i].p[j].score[k] = 4;
break;
case 8:
s[i].p[j].score[k] = 3;
break;
case 9:
s[i].p[j].score[k] = 2;
break;
case 10:
s[i].p[j].score[k] = 1;
break;
}
s[i].all_score += s[i].p[j].score[t];
s[i].pro_score[j] += s[i].p[j].score[t];
t++;
}
}
}
}
}
in.close();
cout << "信息已从本地txt文件读取进来!!!" << endl;
}
2.input函数
void input()
{
for (int i = 0; i < school_num; i++)
{
cout << "请输入学校的编号:";
cin >> s[i].sch_id;
cout << "请输入学校的名称:";
cin >> s[i].sch_name;
}
cout << "**************************************************" << endl;
for (int i = 0; i < project_num; i++)
{
int id;
char name[20];
cout << "请输入项目的编号:";
cin >> id;
cout << "请输入项目的名称:";
cin >> name;
for (int j = 0; j < school_num; j++)
{
s[j].p[i].project_id = id;
strcpy(s[j].p[i].project_name, name);
}
}
cout << "**************************************************" << endl;
for (int i = 0; i < project_num; i++) {
int num;
cin >> num;
if (num < 10) {
i--;
cout << "输入错误!请重新输入!" << endl;
}
else cout << "参加" << s[i].p[i].project_name << "的参赛队伍一共有"<<num<<"支" << endl;
}
cout << "**************************************************" << endl;
do
{
for (int i = 0; i < school_num; i++)
{
for (int j = 0; j < project_num; j++)
{
cout << "请输入" << s[i].sch_name << "参加" << s[i].p[j].project_name << "的队伍个数:";
cin >> s[i].p[j].project_team;
if (s[i].p[j].project_team)
{
cout << "请输入各队伍的分数:";
for (int k = 0; k < s[i].p[j].project_team; k++)
{
cin >> s[i].p[j].rank[k];
switch (s[i].p[j].rank[k])
{
case 0:
s[i].p[j].score[k] = 0;
break;
case 1:
s[i].p[j].score[k] = 10;
break;
case 2:
s[i].p[j].score[k] = 9;
break;
case 3:
s[i].p[j].score[k] = 8;
break;
case 4:
s[i].p[j].score[k] = 7;
break;
case 5:
s[i].p[j].score[k] = 6;
break;
case 6:
s[i].p[j].score[k] = 5;
break;
case 7:
s[i].p[j].score[k] = 4;
break;
case 8:
s[i].p[j].score[k] = 3;
break;
case 9:
s[i].p[j].score[k] = 2;
break;
case 10:
s[i].p[j].score[k] = 1;
break;
}
s[i].all_score += s[i].p[j].score[k];
s[i].pro_score[j] += s[i].p[j].score[k];
}
}
cout << "**************************************************" << endl;
}
}
} while (!istrue());
writetofile();
}
3.按各种情况排序输出函数
void sortout()
{
int ord;
while (true)
{
cout << "*****************************************************************************************************************" << endl;
cout << "*** 您可以输入相应序号来提交请求!输入-1返回主菜单 ***" << endl;
cout << "*** 【1】按学校编号输出 ***" << endl;
cout << "*** 【2】按学校总分输出 ***" << endl;
cout << "*** 【3】按各项目总分输出 ***" << endl;
cout << "*****************************************************************************************************************" << endl;
cin >> ord;
switch (ord)
{
case 1:
idout();
break;
case 2:
scoreout();
break;
case 3:
projectout();
break;
case -1:
return;
default: cout << "您的请求有误!请您重新输入!" << endl;
}
}
}
void scoreout()
{
sort(s, s + school_num, score_out_cmp);
cout << "id:" << '\t' << "名称:" << '\t' << "总分:" << endl;
for (int i = 0; i < school_num; i++)
{
cout << s[i].sch_id << '\t' << s[i].sch_name << '\t' << s[i].all_score << endl;
}
}
void projectout()
{
for (int i = 0; i < project_num; i++)
{
cout << "各学校在项目" << s[0].p[i].project_id << ":" << s[0].p[i].project_name << "的总分排序如下:" << endl;
int temp[school_maxnum], t;
for (int j = 0; j < school_num; j++)
temp[j] = j;
for (int j = 0; j < school_num; j++)
{
for (int k = j + 1; k < school_num; k++)
{
if (s[temp[j]].pro_score[i] < s[k].pro_score[i])
{
t = temp[j];
temp[j] = temp[k];
temp[k] = t;
}
}
}
for (int j = 0; j < school_num; j++)
{
printf("学校编号:%d, 学校总分:%d, 学校在该项目总分:%d\n", s[temp[j]].sch_id, s[temp[j]].all_score, s[temp[j]].pro_score[i]);
}
}
}
项目二:校园导游咨询
一、设计主要要求
【问题描述】
设计一个校园导游程序,为来访的客人提供各种信息查询服务。
【基本要求】
(1) 设计你所在学校的校园平面图,所含景点不少于10个.以图中顶点表示校内各景点,存放景点名称、代号、 简介 等信息;以边表示路径,存放路径长度等相关信息。
(2) 为来访客人提供图中任意景点相关信息的查询。
(3) 为来访客人提供图中任意景点的问路查询,即查询任意两个景点之间的一条最短的简单路径。
【测试数据】
以江苏科技大学长山校区为例。
【实现提示】
一般情况下,校园的道路是双向通行的,可设校园平面图是一个无向网.顶点和边均含有相关信息。
二、问题的分析与任务定义
分析用Dijkstra算法解析最短路径问题的基本方法。实验要求我们给出的示例代码能求解任何两点之间的最短路径。
三、逻辑设计
基于Dijstra算法:求任意两点的最短路径。
3.1 数据结构
数据类型的定义:为了实现最短路径,需要设置两个结构体,一个是Vertex,用于存放景点信息(包括名称,序号,景点介绍),另一个是MGraph,用于存放景点路径等。
typedef struct {
char name[20];
int number;
char description[100];
}Vertex;
typedef struct {
Vertex vertex[MaxSize];//存放景点信息的数组
int edges[MaxSize][MaxSize];//路
int vertexNum, edgeNum;//图的顶点数和边数
}MGraph;
3.2 算法描述
程序中主要使用其中的几个重要算法:
void allspots()
操作结果:浏览学校全景。
void spots()
操作结果:查询景点信息。
void Dijkstra()
操作结果:求出所需景点之间的最短路径。
3.3 Dijkstra算法
void Dijkstra(int v0) {
int i, j, k, minval, S[MAX];
int n = map.vertexNum;
for (i = 0; i < n; i++) {
dist[i] = map.edges[v0][i];
if (dist[i] != MAX) path[i] = v0;
else
path[i] = -1;
}
S[v0] = 1;
dist[v0] = 0;
int num = 1;
path[v0] = -1;
while (num < n) {
k = 0; minval = MAX;
for (j = 0; j < n; j++)
if ((dist[j]) < minval && S[j] != 1) {
minval = dist[j];
k = j;
}
S[k] = 1;
for (j = 0; j < n; j++) {
if (dist[j] > dist[k] + map.edges[k][j]) {
dist[j] = dist[k] + map.edges[k][j];
path[j] = k;
}
}
num++;
}
}
四、物理设计
(1)假设用邻接矩阵表示带权图,又设S为已找到最短路径的终点集合,则初态S={v}时,其中v是源点,且设v所对应的下标为i,辅助数组dist 的每个分量dist[j] 记录从v到vj当前最短路径长度。则初态情况下,dist[i]=0,dist[j]=w[i][j]。
(2) 选择,使得dis[k]=min {dist[j]|vj∈V-S}, 则就是求得的一条从v出发的最短路径终点。令S=SU{}。
(3) 修改dist[u], 其中u∈V-S,u≠k。
若dist[k] +w[k][u] <dist[u], 则修改dist[u] 为
dist[u]= dist[k] + w[k][u]
(4) 重复(2),(3)共n-1次,由此求得从V到其余各点的最短路径。
算法实现:为了便于程序实现,用一个与顶点对应的一维数组S[MaxSize]作为辅助储结构,起到表示所有己求得最短路径长度的顶点所构成的集合与尚未求得最短路径长度的顶点所构成的集合之间的区分作用:其分量S[j]=0表示顶点V尚未求得最短路径长度,S[j]=1表示顶点已求得最短路径长度( j=0,1,···,n-1)。
另设个整型数组path,其分量path[i]保存的值是到达顶点的当前最短路径长度的前驱顶点的下标。初始时,path[j]的值如下设置:
-1, j=i, i为原点v的下标
path[j]= -1, j≠i,且w[i][j]= ∞
i,j≠i,且w[i][j]≠∞
由于到达顶点,的前趋顶点的路径长度也是最短的,所以通过path[j],path[path[j]],...,i 可反向跟踪出由;(=v为源点)到vy的最短路径所经过的顶点下标及顶点。所以path中保存了从源点到其余各个顶点的最短路径信息。
在算法执行中,path的内容也随之变化,即在上述第(3)中,当调整从源点到u的当前最短路径长度时,用path[u]=做调整,因是当前最短路径上u的前驱结点。
景点地图:
注:图中数据与现实不符
项目三:算数表达式求解
一、设计主要要求
【问题描述】
设计一个简单的算术表达式计算器。
【基本要求】
实现标准整数类型的四则运算表达式的求值(包含括号,可多层嵌入)。
【测试数据】
(30+2*70)/3-12*3
5+(9*(62-37)+15)*6
要求自行设计非法表达式,进行程序测试,以保证程序的稳定运行。
【实现提示】
可以设计以下辅助函数
status isNumber(char ReadInChar); //视ReadInchar 是否是数字而返回 TRUE 或 FALSE 。
int TurnToInteger(char IntChar); // 将字符’0’.’9’ 转换为整数 9
二、问题的分析与任务定义
分析用堆栈解析算术表达式的基本方法。实验要求我们给出的示例代码能求解任何包括+,-,*,/,()和0到9数字组成,可多层嵌入的算术表达式。设计一个简单的算数表达式计算器。
三、逻辑设计
基于堆栈的算法:从左到右扫描每一个字符。
3.1数据结构
数据类型的定义:为了实现表达式的求值,需要设置两个栈,一个是stack<char>CharStack,用于存放运算符,另一个是stack<double>NumStack,用于存放运算数和运算结果。这里将栈定义为double类型是考虑到算数中除法的结果有可能出现double类型的。
利用C++STL库,不需要写出有关栈的所有操作算法,直接#include<stack>,程序中主要使用其中的几个重要算法:
Stack.pop()
操作结果:取出并删除该栈的顶部元素。
Stack.top()
操作结果:只取出栈的顶元素,而不删除。
Stack.push(T x)
操作结果:将某数据类型的x压栈。
3.2算法描述
在求值过程中所用到的算法:
bool isOpe(char ch)
操作结果:判断所扫描的当前字符是否是运算符。
bool isNum(char ch)
操作结果:判断所扫描的当前字符是否是数字。
int cmp(char inStack, char outOfStack)
操作结果:比较栈顶运算符和正在被扫描的当前运算符,若当前运算符优先级大于栈顶运算符则返回-1,若栈顶运算符优先级大则返回1。
double calculation(char ch, double num1, double num2)
操作结果:计算当前运算符所涉及的运算数的值并返回。
double Trans(string str)
操作结果:计算出表达式的值并返回。
四、物理设计
求值的过程是自左至右扫描每一个字符,
·当扫描到的是运算数时,则将其压入栈NumStack,
·当扫描到的是运算符时
·若这个运算符比CharStack栈顶运算符的优先级高,则入栈CharStack,继续向后处理。
·若这个运算符比CharStack栈顶运算符的优先级低,则从NumStack栈中弹出两个运算数,从CharStack栈中弹出栈顶的运算符并进行运算,并将运算结果压入栈NumStack。
·继续处理当前字符,直到遇到结束符“#”为止。