STL-常見容器應用實例(vector,deque,map,set,multimap,multiset)

 需求:

某學校舉行一場唱歌比賽,共有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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章