基于STL的演讲比赛流程管理系统

1 理论基础

1.1 容器

本学习案例采用C++STL实现,所有用到的容器如图,在使用时均需包含其头文件。

容器特点
vector单端数组形式,可动态扩展
deque双端数组形式,头尾端均可动态扩展
map所有元素都以对组的形式存储(key,value)
multimap允许map容器中有重复的元素

1.2 算法

在本案例中用到了排序算法random_shuffle、sort,以及常用算术生成算法accumulate,在其头文件中要加上< algorithm >和< numeric >头文件

算法功能
random_shuffle随意打乱容器中所有元素的次序
sort对容器中的元素进行从小到大排序
accumulate计算区间内容器的累加和

在本案例中还需要用到仿函数:采用STL里面内建的关系仿函数:greater(),可实现容器元素自定义排序。内建函数加头文件< functional >
谓词:返回bool类型的仿函数为谓词
一元谓词:如果重载函数operator()接受一个参数,叫一元谓词;
二元谓词:如果重载函数operator()接受两个参数,叫二元谓词。

2 需求分析

  • 12个选手进行参加演讲比赛,首先将这12个人(ABCDEFGHIJKL)分成两组,每组6个人,其次将这12人打乱抽签,使其依次进行演讲;
  • 演讲的成绩由10个评委打分,每个人的分数都由这10个分数去掉最低和最高分取平均而得出;
  • 首先进行第一轮比赛,取每组前三名共计6人进入第二轮;
  • 其次第二轮中取前三名为冠亚季军;
  • 每次的冠亚季军的编号及其成绩都会记录在文件中,并可显示在屏幕上;
  • 程序中也可删除历史的记录

3 代码实现

在整个程序中添加了一个SpeechManager类和Speaker类,以下为整个程序的逻辑思路以及代码:

3.1 界面的显示及其功能

在运行程序时,首先即为登陆界面的显示,在此案例中登陆界面分为四个功能:开始比赛,查看往届记录,清空比赛记录,退出比赛程序

void SpeechManager::show_menu()
{
	cout << "*************************************" << endl;
	cout << "***********欢迎参加演讲比赛**********" << endl;
	cout << "***********1. 开始演讲比赛***********" << endl;
	cout << "***********2. 查看往届记录***********" << endl;
	cout << "***********3. 清空比赛记录***********" << endl;
	cout << "***********4. 退出比赛程序***********" << endl;
	cout << "*************************************" << endl;
	cout << endl;
}

在main函数中,实现对功能的选择。

SpeechManager sm;
	int choice = 0;//存储用户输入
	while (true)
	{
		sm.show_menu();
		cout << "请输入您的选择:" << endl;
		cin >> choice;
		
		switch (choice)
		{
		case 1://开始比赛
			sm.startSpeech();
			break;
		case 2://查看往届比赛记录
			sm.showRecord();
			break;
		case 3://清空比赛记录
			sm.clearRecord();
			break;
		case 4://退出系统
			sm.exit_menu();
			break;
		default:
			system("cls");//清屏
			break;
		}
	}
	system("pause");
	return 0;

3.2 创建选手及初始化

在案例中用3个vector容器分别存储比赛开始前的12个选手的编号、第二轮比赛的6个选手编号、最后冠亚季军的3个选手编号,还有一个map容器用来创建<编号+姓名>的容器,并且创建变量最为比赛轮数的索引。
首先是初始化操作:

void SpeechManager::initSpeech()
{
	//初始化容器
	this->v1.clear();
	this->v2.clear();
	this->vVectory.clear();
	this->m.clear();
	this->m_Record.clear();
	//设置当前比赛为第一轮
	m_Index = 1;
}

其次为创建选手,其中选手类中的m_Score[0]为选手第一轮的成绩;m_Score[1]为选手第二轮的成绩,12名选手的编号为10001-10012:

void SpeechManager::createrSpeaker()
{
	string nameID = "ABCDEFGHIJKL";
	for (int i = 0; i < nameID.size(); i++)
	{
		string name = "姓名";
		name += nameID[i];
		Speaker sp;
		sp.m_Name = name;
		sp.m_Score[0] = 0;
		sp.m_Score[1] = 0;

		//将选手放入v1容器中
		v1.push_back(10001 + i);

		//将选手放入map容器
		m.insert(make_pair(10001+i, sp));

	}
}

3.3 开始比赛流程

比赛的流程为:

第一轮比赛:抽签 ——比赛——显示晋级结果
第二轮比赛:抽签——比赛——显示最终结果
记录数据

void SpeechManager::startSpeech()
{
	//第一轮比赛
	//1、抽签
	speechDraw();
	//2、比赛
	speechContest();
	//3、显示晋级结果
	showScore();

	//第二轮比赛
	this->m_Index++;
	//1、抽签
	speechDraw();
	//2、比赛
	speechContest();
	//3、显示最终结果
	showScore();
	//4、记录数据
	saveScore();
	  //重置比赛 ,获取记录
	this->initSpeech();
	this->createrSpeaker();
	this->loadRecord();
	cout << "本届比赛已完毕!" << endl;
	system("pause");
	system("cls");
}
3.3.1 抽签

首先判断是第几轮比赛,获取相对应的容器,采用random_shuffle算法将其中元素随意排序:

void SpeechManager::speechDraw()
{
	cout << "第" << this->m_Index << "轮比赛正在进行中"<<endl;
	cout << "抽签顺序为:" << endl;
	cout << "--------------------------------------------------------------------------------------" << endl;

	if (this->m_Index == 1)
	{
	 random_shuffle(v1.begin(), v1.end());
	 for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
	 {
		 cout << *it << "  ";
	 }
	 cout << endl;
	}
	else
	{
		random_shuffle(v2.begin(), v2.end());
		for (vector<int>::iterator it = v2.begin(); it != v2.end(); it++)
		{
			cout << *it << "  ";
		}
		cout << endl;
	}
	cout << "--------------------------------------------------------------------------------------"<<endl;
	system("pause");
}
3.3.2 比赛(重点部分)

★★★★★此过程为案例中的核心部分★★★★★
首先是用临时容器获取,若是第一轮就是v1,第二轮为v2:

vector<int>v_tem;
	if (this->m_Index == 1)
	{
		v_tem = v1;
	}
	else
	{
		v_tem = v2;
	}

其次就是遍历这个临时容器,将评委打分的分数放入map容器中:

	//评委打分
	for (vector<int>::iterator it = v_tem.begin(); it != v_tem.end(); it++)
	{
		n++;
		deque<double>d;
		//10个评委打分
		for (int i = 0; i < 10; i++)
		{
			double score = (rand() % 401 + 600) / 10.f; //60-100随机一个数
			d.push_back(score);
		}
		//将分数从大到小排序
		sort(d.begin(), d.end(), greater<double>());
		d.pop_back();
		d.pop_front();
		double num = accumulate(d.begin(), d.end(), 0.f);
		double avg = num / d.size();


		//平均分放到map容器中
		this->m[*it].m_Score[m_Index - 1] = avg;

然后创建一个按照分数从大到小的multimap容器

//临时容器 key为分数 value为选手编号 按照分数从大到小排序
	multimap<double, int, greater<double>> group;
在上一步的遍历中加入:group.insert(make_pair(avg, *it));

最后分组,取每组的前三名进入第二轮,其中n为元素的个数,每6个为一组进入if语句:

		if (n % 6 == 0)
		{
			cout << "----------第" << n / 6 << "组:----------" << endl;
			for (multimap<double, int, greater<double>>::iterator it = group.begin(); it != group.end(); it++)
			{
				cout << "编号:" << it->second << " " << "姓名:" << this->m[it->second].m_Name << " " << "分数:" << this->m[it->second].m_Score[m_Index - 1] << endl;
			}
			int count = 0;
				//获取每组的前三名
				for (multimap<double, int, greater<double>>::iterator it = group.begin(); it != group.end() && count < 3; it++, count++)
				{
					if (this->m_Index == 1)
					{
						v2.push_back(it->second);
					}
					else
					{
						vVectory.push_back(it->second);
					}
				}
			

			group.clear();
			cout << endl;
		}
		cout << "----------第" << this->m_Index << "轮比赛完毕----------" << endl;
	system("pause");
3.3.3 显示晋级结果

通过map容器可以读出每轮结束时的晋级选手

void SpeechManager::showScore()
{
	cout << "----------第" << this->m_Index << "轮比赛晋级选手:----------" << endl << endl;
	vector<int>v_temp;
	if (this->m_Index == 1)
	{
		v_temp = v2;
	}
	else
	{
		v_temp = vVectory;
	}

	for (vector<int>::iterator it = v_temp.begin(); it != v_temp.end(); it++)
	{
		cout << "编号:" << *it << " " << "姓名:" << this->m[*it].m_Name << " " << "分数:" << this->m[*it].m_Score[m_Index - 1] << endl;
	}

	system("pause");
	system("cls");
	this->show_menu();
}
3.3.4 保存分数

将冠亚季军的编号和数据保存到.csv文件中,这里创建一个布尔类型的成员变量fileIsEmpty来判断文件是否为空。

void SpeechManager::saveScore()
{
	ofstream ofs;
	ofs.open("speech.csv", ios::out | ios::app);//用追加方式写入文件

	//将每个选手数据写入到文件中
	for (vector<int>::iterator it = vVectory.begin(); it != vVectory.end(); it++)
	{
		ofs << *it << "," << m[*it].m_Score[1] << ",";
	}
	ofs << endl;
	ofs.close();
	cout << "记录已经保存!" << endl;

	//更改文件不为空
	this->fileIsEmpty = false;
}
3.3.5 加载记录

上面将写到文件中,但是写到文件里的内容还有”,“,因此下面用map<int, vector>m_Record容器存放数据

void SpeechManager::loadRecord()
{
	ifstream ifs;
	ifs.open("speech.csv", ios::in);

	//判断文件是否存在
	if (!ifs.is_open())
	{
		this->fileIsEmpty = true;
		cout << "无这个文件" << endl;
	}


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

	//文件打开且不为空
	this->fileIsEmpty = false;
	ifs.putback(ch);//读取的单个字符放回去
	string data;
	int index = 0;
	
	while (ifs>>data)
	{
		//cout << data;
		vector<string>v;
		int pos = -1;
		int start = 0;
		
		while(true)
		{
			pos = data.find(",", start);
			if (pos == -1)
			{
				break;
			//未找到
			}
			string temp = data.substr(start, pos - start); 
			v.push_back(temp);
			start = pos + 1;
		}
		this->m_Record.insert(make_pair(index, v));
		index++;
		
	}
	ifs.close();
	/*for (map<int,vector<string>>::iterator it = m_Record.begin();it!=m_Record.end() ;it++)
	{
		cout <<"第几届: "<<it->first <<"冠军编号:"<<it->second[0]<<"分数:"<<it->second[1]<< endl;
	}*/
}

3.4 查看往届记录

利用上面加载的数据记录,可获得第i+1届的冠亚季军的编号的和成绩

void SpeechManager::showRecord()
{
	if (this->fileIsEmpty)
	{
		cout << "文件为空或者文件不存在!" << endl;
	}
	else
	{
		for (int i = 0; i < m_Record.size(); i++)
		{
			cout << "第" << i + 1 << "届" << "冠军编号:" << m_Record[i][0] << " 得分: " << m_Record[i][1] << "  "
				<< "亚军编号:" << m_Record[i][2] << " 得分: " << m_Record[i][3] << "  "
				<< "季军编号:" << m_Record[i][4] << " 得分: " << m_Record[i][5] << endl;
		}
	}
	system("pause");
	system("cls");
}

3.5 清空比赛记录

当清空比赛记录时,要重新初始化、创建选手、加载记录

void SpeechManager::clearRecord()
{
	cout << "是否确定清空文件?" << endl;
	cout << "1、是" << endl;
	cout << "2、否" << endl;
	int select = 0;
	cin >> select;
	if (select == 1)
	{
		ofstream ofs("speech.csv", ios::trunc);
		ofs.close();
		this->initSpeech();
		this->createrSpeaker();
		this->loadRecord();
		cout << "清空成功!" << endl;
	}
	system("pause");
	system("cls");
}

3.5 退出系统

void SpeechManager::exit_menu()
{
	cout << "欢迎下次使用!" << endl;
	system("pause");
	exit(0);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

rubbish_miao

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

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

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

打赏作者

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

抵扣说明:

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

余额充值