【学习笔记】《STL使用入门教程》第七讲:STL的综合应用

STL综合题:歌唱比赛

某学校举行一场唱歌比赛,共有24个人参加,按参加顺序设置参赛号(参赛号为100至123)。
每个选手唱完一首歌之后,由10个评委分别打分。该选手的最终得分是去掉一个最高分和一个最低分,求得剩下的8个评分的平均分。
比赛共三轮,前两轮为淘汰赛,第三轮为决赛。选手的名次按得分降序排列,若得分一样,按参赛号升序排名。
第一轮分为4个小组,根据参赛号顺序依次划分,比如100-105为一组,106-111为第二组,依次类推,每组6个人,每人分别按参赛号顺序演唱。当小组演唱完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。

第二轮分为2个小组,每组6人,每个人分别按参赛号顺序演唱。当小组演唱完后,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。

第三轮只剩下6个人,本轮为决赛,不淘汰选手,本轮目的是赛出每个人的名次。该6人按参赛号顺序分别演唱。

请用STL解答以下问题:
1.请打印出所有选手的名字与参赛号,并以参赛号的升序排列。

2.请打印出第1轮和第2轮淘汰赛中,各小组选手的名字与选手得分,并以名次的顺序排列

3.请打印出第1轮淘汰赛中被淘汰的歌手的名字(不要求打印顺序)。

4.请打印出第2轮淘汰赛中被淘汰的歌手的分数,并以名次的降序排列。


数据存放分析:


选手和ID有映射关系,故选map。                                                            剩余选手不确定位置删除,故选list

【学习笔记】《STL使用入门教程》第七讲:STL的综合应用_第1张图片                                         【学习笔记】《STL使用入门教程》第七讲:STL的综合应用_第2张图片


小组内存放分数和ID的映射,由于分数可能相同,故选multimap

【学习笔记】《STL使用入门教程》第七讲:STL的综合应用_第3张图片


vector满足存放被淘汰选手的ID

【学习笔记】《STL使用入门教程》第七讲:STL的综合应用_第4张图片


分数排序,选multiset

【学习笔记】《STL使用入门教程》第七讲:STL的综合应用_第5张图片


singer.h(选手信息结构体)
-------------------------
#pragma once

#include <string>
using namespace std;

struct Singer
{
	string strName;		//名字
	int iLatestScore;	//最新得分
};


SingingCompetition.h
-------------------------
#pragma once

#include "Singer.h"
#include <vector>
#include <map>
#include <list>
#include <deque>
#include <set>
#include <algorithm>
#include <numeric>
using namespace std;

class CSingingCompetition
{
public:
	CSingingCompetition(void);
	virtual ~CSingingCompetition(void);

//对外开放的成员方法
public:
	//报名参加比赛
	void JoinCompetition();

	//第一轮淘汰赛
	void FirstKnockout();

	//第二轮淘汰赛
	void SecondKnockout();

	//决赛
	void Finals();

//不对外开放的私有成员方法
private:
	//生成歌手的分数
	void MakeScore(Singer &singer);

	//打印当前小组的分数
	void PrintGroupScore();

	//在当前小组中淘汰歌手
	void EraseInCurGroup();

	//在剩余歌手中删除歌手
	void EraseInRemainingID(list<int>::iterator it);

	//淘汰赛
	void Knockout();

//私有成员变量
private:
	map<int, Singer> m_mapSinger;		//所有的参赛ID与歌手的映射集合。int:参赛ID,Singer:参加比赛的歌手。
	list<int> m_lstRemainingID;			//剩余歌手(没被淘汰的歌手)的参赛ID。int:剩余歌手的参赛ID。
	multimap<int, int, greater<int> > m_mltmapCurGroup;		//当前演唱小组的歌手分数与歌手参赛ID的映射集合。
	vector<int> m_vecIDBeEliminatedInFirstRound;			//第一轮淘汰赛中被淘汰的歌手参赛的集合。int: 歌手的参赛号。
	multiset<int> m_mltsetScoreBeEliminatedInSecondRound;	//第二轮淘汰赛中被淘汰的歌手分数的集合。int: 歌手的分数。

	int m_iRound;		//第几轮比赛,值为1:第一轮;值为2:第二轮;值为3:第三轮。
};


SingingCompetition.cpp
-------------------------
#include "StdAfx.h"
#include "SingingCompetition.h"

CSingingCompetition::CSingingCompetition(void)
{
	//还没开始比赛,比赛轮数设置为0
	m_iRound = 0;

	//设置随机种子
	srand ( (unsigned)time ( 0 ) );
}

CSingingCompetition::~CSingingCompetition(void)
{
}

//报名参加比赛
void CSingingCompetition::JoinCompetition()
{
	if (m_iRound == 0)
	{
		string strNameBaseSource("ABCDEFGHIJKLMNOPQRSTUVWXYZ");  //名字组成元素的来源

		//随机排序名字组成元素的来源
		random_shuffle(strNameBaseSource.begin(), strNameBaseSource.end());

		for (int i=0; i<24; ++i)
		{
			//获取参加比赛的歌手名字
			string strExt(1,strNameBaseSource[i]);

			//构造歌手对象
			Singer singer;
			singer.iLatestScore = 0;
			singer.strName = "选手";
			singer.strName += strExt;

			//录入参加比赛的歌手
			m_mapSinger.insert(pair<int, Singer>(i+100, singer));
			m_lstRemainingID.push_back(i+100);
		}

		//打印参加比赛的歌手名字与参赛号
		TRACE("*******************************************************\n");
		TRACE("参加比赛的歌手名字与参赛号:\n");
		for (map<int,Singer>::iterator it=m_mapSinger.begin(); it!=m_mapSinger.end(); ++it)
		{
			TRACE("ID:%d, %s\n",it->first,  it->second.strName.c_str());
		}
		TRACE("\n");
	}
}

//第一轮淘汰赛
void CSingingCompetition::FirstKnockout()
{
	if (m_iRound == 0)
	{
		m_iRound = 1;

		//进行淘汰赛
		Knockout();

		TRACE("第%d轮淘汰赛中被淘汰的歌手的名字:\n", m_iRound);
		for (vector<int>::iterator it=m_vecIDBeEliminatedInFirstRound.begin(); it!=m_vecIDBeEliminatedInFirstRound.end(); ++it)
		{
			TRACE("%s ", m_mapSinger[*it].strName.c_str());
		}
		TRACE("\n");
		TRACE("\n");
	}
}

//第二轮淘汰赛
void CSingingCompetition::SecondKnockout()
{
	if (m_iRound == 1)
	{
		m_iRound = 2;

		//进行淘汰赛
		Knockout();

		TRACE("第%d轮淘汰赛中被淘汰的歌手的分数:\n", m_iRound);
		for (multiset<int>::iterator it=m_mltsetScoreBeEliminatedInSecondRound.begin(); it!=m_mltsetScoreBeEliminatedInSecondRound.end(); ++it)
		{
			TRACE("%d ", *it);
		}
		TRACE("\n");
		TRACE("\n");
	}
}

//决赛
void CSingingCompetition::Finals()
{
	if (m_iRound == 2)
	{
		m_iRound = 3;

		//第三轮决赛
		for (list<int>::iterator it=m_lstRemainingID.begin(); it!=m_lstRemainingID.end(); ++it)
		{
			//生成歌手的分数
			MakeScore(m_mapSinger[*it]);

			//记录当前小组歌手的得分情况,按分数降序排列
			m_mltmapCurGroup.insert(pair<int,int>(m_mapSinger[*it].iLatestScore, *it));
		}

		//打印小组决赛情况
		TRACE("*************小组决赛情况:*************\n");
		for (multimap<int,int, greater<int> >::iterator it=m_mltmapCurGroup.begin(); it!=m_mltmapCurGroup.end(); ++it)
		{
			TRACE("%s的得分:%d\n", m_mapSinger[it->second].strName.c_str() ,it->first);
		}
		TRACE("\n");

		//清除所有的数据
		m_mapSinger.clear();
		m_lstRemainingID.clear();
		m_vecIDBeEliminatedInFirstRound.clear();
		m_mltsetScoreBeEliminatedInSecondRound.clear();
		m_mltmapCurGroup.clear();
		m_iRound = 0;
	}
}

//生成歌手的分数
void CSingingCompetition::MakeScore(Singer &singer)
{
	deque<int> deqScore;

	//十个评委分别对歌手打分
	for (int i=0; i<10; ++i)
	{
		int iScore = 60 + rand()%40;
		deqScore.push_back(iScore);
	}

	//为十个评委的打分排序
	sort(deqScore.begin(), deqScore.end());

	//去掉一个最高分,去掉一个最低分
	deqScore.pop_front();
	deqScore.pop_back();

	//求八个评委打分的总和
	int iScoreSum = accumulate(deqScore.begin(), deqScore.end(), 0);

	//求八个评委打分的平均分
	int iScoreAverage = (int)(iScoreSum/deqScore.size());

	//给歌手设置得分
	singer.iLatestScore = iScoreAverage;
}

//打印当前小组的分数
void CSingingCompetition::PrintGroupScore()
{
	TRACE("小组得分情况:\n");
	for (multimap<int,int, greater<int> >::iterator it=m_mltmapCurGroup.begin(); it!=m_mltmapCurGroup.end(); ++it)
	{
		TRACE("%s的得分:%d\n", m_mapSinger[it->second].strName.c_str() ,it->first);
	}
	TRACE("\n");
}

//在当前小组中淘汰歌手
void CSingingCompetition::EraseInCurGroup()
{
	int iSingerLastIndexInGroup = 0;		//组内歌手的倒数索引
	while(iSingerLastIndexInGroup<3)
	{
		//获取当前演唱小组的最后一个元素的迭代器
		multimap<int,int,greater<int> >::iterator it=m_mltmapCurGroup.end();
		--it;

		++iSingerLastIndexInGroup;

		if (m_iRound == 1)
		{
			//记录第一轮淘汰赛中被淘汰的歌手的参赛号
			m_vecIDBeEliminatedInFirstRound.push_back(it->second);
		}
		else if (m_iRound == 2)
		{
			//记录第二轮淘汰赛中被淘汰的歌手的分数
			m_mltsetScoreBeEliminatedInSecondRound.insert(m_mapSinger[it->second].iLatestScore);
		}

		//从当前演唱小组的集合容器中删除最后一个元素
		m_mltmapCurGroup.erase(it);
	}
}

//在剩余歌手中删除歌手
void CSingingCompetition::EraseInRemainingID(list<int>::iterator it)
{
	int iSingerReverseIndexInGroup = 0;		//逆向遍历的索引
	while(iSingerReverseIndexInGroup<6)
	{
		//查找逆向遍历迭代器所指的参赛ID所对应歌手的{分数,参赛ID}是否在当前演唱小组中
		multimap<int,int,greater<int> >::iterator itMltmapScoreToID = 
			find(m_mltmapCurGroup.begin(),m_mltmapCurGroup.end(), 
			multimap<int,int,greater<int> >::value_type(m_mapSinger[*it].iLatestScore, 
			*it));

		if (itMltmapScoreToID == m_mltmapCurGroup.end())
		{
			//没找到,从剩余歌手集合中删除该歌手的参赛号
			it = m_lstRemainingID.erase(it);
		}

		//逆向遍历的索引自增
		++iSingerReverseIndexInGroup;

		//防止对容器的begin()迭代器进行--操作。
		if (it != m_lstRemainingID.begin())
		{
			--it;
		}
	}

	//清除该组的比赛记录存储,以便下一组比赛记录的存储
	m_mltmapCurGroup.clear();
}

//淘汰赛
void CSingingCompetition::Knockout()
{
	TRACE("*************第%d轮淘汰赛:*************\n", m_iRound);

	int iSingerIndex = 0;		//第几个歌手正在演唱,1代表第一个歌手,2代表第二个歌手。。。
	for (list<int>::iterator it=m_lstRemainingID.begin(); it!=m_lstRemainingID.end(); )
	{
		++iSingerIndex;

		//生成歌手的分数
		MakeScore(m_mapSinger[*it]);

		//记录当前演唱小组歌手的得分情况,按分数降序排列
		m_mltmapCurGroup.insert(pair<int,int>(m_mapSinger[*it].iLatestScore, *it));

		if (iSingerIndex%6 == 0)
		{
			//小组演唱完毕,打印小组得分情况
			PrintGroupScore();

			//在当前小组中淘汰歌手
			EraseInCurGroup();

			//在剩余歌手中删除歌手
			EraseInRemainingID(it++);  //不可用++it代替,因为要转入自增之前的迭代器
		}
		else
		{
			++it;
		}
	}
}



你可能感兴趣的:(STL,应用)