合肥学院计算机科学与技术系课程设计报告2008~2009学年第二期课程程序设计语言Ⅱ课程设计课程设计名称足球联赛积分排名程序学生姓名朱新维学号**********专业班级网络工程(2)指导教师高玲玲、李红2009年6月一.课程设计题目:足球联赛积分排名程序1.设计内容:足球联赛采用主客场双循环赛制,胜一场得3分,平局各得1分,负一场得0分,联赛排名以积分多者在前,当两队(或多队)积分相同时,则净胜球(即进球数与失球数之差)多者在前,若净胜球相同,则进球数多者在前,若仍相同,则抽签或踢附加赛决定名次(这在联赛结束后进行,联赛未结束则两队名次并列,本程序不做这方面要求)。
试编写一个足球联赛积分排名程序,程序统计最近一轮比赛后,各队积分及排名。
2.任务和要求:假设积分表结构如下:队名(不超过15个字符),已比赛的场数,赢的场数,平的场数,负的场数,进球数,失球数,积分。
积分表放在正文文件中。
最近一轮的结果从键盘输入,其形式为:主队名(可用代码),客队名(可用代码),主队得分(即进球数),客队得分(即进球数)。
程序应根据此轮结果修改各队的积分和名次,所得的最新记分表仍在原积分文件中并同时在屏幕上显示。
3.测试数据:可选择我国当年的甲A或甲B联赛的数据输入,并检查与报章公布的数据是否一致。
二.问题的分析本学年,上学期中我们学习了C语言,初步了解了如何用计算机语言来写出我们所需的程序。
然后下学期中进一步学习了C++语言,通过半年的更深层次的学习,我也初步学会应用类与对象,数组与指针,继承与派生等等来解决一些C++语言程序中的一些实际问题。
看完这个要求,这个题目要求我实现以下几个功能:1).能够输入比赛的2个队伍和其进球数;2).能够对比赛的赢输平进行判定;3).能够根据比赛的赢输平进行积分的累加;4).能够对积分的高低对各个队伍进行排序,特别是在有些队伍积分相同时,可以通过对赢的场次的多少,或者平的场次的多少,输的场次的多少乃至进球数和失球数的多少来进行最终的比较和排序;5).能够将数据存储在一个文件中,可以将文件中的数据进行输入和输出。
我想到,首先我可以运用类和数组先来解决多个足球队的问题。
我可以首先定义一个球队类和对象数组,那么每个球队就都是球队类的对象,并且由于联赛中参赛的队伍数是固定的,那么我就可以将每个球队存放在对象数组的一个数组元素中。
然后是解决如何正确计算,保存和输出比赛的胜,平,负所得的积分,并且要对各个队伍和积分排列出正确的顺序。
经过思考,我的想法是把所有的队伍编号,队伍名称,赢输平的场次,进和失的球数统统归纳到一个足球类里,然后构建函数,通过对函数的调用来实现上述要求。
但事实操作中发现,如果仅仅是这样不仅程序会很繁杂,而且很容易出现错误,于是我考虑继续用一个类来解决函数调用的问题。
用类是解决了上述的问题,但是到底如何进行排序,我想了很久,也试着写了些简单的程序,但都解决不了全部的问题。
后来我在网上查找资料,发现了一个乒乓球比赛排序方法,和我所要做的这个程序有很多相似的地方,特别是排序方面,于是我决定把它的排序改动一下,用在我的程序上。
这样,大的思路方面基本解决了,下面就是,开始写程序了。
三.算法的设计因为一开始写程序时总是会把多个类的定义,函数的调用等弄混淆掉,导致程序产生了很多运行逻辑的错误。
后来我在查找资料时看到一个例子,可以用一个程序调用另外一个相关的程序,这样不仅使程序看上去简洁不少,也使各个程序的作用更加明了。
所以我觉定把整个程序分为2个分程序,通过一个程序来调用另一个程序来实现题目的要求。
于是我先写了一个“football(b)”的程序,首先解决对足球类的定义,建立一个class football把courseNo队伍编号,name队伍名字,credit积分,wNume赢,sNume输,pNume平,jNume进球数,dNume失球数放与这个类中并进行定义,然后进行函数的构造,并且把上述各个属性的设置或者获取方法设置出来。
然后是设置结果,也就是积分的设置。
首先定义一个函数void setResult(int n1,int n2)然后根据进球数和失球数jNume+=n1和dNume+=n2来进行判断,这里有三中情况如下if(n1>n2)时也就是主队赢了,那么有credit+=3;wNume++;然后时else if(n1==n2)这是2队打平了,那么有credit++和pNume++;最后用一个else时,表示的时客队赢了那么sNume+=1。
积分设置过后就是队伍的排序了,这里也有种特殊情况,也就是主队客队的积分相同那么致力就要分为几种情况了这里就要根据赢的场次的多少,或者平的场次的多少,输的场次的多少乃至进球数和失球数的多少来进行最终的比较和排序。
通过在网上查找的资料及程序(乒乓球比赛排序)了解到bool布尔型变量可用于逻辑表达式,也就是“或”“与”“非”之类的逻辑运算和大于小于之类的关系运算,逻辑表达式运算结果为真或为假。
所以这里我选取了网上所查找到的“乒乓球比赛排序方法”中的关于排序的模块加以更改用在了我的程序上。
这样一来“football(b)”这个程序就大体上的框架就完成了。
最后还需要用一个#endif来结束条件编译,这也是出现了错误后才发现的。
接下来是“football(a)”这个程序。
这里我首先用了一个头文件“vector”,用以存放任意类型的动态数组和增加和压缩数据。
同时根据题目要求我可以输入2个队伍及这2个队伍的进球数,并且要可以在后续的操作中读取前面已经输入的数据及排名情况,所以我在这里通过建立程序外的一个文件来对积分表进行记录,所以这里我用了一个头文件“fstream”,然后用了一个“ifsream”(标准输入文件流)定义了一个“f.txt”的文件用以保存积分表。
然后可以用了一个动态的“vector<football> fbList”,将文件中的内容存放在fbList数组中,这里可以将上面已经定义了的football类里的成员保存在这里。
后续的任务是排序,在这里我运用了“iomanip”这个头文件,然后用了setw()的模式对输出格式进行了排列。
然后完成对实验数据的输入的表达,及下来就是对所输入的数据的处理了。
只这里我一开始只考虑到fbList数组中的两种情况,一是数组中已经有了某组队伍,二是数组中还没有这组队伍,后来在实际的调试中发现了错误,通过向老师咨询,在程序中重新添加了一种数组是空的,即文件中没有某队任何的信息的情况。
需要注意的是在这里的排序中会调用“football(b)”这个程序。
后面的sort是调用了程序“football(b)”的来进行排序。
最后是是关于排序等处理后的输出,这里一样用了setw()的模式。
并且括号里个数值要于开始的相同。
四.上机调试过程通过上面的问题分析和算法的设计,并且查找了许多资料和获得了老师的指导和帮助,初程序终于可以上机进行调试了。
这里首先是对“football(b)”的调试。
一开始调试。
直接出现一百多个错误和二十几个警告,顿时呆了。
然后首先开始寻找一些不应该出现的小错误。
解决了一些对“;”的漏写和“{}”的不配套等等的小问题后,错误减少到了二十几个。
后来查找类似的A程序调用B程序的例子,发现它们很多都使用了#ifndef x#define x...#endif模式,然后上网查找了解到了它们的意思:条件指示符#ifndef检查预编译常量在前面是否已经被定义。
如果在前面没有被定义,则条件指示符的值为真,于是从#ifndef到#endif之间的所有语句都被包含进来进行处理。
相反,如果#ifndef指示符的值为假,则它与#endif指示符之间的行将被忽略。
条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译。
并且#ifndef x//先测试x是否被定义过#define x//如果没有定义下面就定义x并执行下面的语句...#endif//如果已经定义了则执行#endif后面的语句然后询问了老师,在程序中加入了这个模式,然后根据老师指出的错误,运用了this指针指向courseNo和name。
对与最后的对大于和小于号的重载和为以后调用sort方法做准备的部分,因为几乎是照搬了一个乒乓球比赛排序程序的类似模块,通过运用布尔型变量,很好的解决了问题。
这样,football(b)这个程序就算完成了。
接下来是football(a)。
首先解决的也是一些对“;”的漏写和“{}”的不配套等等的较小的的问题。
然后发现一开始我没有用“vector”这个用以存放任意类型的动态数组和增加和压缩数据的头文件,导致f.txt的建立和判定以及后面的动态数组fbList出现了很多的运行逻辑错误。
后面对fbList.push_back(football(num,name,credit,wNume,sNume,pNume,jNume,dNume))中的fbList.push_back的书写也出现了较大的错误,后在老师的帮助下改正了过来。
后面写football 类中的成员输出的语句时用了for(i=0;i<fbList.size();i++)等,但忘记了定义i,后在这句上加了int i改正了错误。
后面对fbList.size()的运用还是差强人意出现了错误和漏用的地方。
然后后面的因为有了一些例子的对比所以就没有太大的错误了。
五.测试结果及分析现在把文件清空下面测试一组数据a,b 1,2b,c 4,5a,c 3,4d,a 3,3可以预测他们的结果:积分应该是:a 1b 3c 6d 1结果完全正确六.参考书目[1]郑莉.C++语言程序设计(第三版).北京:清华大学出版社[2]李春葆.C++程序设计学习与上机实验指导.北京:清华大学出版社[3]范辉.Visual C++6.0程序设计简明教程.高等教育出版社[4]李龙澍.C++程序设计实训教程.北京:清华大学出版社[5]严蔚敏等.数据结构(c语言版).北京:清华大学出版社,1997年4月第1版[6]胡学钢.数据结构算法设计指导.北京:清华大学出版社,1999年第1版。
七.附录朱新维football(a):#include<iostream>#include<fstream>#include<vector>#include<iomanip>#include<algorithm>#include"朱新维football(b).cpp"using namespace std;int main(){ifstream is("f.txt",ios_base::in);if(!is.good()){cout<<"文件不存在!"<<endl;return 1;}//将文件中的内容保存在fbList数组中vector<football>fbList;while(is.good()){int num=0;string name;int credit;int wNume;int sNume;int pNume;int jNume;int dNume;is>>num>>name>>credit>>wNume>>sNume>>pNume>>jNume>>dNume;if(num!=0){fbList.push_back(football(num,name,credit,wNume,sNume,pNume,jNume,dNume));}}is.close();//排序sort(fbList.begin(),fbList.end());//输出它们的信息cout<<setw(16)<<"名字"<<setw(6)<<"积分"<<setw(5)<<"赢"<<setw(5)<<"输"<<setw(5)<<"平"<<setw(5)<<"进球"<<setw(5)<<"失球"<<endl;int i;for(i=0;i<fbList.size();i++){football f=fbList.at(i);cout<<setw(16)<<f.getName()<<setw(6)<<f.getCredit()<<setw(5)<<f.getWNume()<<setw(5)<<f.getSNume()<<setw(5)<<f.getPNume()<<setw(5)<<f.getJNume()<<setw(5)<<f.getDNume()<<endl;}string name1,name2;int jNume1,jNume2;cout<<"请输入最近一轮比赛的结果:"<<endl;cout<<"请输入主队名:";cin>>name1;cout<<"请输入客队名:";cin>>name2;cout<<"请输入主队进球数:";cin>>jNume1;cout<<"请输入客队进球数:";cin>>jNume2;//如果是数组是空的,即文件中没有任何的信息if(fbList.size()==0){football f;f.setCourseNo(fbList.size()+1);f.setName(name1);f.setResult(jNume1,jNume2);fbList.push_back(f);football f2;f2.setCourseNo(fbList.size()+1);f2.setName(name2);f2.setResult(jNume2,jNume1);fbList.push_back(f2);}else{for(i=0;i<fbList.size();i++){//如果数组中已经有了该队伍if(fbList.at(i).getName()==name1){fbList.at(i).setResult(jNume1,jNume2);break;}else if(i==(fbList.size()-1)){//如果没有该队伍,则新建一个football对象//对它进行一些初始化以后就把它保存在fbList数组中football f;f.setCourseNo(fbList.size()+1);f.setName(name1);f.setResult(jNume1,jNume2);fbList.push_back(f);break;}}for(int i=0;i<fbList.size();i++){if(fbList.at(i).getName()==name2){fbList.at(i).setResult(jNume2,jNume1);break;}else if(i==(fbList.size()-1)){football f;f.setCourseNo(fbList.size()+1);f.setName(name2);f.setResult(jNume2,jNume1);fbList.push_back(f);break;}}}//排序sort(fbList.begin(),fbList.end());cout<<"现在的排名是:"<<endl;cout<<setw(16)<<"名字"<<setw(6)<<"积分"<<setw(5)<<"赢"<<setw(5)<<"输"<<setw(5)<<"平"<<setw(5)<<"进球"<<setw(5)<<"失球"<<endl;//将数组中的信息保存在文件中ofstream os("f.txt",ios_base::out);for(i=0;i<fbList.size();i++){football f=fbList.at(i);cout<<setw(16)<<f.getName()<<setw(6)<<f.getCredit()<<setw(5)<<f.getWNume()<<setw(5)<<f.getSNume()<<setw(5)<<f.getPNume()<<setw(5)<<f.getJNume()<<setw(5)<<f.getDNume()<<endl;os<<setw(5)<<f.getCourseNo()<<setw(16)<<f.getName()<<setw(6)<<f.getCredit()<<setw(5)<<f.getWNume()<<setw(5)<<f.getSNume()<<setw(5)<<f.getPNume()<<setw(5)<<f.getJNume()<<setw(5)<<f.getDNume()<<endl;}system("pause");}朱新维football(b):#include<string>#include<iostream>using namespace std;#ifndef football_CLASS#define football_CLASS//足球类class football{private:int courseNo;//队伍编号string name;//队伍名字int credit;//积分int wNume;//赢int sNume;//输的int pNume;//平int jNume;//进球数int dNume;//失球数public:football(){//构造函数courseNo=0;name="";credit=0;wNume=0;sNume=0;pNume=0;jNume=0;dNume=0;}//构造函数football(int c,string n,int cre,int w ,int s,int p,int j,int d) {courseNo=c;credit=cre;name=n;wNume=w;sNume=s;pNume=p;jNume=j;dNume=d;}//以下是各个属性的设置/获取方法void setCourseNo(int courseNo){this->courseNo=courseNo;}void setName(string name){this->name=name;}int getCourseNo(){return courseNo;}string getName(){return name;}int getCredit(){return credit;}int getDNume(){return dNume;}int getJNume(){return jNume;}int getWNume(){return wNume;}int getSNume(){return sNume;}int getPNume(){return pNume;}//设置结果void setResult(int n1,int n2) {jNume+=n1 ;dNume+=n2;if(n1>n2){credit+=3;wNume++;}else if(n1==n2){credit++;pNume++;}else{sNume+=1;}}//下面是对大于和小于号的重载//为以后调用sort方法做准备bool operator>(football &f){if(this->credit>f.getCredit())return true;if(credit==f.getCredit()){if((jNume-dNume)>(f.getJNume()-f.getDNume()))return true;else if(jNume>f.getJNume())return true;}return false;}bool operator<(football &f){if(this->credit<f.getCredit())return true;if(credit==f.getCredit()){if((jNume-dNume)<(f.getJNume()-f.getDNume()))return true;else if(jNume<f.getJNume())return true;}return false;}};#endif。