【C++】STL案例:演讲比赛

前言

最近在学C++,看到一个关于使用STL的小作业,一时兴起想做一做。

作业题目

某地举办一次比赛,共有24人参加,比赛总共3轮,前两轮为淘汰赛,最后一轮为决赛。

比赛方式:分组比赛,每组6人;选手每次要随机分组,进行比赛。例如:

  • 第一轮分为4个组,每组6个人,比如所有人的编号为100-123,对这些人编号后随机分为4组,比赛结束后淘汰组内最后3个人,然后继续下一轮比赛。
  • 第二轮分为2个组,每组6个人,比赛结束后淘汰组内最后3个人,然后进行决赛。
  • 决赛只剩下6个人,选出前三名,获奖。

评分规则:10个评委打分,每轮比赛都是去除最高分和最低分,对剩下8个成绩求平均分,选手的名次按平均分降序排序。

要求:用STL编程,每轮比赛结束后打印出晋级的名单。

开始

注:全部在一个.cpp文件里实现,不分文件编写了。

实现思路:根据下面的代码块来讲解。

  • 先导入头文件
#include <iostream>
#define _CRT_SECURE_NO_DEPRECATE
using namespace std;
#include <vector>
#include <deque>
#include <algorithm>
#include <numeric>
  • 定义Person类
class Person
{
public:
	
	string Name;
	deque<int> Score;
	int Id;
	double MeanScore;

};

比赛成绩用一个队列 deque 来存,好处是:排序后便于去掉最高分和最低分,使用pop_front()和pop_back()即可。

  • 产生选手
void CreatPerson(vector<Person>& v)
{
	string names = "ABCDEFGHIJKLNMOPQRSTUVWX";
	int id = 100;
	for (int i = 0; i < names.size(); ++i)
	{
		Person p;
		p.Name = "选手";
		p.Name += names[i];
		p.Id = id + i;

		v.push_back(p);
	}
}

用24个字母代替24个选手,函数传入的是一个vector的引用,里面放的是所有选手的对象实例。

  • 给选手打分
void getScore(vector<Person>& v)
{
	for (vector<Person>::iterator begin = v.begin(); begin != v.end(); ++begin)
	{
		for (int i = 0; i < 10; ++i)
		{
			(*begin).Score.push_back(rand() % 41 + 60);
		}
	}
}

随机生成60-100之间的数字作为每个选手的分数,用一个迭代器遍历,把分数加到队列Score里。

  • 计算所有选手平均分,并排序
class AvgCompare
{
public:
	bool operator()(Person& p1, Person& p2)
	{
		return p1.MeanScore > p2.MeanScore;
	}
};

bool AvgCompare1(Person& p1, Person& p2)
{
	return p1.MeanScore > p2.MeanScore;
}

void calAvgScore(vector<vector<Person>>& vGroup)
{
	for (vector<vector<Person>>::iterator begin1 = vGroup.begin(); begin1 != vGroup.end(); ++begin1)
	{
		// 对每一组的选手,计算平均分
		for (vector<Person>::iterator begin2 = (*begin1).begin(); begin2 != (*begin1).end(); ++begin2)
		{
			// 先把分数排序
			sort((*begin2).Score.begin(), (*begin2).Score.end(), greater<int>());

			// 去掉最高、最低分
			(*begin2).Score.pop_front();
			(*begin2).Score.pop_back();

			// 计算平均分
			double mean = double(accumulate((*begin2).Score.begin(), (*begin2).Score.end(), 0)) / double((*begin2).Score.size());
			(*begin2).MeanScore = mean;
            // 下面这句按照平均分对选手排序的写法是错误的!
            //sort((*begin2).Score.begin(), (*begin2).Score.end(), AvgCompare()); 错误!!!
		}

		// 按照平均分对选手排序
		//sort((*begin1).begin(), (*begin1).end(), AvgCompare());
		//sort((*begin1).begin(), (*begin1).end(), AvgCompare1);
		sort((*begin1).begin(), (*begin1).end(), [](Person& p1, Person& p2) {return p1.MeanScore > p2.MeanScore; }); 
	}
}

定义一个AvgCompare类,在使用sort()方法对自定义数据类型排序的时候,当仿函数使用。

函数体传入的参数是包含4个小vector的大vector,第一个for遍历每个小vector,第二个for遍历每个小vector里的每个选手。

第2个for里,计算平均分的时候,由于传入的vector里的成绩是未排序的,因此需要先排序,这里使用了内建函数 greater<int>();

第2个for跳出后,再按平均分对选手排序,有三种写法,第一种是用仿函数,第二种忘了叫什么了(额),第三种用了匿名函数(写起来更清爽)。

注意,第1个for里最后注释的那句是错的,两点错误,首先,需求是根据MeanScore来对Person排序,而这句是根据MeanScore对Score排序(完全乱套),其次,参数前后类型要一致,*begin1是vector<Person>,从而才能对其使用sort()算法,(*begin2)是Person,不是容器,当然无法使用sort()。

  • 第k轮比赛,对所有选手随机分组,进行比赛,获得分数
// 参数含义:第round轮比赛,共n组,每组k人
vector<vector<Person>> Round(vector<Person> &v, int round, int n, int k)
{
	cout << endl << "+++++++++++++++++++++++++" << endl;
	if (round == 3)
	{
		cout << "--------决赛" <<"--------";
	}
	else
	{
		cout << "--------Round " << round << "--------";
	}
	cout << endl << "+++++++++++++++++++++++++" << endl;
	vector<vector<Person>> vGroup;

	// 随机打乱所有选手
	random_shuffle(v.begin(), v.end());

	// 创建保存4组选手的容器,并添加进去
	for (int i = 0; i < n; ++i)
	{
		vector<Person>vTemp;
		vGroup.push_back(vTemp);
	}

	int num = 0;
	for (vector<vector<Person>>::iterator iter = vGroup.begin(); iter != vGroup.end(); ++iter)
	{
		// 给每位选手分组,并打分
		for (int i = num; i < v.size(); ++i)
		{
			// 先判断Score容器是否有分数,如果有,需要清空,再打分,不然新的一轮比赛会把分数加在后面 -- 用clear,清空元素,但不回收空间
			if (!v[i].Score.empty())
			{
				v[i].Score.clear();
			}
			v[i].MeanScore = 0;
			(*iter).push_back(v[i]);

			++num;
			if (num % k == 0)
			{
				break;
			}
		}

		getScore(*iter);
	}

	return vGroup;
}

传入的参数是包含了所有选手的vector,为了后面进行打乱。

随机分组的思路是:

1. 先把24个人全部放到一个vector里,然后用random_shuffle打乱;

2. 定义4个空的小vector,把24个人分别放到4个vector中;

3. 利用getScore()函数给选手随机生成分数,注意需要先判断队列Score是否为空,如果有分数在里面,需要先清空,不然上一轮比赛的分数会存在里面。

  • 淘汰最后3个选手,再把所有选手放在一起
vector<Person> getoutLast3(vector<vector<Person>>& vGroup)
{
	vector<Person>vGroupNew;

	for (vector<vector<Person>>::iterator begin = vGroup.begin(); begin != vGroup.end(); ++begin)
	{
		// 对每一组的选手,淘汰最后三人
		for (int i = 0; i < 3; ++i)
		{
			(*begin).pop_back();
		}

		for (vector<Person>::iterator begin1 = (*begin).begin(); begin1 != (*begin).end(); ++begin1)
		{
			vGroupNew.push_back(*begin1);
		}
	}

	return vGroupNew;

}

传入的vGroup是排好序的,因此只需要pop_back最后三个人即可;用一个vGroupNew来存放所有晋级的选手。

  • 输出测试
void out1(vector<Person>& v)
{
	for (vector<Person>::iterator begin = v.begin(); begin != v.end(); ++begin)
	{
		cout << "name:" << (*begin).Name << "   " << "id:" << (*begin).Id << "   " << "score:";
		for_each((*begin).Score.begin(), (*begin).Score.end(), [](int val) {cout << val << " "; });
		cout << "mean score:" << (*begin).MeanScore << endl;
	}
}

void out2(vector<vector<Person>>& vGroup)
{
	int num = 1;
	for (vector<vector<Person>>::iterator begin1 = vGroup.begin(); begin1 != vGroup.end(); ++begin1) // begin1指向每个vector,共有4个
	{
		cout << "------------------------------------------------------------------------" << endl;
		cout << "group" << num << endl;
		cout << "------------------------------------------------------------------------" << endl;
		for (vector<Person>::iterator begin2 = (*begin1).begin(); begin2 != (*begin1).end(); ++begin2)
		{
			cout << "name:" << (*begin2).Name << "   " << "id:" << (*begin2).Id << "   " << "score:";
			for_each((*begin2).Score.begin(), (*begin2).Score.end(), [](int val) {cout << val << " "; });
			cout << "   " << "mean score:" << (*begin2).MeanScore << endl;
		}
		++num;		
	}
}

out1打印选手的信息,是针对只有一个vector的情况;out2是针对大vector里有4个vector的情况。

  • 主函数
void test()
{
	// 创建存储Person的容器
	vector<Person> v0;

	// 产生选手
	CreatPerson(v0);
	//out1(v0);

	/***************第一轮比赛***************/ 
	// 对所有选手随机分组,并进行比赛,获得分数
	vector<vector<Person>>vGroup1 = Round(v0, 1, 4, 6);

	//out2(vGroup1);

	// 计算每一组选手的平均分
	calAvgScore(vGroup1);
	cout << endl;
	//out2(vGroup1);

	//淘汰每组最后3名选手,并重新组队
	vector<Person>v1 = getoutLast3(vGroup1);
	out1(v1);

	/***************第二轮比赛***************/
	vector<vector<Person>>vGroup2 = Round(v1, 2, 2, 6);

	calAvgScore(vGroup2);
	//out2(vGroup2);
	vector<Person>v2 = getoutLast3(vGroup2);
	out1(v2);

	/***************决赛***************/
	vector<vector<Person>>vGroup3 = Round(v2, 3, 1, 6);

	calAvgScore(vGroup3);
	//out2(vGroup3);
	vector<Person>v3 = getoutLast3(vGroup3);
	cout << "最终获奖:" << endl;
	out1(v3);

}

int main()
{
	test();
	return 0;
}
  • 输出
+++++++++++++++++++++++++
--------Round 1--------
+++++++++++++++++++++++++

name:选手C   id:102   score:99 91 89 86 84 78 76 69 mean score:84
name:选手N   id:112   score:97 97 95 90 80 71 70 65 mean score:83.125
name:选手L   id:111   score:96 91 83 82 77 76 76 65 mean score:80.75
name:选手F   id:105   score:95 89 88 87 86 81 75 68 mean score:83.625
name:选手H   id:107   score:92 92 88 87 86 79 71 68 mean score:82.875
name:选手E   id:104   score:91 88 81 79 75 70 68 64 mean score:77
name:选手M   id:113   score:97 93 91 86 85 77 75 73 mean score:84.625
name:选手Q   id:116   score:96 94 92 89 79 72 67 64 mean score:81.625
name:选手O   id:114   score:91 86 84 81 78 75 72 70 mean score:79.625
name:选手I   id:108   score:98 94 92 92 89 87 86 77 mean score:89.375
name:选手R   id:117   score:98 94 89 86 85 84 79 78 mean score:86.625
name:选手U   id:120   score:93 87 86 82 80 78 64 62 mean score:79

+++++++++++++++++++++++++
--------Round 2--------
+++++++++++++++++++++++++
name:选手U   id:120   score:97 93 92 90 89 87 77 71 mean score:87
name:选手Q   id:116   score:89 86 83 82 80 80 78 70 mean score:81
name:选手C   id:102   score:95 93 88 83 80 78 67 63 mean score:80.875
name:选手F   id:105   score:95 93 91 91 90 86 76 71 mean score:86.625
name:选手R   id:117   score:95 91 90 88 85 80 70 68 mean score:83.375
name:选手L   id:111   score:94 92 88 87 79 78 77 67 mean score:82.75

+++++++++++++++++++++++++
--------决赛--------
+++++++++++++++++++++++++
最终获奖:
name:选手F   id:105   score:97 90 88 87 86 79 79 63 mean score:83.625
name:选手C   id:102   score:94 91 90 88 77 72 64 61 mean score:79.625
name:选手U   id:120   score:94 88 86 81 77 76 68 65 mean score:79.375

后记

尽管代码有点长,但思路其实很简单,主要是想练习一下STL最基础的使用。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值