STL-常见容器应用实例(vector,deque,map,set,multimap,multiset)

该博客围绕学校唱歌比赛展开,比赛共三轮,前两轮淘汰赛,第三轮决赛。比赛有24人参加,按参赛号顺序演唱,评委打分后去掉最高分和最低分取平均分。第一轮分4组,每组6人,淘汰后三名;第二轮分2组,每组6人,同样淘汰后三名;第三轮6人决赛定名次,可能运用C++和STL容器实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 需求:

某学校举行一场唱歌比赛,共有24个人参加,按参加顺序设置参赛号(参赛号为100至123)。

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

#include "stdafx.h"
#include "stdio.h"
#include "string"
#include "vector"
#include "list"
#include "map"
#include "set"
#include "stack"
#include "deque"
#include <algorithm>//排序算法
#include "iostream"
#include <time.h>
#include <numeric>//求和函数
using namespace std;

/*
需求1、请打印出所有选手的名字与参赛号,并以参赛号的升序排列。
分析1、参赛号唯一,可以用map,参加比赛的时候对map进行赋值

需求2、请打印出第1轮和第2轮淘汰赛中,各小组选手的名字与选手得分,并以名次的顺序排列
分析2、选手和得分又是关联的,分数有可能一样,可以考虑用multimap,需要定义两个multimap,或者局部变量
流程是:分组,歌唱,评分,打印,更新list
分组:按照需要分组,6人一组,每一轮比赛流程一致,可以统一写成一个函数
伪代码:

Round  = 1
start = 100

歌手IDlist来控制循环每一个歌手进行比赛
for i = 0,i < 6,i++
index = start + i
//唱歌:用Singer对象调用唱歌方法
//评分:获取10的随机评分值(??),用临时变量deque来做记录,sort排序一下,去掉最高和最低,然后求和平均,把平均分与这个歌手绑定 multimap
//歌手和分数绑定,分数有可能一样,用multimap
endfor

//map自动排序,打印出这一组的选手的名字和得分
//根据得分,获取晋级的和被淘汰的,把被淘汰的歌手名字用vector来存放

更新list
更新

需求3、请打印出第1轮淘汰赛中被淘汰的歌手的名字(不要求打印顺序)。
在需求2的基础上,把每组最低分的3个取出来,打印出来,更新list

需求4、请打印出第2轮淘汰赛中被淘汰的歌手的分数,并以名次的降序排列。
在需求2的基础上,把每组最低分的3个取出来,打印出来,更新list

*/

//歌手类
class Singer /*: public Ponsen*/
{
public:
	Singer() { m_SingerID = 0; m_LastScore = 0;	
		printf("Singer Singer() GetName:%s,GetAddress:%s \n", GetName().c_str(), GetAddress().c_str()); 
		printf("\n");
	}
	Singer(string name, string addr, int id) :/*Ponsen(name, addr), */m_Name(name), m_Address(addr), m_SingerID(id) {  m_LastScore = 0;

		printf("Singer  GetName:%s, GetAddress:%s GetSingerID() = %d \n", GetName().c_str(), GetAddress().c_str(), m_SingerID);
		printf("\n");
	}

	Singer(const Singer & sing);
	inline void SingSong() { 
		//printf("**歌手:%s, ID:%d 唱歌*********,最终得分为%d \n", GetName().c_str(), m_SingerID , m_LastScore); 
	}
	inline int GetSingerID() const { return m_SingerID; }
	inline void SetSingerID(const int id) { m_SingerID = id; }
	inline int GetScore() const{ return m_LastScore; }
	inline void SetScore(const int score) { m_LastScore = score; }
	inline string GetName() const { return m_Name; }
	inline string GetAddress() const { return m_Address; }
	inline void SetName(const string name) 
	{ m_Name = name; printf("Singer SetName(string) m_Name = %s \n", m_Name.c_str()); printf("\n"); }
	inline void SetAddress(const string addr) 
	{ m_Address = addr; printf("Singer SetAddress(string) m_Address = %s \n", m_Address.c_str()); printf("\n"); }
private:
	int m_SingerID;//歌手ID,唯一性
	int m_LastScore;//最新分数
	string m_Name;
	string m_Address;
};
Singer::Singer(const Singer & sing)
{
	//printf("Singer Singer(Singer&)  GetName:%s,GetAddress:%s \n", GetName().c_str(), GetAddress().c_str());
	printf("\n");
}

//比赛类
/*
数据结构和流程怎么设计
利用STL中的容器和算法:vector,deque,quque,stack,list,map,multimap,set,multiset
方法:
1、报名:把ID和歌手类映射一起,把ID存放到list列表中
2、分组
3、比赛(1轮,2轮,决赛):传入ID信息,
4、打印
*/
class SongCompetition
{
public:

	//
	SongCompetition()
	{
		//还没开始比赛,比赛轮数设置为0
		m_iRound = 0;
		//设置随机种子
		srand((unsigned)time(0));
	}
	void SignUp(const int, const int);
	//构造函数
	void SignUpConpetition(const int, const Singer&);		
	void FirstRound();
	void SecondRound();
	void LastRound();
private:

	int m_iRound;//比赛次数,控制比赛流程
	//为什么选用map,歌手id唯一性,id与歌手的关联性
	map<int, Singer, less<int>> m_SignUpInfoMap;//报名信息的Map,用一个ID绑定一个歌手
	list<int> m_SingerList;//维护参赛ID,开始24人,每一轮比赛后删除淘汰的选手,然后再
	multimap<int, int, greater<int>> m_mltmapCurGroupInfo;//分数,ID,降序排列,
	vector<int> m_vecEliminateSingerRO;//第一轮比赛淘汰的ID号
	multiset<int> m_mtlsetEliminateSingerRT;//第二轮淘汰的ID号,需要顺序
		
	void PrintCurRoundInfo();
	void RecordEliminateSinger();
	void DelCurRoundSingerID(list<int>::iterator);
	//唱歌得出分数函数
	int SingleSongCp(Singer &);
	void SingRound();
	int MakeScore(const int id);
	void PrintAllSignUpInfo();
	
};

void SongCompetition::FirstRound()
{
	if (m_iRound == 0)
	{
		m_iRound = 1;
		printf("**第%d轮歌唱比赛** \n", m_iRound);	
		SingRound();
		//打印被淘汰的歌手的名字,由ID进行绑定
		for (vector<int>::iterator it = m_vecEliminateSingerRO.begin(); it != m_vecEliminateSingerRO.end(); it++)
		{
			printf("被淘汰的歌手的名字为:%s  \n", m_SignUpInfoMap[*it].GetName().c_str());
		}
	}
}

void SongCompetition::SecondRound()
{

	if (m_iRound == 1)
	{
		m_iRound = 2;
		printf("\n");
		printf("**第%d轮歌唱比赛** \n", m_iRound);		
		SingRound();
		//打印第2轮被淘汰的歌手的分数,按照顺序排列
		for (multiset<int>::iterator it = m_mtlsetEliminateSingerRT.begin(); it != m_mtlsetEliminateSingerRT.end(); it++)
		{
			printf("被淘汰的歌手的分数:%d \n", *it);
		}
	}
}

void SongCompetition::LastRound()
{
	if (m_iRound == 2)
	{
		m_iRound = 3;
		printf("\n");
		printf("**第%d轮歌唱比赛** \n", m_iRound);
		SingRound();
	}
	m_SignUpInfoMap.clear();
	m_SingerList.clear();
	m_mltmapCurGroupInfo.clear();
	m_vecEliminateSingerRO.clear();
	m_mtlsetEliminateSingerRT.clear();
	m_iRound = 0;

}

//在剩余歌手中删除歌手
void SongCompetition::DelCurRoundSingerID(list<int>::iterator it)
{
	//输入的是ID的迭代器,通过ID号查找当前分数-ID集合中的集合,
	int index = 0;//逆向遍历的索引
	while (index < 6)//为什么是循环6次,
	{
		//查找逆向遍历迭代器所指的参赛ID所对应歌手的{分数,参赛ID}是否在当前演唱小组中
		multimap<int, int, greater<int>>::iterator itr =
			find(m_mltmapCurGroupInfo.begin(),
				m_mltmapCurGroupInfo.end(),
				multimap<int, int, greater<int>>::value_type(m_SignUpInfoMap[*it].GetScore(), *it));

		index++;

		if (itr == m_mltmapCurGroupInfo.end())
		{
			//没找到,从剩余歌手集合中删除该歌手的参赛号,因为这个歌手已经被淘汰了,要更新list列表
			it = m_SingerList.erase(it);//一定要用it接收返回值,返回值为下一个迭代器
		}
		//防止对容器的begin()迭代器进行--操作。
		if (it != m_SingerList.begin())
		{
			--it;
		}
	}
	m_mltmapCurGroupInfo.clear();
}

/*
//函数功能:往map里面插入数据
*/
void SongCompetition::SignUpConpetition(const int id, const Singer &sing)
{
	////插入数据方法一,//用这个方法,遍历的时候GetName内容为空,GetAddress内容为空,为什么呢
	//m_SignUpInfoMap.insert(map<int, Singer>::value_type(id, sing));
	//插入数据方法二,用这个方法,遍历的时候GetName内容为空,GetAddress内容为空,为什么呢
	//m_SignUpInfoMap.insert(pair<int, Singer>(id, sing));
	m_SignUpInfoMap[id] = sing;//插入数据方法三
	printf("\n");
}

void SongCompetition::PrintCurRoundInfo()
{
	if (m_mltmapCurGroupInfo.size())
	{
		//printf("*****************第%组比赛结果如下*************** \n", m_iRound);
		for (multimap<int, int, greater<int>>::iterator it = m_mltmapCurGroupInfo.begin(); it != m_mltmapCurGroupInfo.end(); it++)
		{
			//根据ID号找到歌手名字
			printf("歌手:%s, 歌唱评分为:%d \n", m_SignUpInfoMap[it->second].GetName().c_str(), it->first);
		}
		printf("\n");
	}
}

void SongCompetition::SignUp(const int start, const int all)
{
	for (int i = 1; i <= all; i++)
	{
		char strstart = 'A';//
		string sFirstName(2, strstart + i);
		//printf("sFirstName:%s \n", sFirstName.c_str());
		Singer sing(sFirstName, "beijing", start + i);
		sing.SetSingerID(start + i);
		SignUpConpetition(start + i, sing);
		m_SingerList.push_back(start + i);
		printf("\n");
	}
	PrintAllSignUpInfo();
	//Ponsen的属性无法设置//////////////////////////////////////////////////////////////////////////////////////////////////
}

//分组
//定义接口:唱歌比赛函数,输入ID,得出分数
int SongCompetition::SingleSongCp(Singer &sing)
{
	if (1/*sing.GetSingerID > 100*/)
	{
		//printf("歌手%s ID:%d 准备唱歌", sing.GetName().c_str(), sing.GetSingerID());
		
		int ret = MakeScore(sing.GetSingerID());
		sing.SetScore(ret);
		sing.SingSong();
		return ret;
	}
	else
	{
		return 0;
	}
}

//唱歌评分
int SongCompetition::MakeScore(const int id)
{
	deque<int> deqSingScore;
	//十个评委分别对歌手打分
	for (int i = 0; i<10; ++i)
	{
		int iScore = 60 + rand() % 40;
		deqSingScore.push_back(iScore);
		//printf("评委%d对歌手%d进行评分,分数为:%d", i, id, iScore);
	}
	//排序sort
	sort(deqSingScore.begin(), deqSingScore.end());
	//排除最高和最低分
	deqSingScore.pop_front();
	deqSingScore.pop_back();
	//求和
	int sum = accumulate(deqSingScore.begin(), deqSingScore.end(), 0);	
	//求平均分
	return sum / deqSingScore.size();
}

void SongCompetition::RecordEliminateSinger()
{
	int index = 0;	
	//已经排好序,直接拿最后三个数据
	for (int i = 0; i < 3/*m_mltmapCurGroupInfo.size() / 2*/; i++)
	{
		multimap<int, int, greater<int>>::iterator itr = m_mltmapCurGroupInfo.end();
		--itr;
		if(m_iRound == 1)
			m_vecEliminateSingerRO.push_back((itr)->second);//第一轮被淘汰的ID
		if (m_iRound == 2)
			m_mtlsetEliminateSingerRT.insert((m_SignUpInfoMap.at(itr->second).GetScore()));//第二轮淘汰的分数
		//被淘汰的ID号为
		//printf("**被淘汰的歌手的ID号为:%d \n", (itr)->second);
		m_mltmapCurGroupInfo.erase(itr);//删掉这个被淘汰的,剩下晋级的要用于维护list歌手列表
	}
}

void SongCompetition::SingRound()
{
	//m_iRound = 1;
	int iSingerIndex = 0;
	//printf("***********进行第%d轮唱歌比赛************** \n", m_iRound);
	//参数选手信息
	if (m_SingerList.size() > 0)
	{
		for (list<int>::iterator it = m_SingerList.begin(); it != m_SingerList.end();)
		{
			int ret = SingleSongCp(m_SignUpInfoMap[*it]);
			m_mltmapCurGroupInfo.insert(pair<int, int>(ret, *it));//获取当前组的分数,ID

			if ((++iSingerIndex) % 6 == 0)//分组从1开始,1-6,7-12
			{
				//这里是统计一个组的结果,分数排序,筛选,存放结果
				printf("\n");
				//排列当前组的名次
				PrintCurRoundInfo();//打印信息:
				if (m_iRound < 3)
				{																
					RecordEliminateSinger();
					DelCurRoundSingerID(it++);
				}
				else
				{
					it++;
				}
			}
			else
			{
				++it;
			}			
		}
	}

}


//按照ID升序打印所有参赛选手信息
void SongCompetition::PrintAllSignUpInfo()
{
	if (m_SignUpInfoMap.size())
	{
		for (map<int, Singer>::iterator it = m_SignUpInfoMap.begin(); it != m_SignUpInfoMap.end(); it++)
		{
			//pair<int, Singer> pr = *it;//用这个方法,GetName内容为空,GetAddress内容为空,为什么呢
			printf("**参赛选手-编号:%d,姓名:%s, 地址:%s \r\n", it->first, it->second.GetName().c_str(), it->second.GetAddress().c_str());
		}
	}
}

int main()
{
	SongCompetition m_SongCp;
	m_SongCp.SignUp(100, 24);	
	m_SongCp.FirstRound();
	m_SongCp.SecondRound();
	m_SongCp.LastRound();
	char inputchar;
	cin >> inputchar;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值