c++学习笔记-STL案例-演讲比赛管理系统1

发布时间:2024年01月10日

目录

1演讲比赛需求

1.1 比赛规则

1.2 程序功能

2.项目创建

2.1?创建新项目

2.2 添加文件

3.3 文件添加成功

3.创建管理类

3.1 功能描述

3.2 创建文件

?4? 菜单功能

4.1 功能描述

4.2 添加成员函数

4.3 菜单功能实现?

4.4 main()函数中调用

?4.5 实现结果

5 退出系统功能

5.1 功能描述

5.2 添加成员函数

?5.3 退出功能实现

5.4 main()函数中调用

?5.5 实现结果

6 演讲比赛功能

?6.1 功能分析

6.2 创建选手类

6.3 比赛

6.3.1 成员属性添加

6.3.2 初始化属性

?编辑?6.3.3 创建选手

6.3.4 开始比赛成员函数添加

6.3.5 抽签

6.3.6?开始比赛

6.3.7 显示比赛分数

6.3.8 第二轮比赛

6.4 保存分数

7 查看记录?

7.1 读取分数记录

?7.2 解析文件中数据


1演讲比赛需求

1.1 比赛规则

  • 学校举行一场演讲比赛,共有12个人参加,比赛共两轮,第一轮为淘汰赛,第二轮为决赛。
  • 每名选手都有对应的编号,如10001~10012
  • 比赛方式:分组比赛,每组6个人
  • 第一轮为两个小组,整体按照选手编号进行抽签后顺序演讲
  • 十个评委分别给没名选手打分,去除最高分和最低分,求平均分为本轮选手的成绩
  • 当小组演讲完后,淘汰组内排名最后的三个选手,前三名晋级,进入下一轮的比赛
  • 第二轮为决赛,前三名胜出
  • 每轮比赛过后需要显示晋级选手的信息

1.2 程序功能

开始演讲比赛:完成整届比赛的流程,每个比赛阶段需要给用户一个提示,用户按任意键进入下一个比赛阶段

查看往届记录:查看之前比赛前三名结果,每次比赛都会记录到文件中,文件用.csv后缀保存

清空比赛记录:将文件中数据清空

退出比赛程序:可以退出当前程序

1.3 程序展示

1.开始比赛

(1)选择开始比赛

(2)第一轮比赛开始:抽签→打分→晋级名单?

(2)第二轮比赛开始:抽签→比赛打分→晋级选手(最后冠亚季)?

(3)保存第二轮比赛前三名?

2.查看往届记录

3.?清空比赛记录

?4.退出比赛程序:

2.项目创建

2.1?创建新项目

  • 打开visual Studio 2019 选择“创建新项目”

  • 选择“空项目”

  • 更改项目名称“基于STL的演讲比赛流程管理系统”

2.2 添加文件

1.“源文件”? ? ?“右键”? ? “添加”? ? ?“新建项”

2.更改文件名称为“演讲比赛流程管理系统”

3.3 文件添加成功

3.创建管理类

3.1 功能描述

  • 提供菜单界面与用户交互
  • 对演讲比赛流程进行控制
  • 与文件的读写交互

3.2 创建文件

  • 在头文件和源文件下分别创建speechManager.h和speechManager.cpp文件

?4? 菜单功能

4.1 功能描述

  • 与用户的沟通界面

4.2 添加成员函数

在管理类speechManager.h中添加成员函数? void show_Menu();

4.3 菜单功能实现?

4.4 main()函数中调用

?4.5 实现结果

5 退出系统功能

5.1 功能描述

在main函数中提供分支选择,提供每个功能接口

5.2 添加成员函数

?5.3 退出功能实现

5.4 main()函数中调用

?5.5 实现结果

6 演讲比赛功能

?6.1 功能分析

比赛流程分析:

抽签→开始演讲比赛→显示第一轮比赛结果→

抽签→开始演讲比赛→显示前三名结果→保存比赛分数

6.2 创建选手类

speaker.h中创建Speaker类

6.3 比赛

6.3.1 成员属性添加

在speechManager.h头文件中添加成员属性、initSpeech()函数

6.3.2 初始化属性

1.speechManeger.cpp中初始化函数

2.构造函数中调用initSpeech()?

?6.3.3 创建选手

1.speechManager.h中创建speechManager类的creatSpeaker()函数

2.speechManager.cpp中实现creatSpeaker()函数,创建人员、两轮分数均置为0

3. 构造函数中调用creatSpeaker()函数?

4.测试

main()中写入测试代码:

测试结果:

6.3.4 开始比赛成员函数添加

在speechManager.h中提供开始比赛的成员函数void startSpeech(),该函数功能主要控制比赛流程

在speechManager.cpp中实现startSpeech()? ,此处使用了6.3.5的抽签函数

6.3.5 抽签

1.声明speechDraw()函数

2.实现speechDraw()函数

3.测试speechDraw()函数

case1的时候调用startSpeech()函数,startSpeech()函数中调用了抽取speechDraw()函数

?测试结果

6.3.6?开始比赛

1.声明speechContest()函数

2.增加头文件

  • deque用于打分存储队列,便于去除最高、最低分
  • functional用于map排序
  • numeric算数求和

?3.实现speechContest()函数

总结:

  • (1)multimap<double, int, greater<double>> groupScore
  • 小技巧?:groupScore的key是成绩,value是选手编号可以插入重复的成绩并从大到小排序,greater<double>是#include<functional> ?内建函数实现从大到小排序,
  • (2)vector<int>v_Src;//比赛选手容器? ?
  • 小技巧:通过if条件判断是第一轮则v_Src=v1,第二轮v_Src=v2,可有效重复利用切换数据进行打分和分数计算
  • (3)if (num % 6 == 0)?
  • 小技巧:12个选手,分两组,所以除6余数为0则是一组,小组赛前三名需要进行第二轮比赛,所以小组前三取出存v2,v2的前三就是vVictory
void SpeechManager::speechContest()
{
	cout << "--------第<<" << this->m_Index << ">>轮比赛正式开始--------" << endl;

	//准备临时容器  存放小组成绩
	multimap<double, int, greater<double>> groupScore;

	int num = 0;// 记录人员个数

	vector<int>v_Src;//比赛选手容器

	if (m_Index == 1)
	{
		v_Src = v1;
	}
	else
	{
		v_Src = v2;
	}

	//所有的选手进行比赛
	for (vector<int>::iterator it = v_Src.begin(); it != v_Src.end(); it++)
	{
		num++;
		//评委打分
		deque<double>d;
		for (int i = 0; i < 10; i++)
		{
			double score = (rand() % 401 + 600) / 10.f;   //600~1000
			//cout << score << "  ";
			d.push_back(score);
		}
		//cout << endl;
		sort(d.begin(), d.end(), greater<double>());//排序 从大到小
		d.pop_front();//去除最高分
		d.pop_back();//去除最低分

		double sum = accumulate(d.begin(), d.end(), 0);   //分数求和
		double avg = sum / (double)d.size();    //平均分
		
		//打印平均分
		//cout << "编号: " << *it << "  姓名:" << this->m_Speaker[*it].m_Name << "  平均分" << avg;
		//将平均分放入map容器
		this->m_Speaker[*it].m_Score[this->m_Index - 1] = avg;
		//cout << endl;

		//将打分数据放入临时小组容器中
		groupScore.insert(make_pair(avg, *it));//key是得分,value是具体选手编号
		//六人取出前三名
		if (num % 6 == 0)
		{
			cout << "第 " << num / 6 << " 小组比赛名次:" << endl;
			for (multimap<double, int, greater<double>>::iterator it = groupScore.begin(); it != groupScore.end(); it++)
			{
				cout << "编号: " << it->second << "  姓名:" << this->m_Speaker[it->second].m_Name << "  成绩:"
					<< this->m_Speaker[it->second].m_Score[this->m_Index - 1] << endl;
			}

			//取走前三名
			int count = 0;
			for (multimap<double, int, greater<double>>::iterator it = groupScore.begin(); it != groupScore.end() && count<3; it++,count++)
			{
				if (this->m_Index == 1)
				{
					v2.push_back((*it).second);
				}
				else
				{
					vVictory.push_back((*it).second);
				}
			}

			groupScore.clear();//小组容器清空
			cout << endl;
		}


	}
	cout<<"--------第<<" << this->m_Index << ">>轮比赛完毕!--------" << endl;
	system("pause");
}

?4.测试speechContest()函数?

测试结果:

6.3.7 显示比赛分数

1.声明showScore()函数

  • 在speechManager.h中添加保存记录的成员函数void showScore();

2.实现showScore()函数

  • 在speechManager.spp中实现的成员函数void showScore();

3.测试showScore()函数

6.3.8 第二轮比赛

6.4 保存分数

1.声明saveRecord()函数

  • #include<fstream? //添加头文件

  • 在speechManager.h中添加保存记录的成员函数void saveRecord();

?2.实现saveRecord()函数

  • 在speechManager.cpp中实现成员函数void saveRecord();

3.测试saveRecord()函数

测试结果:?

?

7 查看记录?

7.1 读取分数记录

1.声明成员函数loadRecord()、是否为空的标志fileIsEmpty、往届记录的容器map

  • 在speechManager.h中添加保存记录的成员函数void loadRecord();
  • 添加判断文件是否为空的标志 bool fileIsEmpty;
  • 添加往届记录的容器map<iny,vector<string>> m_Record;
  • 其中m_record中的key代表第几届,value记录具体的信息

2. 在speechManager.cpp中实现成员函数void loadRecord()

void SpeechManager::loadRecord()
{
	ifstream ifs("speech.csv", ios::in);//读文件
	if (!ifs.is_open())
	{
		this->fileIsEmpty = true;
		cout << "文件不存在" << endl;
		ifs.close();
		return;
	}

	//文件清空
	char ch;
	ifs >> ch;
	if (ifs.eof())
	{
		cout << "文件为空" << endl;
		this->fileIsEmpty = true;
		ifs.close();
		return;
	}

	//文件不为空
	this->fileIsEmpty = false;
	ifs.putback(ch);//将上面读取的单个字符再放回
	
	string data;
	while (ifs >> data)
	{
		cout << data << endl;
	}
	ifs.close();
}

3.测试? loadRecord()

构造函数加载记录,测试结果有两条往届记录:

?7.2 解析文件中数据

while (ifs >> data)
	{
		//cout << data << endl;
		//10002,86.375,10009,81,10010,78,

		vector<string>v;//存放6个string字符串

		int pos = -1;//查到","位置的变量
		int start = 0;
		while (true)
		{
			pos = data.find(",", start);
			if (pos == -1)
			{
				//没有找到的情况
				break;
			}
			string temp = data.substr(start, pos - start);
			//cout << temp << endl;
			v.push_back(temp);
			start = pos + 1;
		}

		this->m_Record.insert(make_pair(index, v));
		index++;

	}

通过“,”查找分割每个数据,数据为编号、得分、编号、得分、编号、得分,并将查找结果进行记录到v中,m_Recoed记录:届数index+每届前三名得分情况v,循环读入每节届的得分情况。

7.3 查看往届记录

1.speechManager.h中声明成员函数showRecord()

2.speechManager.cpp中实现成员函数showRecord()

3.测试showRecord()

测试结果:

7.4 bug解决

目前程序中有几处bug未解决:

1.查看往届记录,若文件不存在或者为空,并未提示:

解决方式:在showRecord()函数中,判断文件状态

2.若记录为空或不存在,比赛后依然提示记录为空

解决方式:saveRecord()中更新文件为空标志

3.比玩赛后查找不到本届比赛的记录,没有实时更新

解决方式:比赛完毕后,所有数据重置

4.在初始化时,没有初始化记录容器

解决方式:initSpeech()中添加? 初始记录容器

5.每次记录都是一样的

解决方式:在main()函数一开始? 添加随机数种子

结果显示:

8 清空记录

8.1 清空功能实现

1.在speeckManager.h中添加清空记录的成员函数void clearRecord();

2.在speeckManager.cpp中实现清空记录的成员函数void clearRecord();

8.2 清空功能测试

测试结果:

?

文章来源:https://blog.csdn.net/qq_26572229/article/details/135401614
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。