C++STL容器实现演讲比赛管理系统以及对map/multimap容器的使用

🎆C++STL容器实现演讲比赛管理系统🎆



一、🧨实现功能

🩰我提前设置了固定的12人参赛,六人一组,每次取前三名晋级,所有到了第二轮剩下六人比赛,再取前三名就是冠军亚军季军。

在这里插入图片描述

二、🎈编程思想

👚一些基本的代码分布,关于using namespace的位置我不做解释。

🦺代码注释中对功能写的很详细,没有必要太多文章文字解释

在这里插入图片描述

三、🧧源码

1.👓源文件

🎍speechManager.cpp

srand种子函数是为了让rand函数每次运行程序不会有固定的结果,如果不设置你去掉那行代码试试,结果都是一样的,设置后才会不一样。

#include "speechManager.h"

//构造函数
SpeechManager::SpeechManager()
{
	//初始化
	this->init_Speech();

	//创建选手
	this->create_Speaker();

	//获取往届记录
	this->load_Record();
}

//显示菜单
void SpeechManager::show_Menu()
{
	cout << "*******************************************" << endl;
	cout << "**********  欢迎参加演讲比赛  *************" << endl;
	cout << "**********  1.开始演讲比赛    *************" << endl;
	cout << "**********  2.查看往届记录    *************" << endl;
	cout << "**********  3.清空比赛记录    *************" << endl;
	cout << "**********  0.退出比赛程序    *************" << endl;
	cout << "*******************************************" << endl;


}

//初始化
void SpeechManager::init_Speech()
{
	//容器保证为空
	this->v1.clear();
	this->v2.clear();
	this->victory.clear();
	this->m_Speaker.clear();
	//初始化比赛轮数
	this->m_Index = 1;
	//初始化记录容器
	this->m_Record.clear();
}

//创建12名选手
void SpeechManager::create_Speaker()
{
	string nameSeed = "ABCDEFGHIJKL";
	for (int i = 0;i < nameSeed.size();i++)
	{
		string name = "选手";
		name += nameSeed[i];

		Speaker sp;
		sp.m_Name = name;
		for (int i = 0;i < 2;i++)
		{
			sp.m_Score[i] = 0;
		}

		//
		this->v1.push_back(i + 10001);

		//
		this->m_Speaker.insert(make_pair(i + 10001, sp));
	}

}

//开始
void SpeechManager::start_Speech()
{
	srand((unsigned int)time(NULL));
	//第一轮比赛
	// 
	//1.抽签
	this->speech_Draw();
	
	//2.比赛
	this->speech_Contest();

	//3.显示晋级结果
	this->show_Score();

	//第二轮比赛
	this->m_Index++;

	//1.抽签
	this->speech_Draw();

	//2.比赛
	this->speech_Contest();
	
	//3.显示最终结果
	this->show_Score();

	//4.保存分数
	this->save_Score();

	//重置比赛
	//初始化属性
	this->init_Speech();

	//创建选手
	this->create_Speaker();

	//获取记录
	this->load_Record();

	cout << "本届比赛完毕!" << endl;
	system("pause");
	system("cls");
}
void SpeechManager::speech_Draw()
{
	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(v1.begin(), v1.end());
		for (vector<int>::iterator it = v1.begin();it != v1.end();it++)
		{
			cout << *it << " ";
		}
		cout << endl;
	}
	cout << "--------------------" << endl;
}

//比赛进行
void SpeechManager::speech_Contest()
{
	cout << "--------------第" << this->m_Index << "轮比赛开始:------------------" << endl;
	multimap<double, int, greater<double>> groupScore;//临时容器保存  key分数value选手编号

	int num = 0;//记录人员数,6个为1组

	vector<int>v_Src;//比赛人员的容器
	if (this->m_Index == 1)
	{
		v_Src = v1;
	}
	else
	{
		v_Src = v2;
	}

	//遍历所有参赛选手
	for (vector<int>::iterator it = v_Src.begin();it != v_Src.end();it++)
	{
		num++;

		//评委打分
		deque<double>d;
		for (int i = 0;i < 10;i++)
		{
			double score = (rand() % 401 + 600) / 10.f;//600 ~1000
			cout << score << "分 ";
			d.push_back(score);
		}

		sort(d.begin(), d.end(), greater<double>());//排序
		d.pop_front();//去掉最高分
		d.pop_back();//去掉最低分

		double sum = accumulate(d.begin(), d.end(), 0.0f);//获取总分
		double avg = sum / (double)d.size();//获取平均分

		//每个人平均分
		cout << "编号:" << *it << "选手:" << this->m_Speaker[*it].m_Name << "获取平均分为: " << avg << endl;//打印分数
		this->m_Speaker[*it].m_Score[this->m_Index - 1] = avg;

		//六人一组,用临时容器保存
		groupScore.insert(make_pair(avg, *it));
		if (num % 6 == 0)
		{
			cout << "第" << num / 6 << "小组比赛名次:" << endl;
			for (multimap<double, int, greater<double>>::iterator it = groupScore.begin();it != groupScore.end();it++)
			{
				cout << "编号:" << it->second << "姓名:" << this->m_Speaker[it->second].m_Name << "得分:" << this->m_Speaker[it->second].m_Score[this->m_Index - 1] << endl;
			}

			int count = 0;
			//取前三名
			for (multimap<double, int, greater<double>>::iterator it = groupScore.begin();it != groupScore.end() && count < 3;it++, count++)
			{
				if (this->m_Index == 1)
				{
					v2.push_back((*it).second);
				}
				else
				{
					victory.push_back((*it).second);
				}
			}
			groupScore.clear();
		}

	}
}


void SpeechManager::show_Score()
{
	cout << "-----------第" << this->m_Index << "轮晋级选手信息如下:-----------------" << endl;
	vector<int>v;
	if (this->m_Index == 1)
	{
		v = v2;
	}
	else
	{
		v = victory;
	}

	for (vector<int>::iterator it = v.begin();it != v.end();it++)
	{
		cout << "选手编号:" << *it << "姓名:" << m_Speaker[*it].m_Name << "得分: " << m_Speaker[*it].m_Score[this->m_Index - 1] << endl;

	}
	cout << endl;
	system("pause");
	system("cls");


	this->show_Menu();
}

void SpeechManager::save_Score()
{
	ofstream ofs;
	ofs.open("speech.csv", ios::out | ios::app);//用输出的方式打开文件写文件

	//将每个人数据写入到文件中
	for (vector<int>::iterator it = victory.begin();it != victory.end();it++)
	{
		ofs << *it << ","
			<< m_Speaker[*it].m_Score[this->m_Index - 1] << ",";
	}
	ofs << endl;

	//关闭文件
	ofs.close();

	cout << "记录已经保存" << endl;

	//此时文件不为空
	this->fileIsEmpty = false;
}

void SpeechManager::load_Record()
{
	ifstream ifs("speech.csv", ios::in);//输入流对象 读取文件

	if (!ifs.is_open())
	{
		this->fileIsEmpty = true;
		cout << "文件不存在!" << endl;
		ifs.close();
		return;
	}

	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 << endl;
		vector<string>v;

		int pos = -1;
		int start = 0;

		while (true)
		{
			pos = data.find(",", start);//从0开始查找逗号 
			if (pos == -1)
			{
				break;//找不到返回
			}
			string tmp = data.substr(start, pos - start);//找到了,进行分割,参数一是起始位置,参数二是截取长度
			v.push_back(tmp);
			start = pos + 1;
		}
		
		this->m_Record.insert(make_pair(index, v));
		index++;
	}

	ifs.close();
}

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

void SpeechManager::clear_Record()
{
	cout << "确认清空?" << endl;
	cout << "1.确认" << endl;
	cout << "2.返回" << endl;

	int select = 0;
	cin >> select;
	
	if (select == 1)
	{
		//打开模式 ios::trunc 如果存在删除文件再重新创建
		ofstream ofs("speech.csv", ios::trunc);
		ofs.close();

		//初始化属性
		this->init_Speech();

		//创建选手
		this->create_Speaker();

		//获取往届记录
		this->load_Record();

		cout << "清空成功!!!" << endl;
	}
}

//退出系统
void SpeechManager:: exit_System()
{
	cout << "欢迎下次使用" << endl;
	system("pause");
	exit(0);
}





//析构函数
SpeechManager::~SpeechManager()
{

}


🎋演讲比赛管理系统.cpp

#include "speechManager.h"
using namespace std;


int main()
{
	SpeechManager wm;
	int input;//用户选择的功能
	while(true)
	{
		wm.show_Menu();

		cout << "请输入你的选择数字" << endl;
		cin >> input;

		switch (input)
		{
		case 1://开始比赛
			wm.start_Speech();
			break;
		case 2://查看往年信息
			wm.show_Record();
			break;
		case 3://清空比赛记录
			wm.clear_Record();
			break;
		case 0://退出系统
			wm.exit_System();
			break;
		default:
			cout << "输入无效,请重新输入" << endl;
			system("cls");
			break;
		}
	}



	
}

2.🕶头文件

🎄speechManager.h

#pragma once


#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
#include<deque>
#include<numeric>
#include<ctime>
#include <fstream>


#include"speaker.h"

using namespace std;

//设计演讲管理类
class SpeechManager
{
public:

	//构造函数
	SpeechManager();

	//显示菜单
	void show_Menu();

	//退出系统
	void exit_System();

	//开始比赛12名选手
	vector <int>v1;

	//第二轮六个选手
	vector <int>v2;

	//前三名是胜利者
	vector <int>victory;

	//存放编号以及对应的选手容量
	map<int, Speaker> m_Speaker;

	//记录比赛轮数
	int m_Index;

	//初始化上述属性
	void init_Speech();

	//初始化创建12名选手
	void create_Speaker();

	//开始比赛  -  比赛流程控制
	void start_Speech();
	
	//抽签
	void speech_Draw();

	//比赛进行
	void speech_Contest();

	//显示比赛结果
	void show_Score();

	//保存分数
	void save_Score();

	//读取记录分数,不做显示功能
	void load_Record();

	//文件是否为空的标志
	bool fileIsEmpty;

	//添加往届记录的容器
	map<int, vector<string>> m_Record;

	//显示往届得分功能
	void show_Record();

	//清空记录功能
	void clear_Record();

	//析构函数
	~SpeechManager();

};

🧶 speech.h

#pragma once
#include<iostream>
using namespace std;

class Speaker 
{
public:
	string m_Name;//选手姓名
	double m_Score[2];//选手分数  最多两轮得分
};

四、💋map/multimap容器

1.🥇map容器概念

简介:

  • map中所有元素都是pair
  • pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
  • 所有元素都会根据元素的键值自动排序

本质:

  • map/multimap属于关联式容器,底层结构是用二叉树实现。

优点:

  • 可以根据key值快速找到value值

map和multimap区别

  • map不允许容器中有重复key值元素
  • multimap允许容器中有重复key值元素

2.🥈map的构造和赋值

功能描述:

  • 对map容器进行构造和赋值操作

函数原型:

构造:

  • map<T1, T2> mp; //map默认构造函数:
  • map(const map &mp); //拷贝构造函数

赋值:

  • map& operator=(const map &mp); //重载等号操作符

示例:

#include <map>

void printMap(map<int,int>&m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}

void test01()
{
	map<int,int>m; //默认构造
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));
	printMap(m);

	map<int, int>m2(m); //拷贝构造
	printMap(m2);

	map<int, int>m3;
	m3 = m2; //赋值
	printMap(m3);
}

int main() {

	test01();

	system("pause");

	return 0;
}

总结:map中所有元素都是成对出现,插入数据时候要使用对组

3.🥉map大小和交换

功能描述:

  • 统计map容器大小以及交换map容器

函数原型:

  • size(); //返回容器中元素的数目
  • empty(); //判断容器是否为空
  • swap(st); //交换两个集合容器

示例:

#include <map>

void printMap(map<int,int>&m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}

void test01()
{
	map<int, int>m;
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));

	if (m.empty())
	{
		cout << "m为空" << endl;
	}
	else
	{
		cout << "m不为空" << endl;
		cout << "m的大小为: " << m.size() << endl;
	}
}


//交换
void test02()
{
	map<int, int>m;
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));

	map<int, int>m2;
	m2.insert(pair<int, int>(4, 100));
	m2.insert(pair<int, int>(5, 200));
	m2.insert(pair<int, int>(6, 300));

	cout << "交换前" << endl;
	printMap(m);
	printMap(m2);

	cout << "交换后" << endl;
	m.swap(m2);
	printMap(m);
	printMap(m2);
}

int main() {

	test01();

	test02();

	system("pause");

	return 0;
}

总结:

  • 统计大小 — size
  • 判断是否为空 — empty
  • 交换容器 — swap

4.🏅map插入和删除

功能描述:

  • map容器进行插入数据和删除数据

函数原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(key); //删除容器中值为key的元素。

示例:

#include <map>

void printMap(map<int,int>&m)
{
	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
	{
		cout << "key = " << it->first << " value = " << it->second << endl;
	}
	cout << endl;
}

void test01()
{
	//插入
	map<int, int> m;
	//第一种插入方式
	m.insert(pair<int, int>(1, 10));
	//第二种插入方式
	m.insert(make_pair(2, 20));
	//第三种插入方式
	m.insert(map<int, int>::value_type(3, 30));
	//第四种插入方式
	m[4] = 40; 
	printMap(m);

	//删除
	m.erase(m.begin());
	printMap(m);

	m.erase(3);
	printMap(m);

	//清空
	m.erase(m.begin(),m.end());
	m.clear();
	printMap(m);
}

int main() {

	test01();

	system("pause");

	return 0;
}

总结:

  • map插入方式很多,记住其一即可
  • 插入 — insert
  • 删除 — erase
  • 清空 — clear

5.🎖map查找和统计

功能描述:

  • 对map容器进行查找数据以及统计数据

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key); //统计key的元素个数

示例:

#include <map>

//查找和统计
void test01()
{
	map<int, int>m; 
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));

	//查找
	map<int, int>::iterator pos = m.find(3);

	if (pos != m.end())
	{
		cout << "找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl;
	}
	else
	{
		cout << "未找到元素" << endl;
	}

	//统计
	int num = m.count(3);
	cout << "num = " << num << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

总结:

  • 查找 — find (返回的是迭代器)
  • 统计 — count (对于map,结果为0或者1)

6.🏆map容器排序

学习目标:

  • map容器默认排序规则为 按照key值进行 从小到大排序,掌握如何改变排序规则

主要技术点:

  • 利用仿函数,可以改变排序规则

示例:

#include <map>

class MyCompare {
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};

void test01() 
{
	//默认从小到大排序
	//利用仿函数实现从大到小排序
	map<int, int, MyCompare> m;

	m.insert(make_pair(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(make_pair(3, 30));
	m.insert(make_pair(4, 40));
	m.insert(make_pair(5, 50));

	for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {
		cout << "key:" << it->first << " value:" << it->second << endl;
	}
}
int main() {

	test01();

	system("pause");

	return 0;
}

总结:

  • 利用仿函数可以指定map容器的排序规则
  • 对于自定义数据类型,map必须要指定排序规则,同set容器

👗总结

如果对您有帮助,请帮小生点点举报🛒🛒🛒!!!

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ STL中的mapmultimap是关联容器,用于存储键值对(key-value pairs),其中每个键(key)唯一对应一个值(value)。 map是一个有序容器,根据键的大小进行自动排序,默认按照键的升序进行排序。每个键只能在map中出现一次,如果尝试插入具有相同键的元素,新元素将替代旧元素。 multimap也是一个有序容器,与map不同的是,它允许多个具有相同键的元素存在。多个具有相同键的元素将按照插入的顺序进行存储,而不会自动排序。 这两个容器都提供了一系列的操作函数,如insert、erase、find等,用于插入、删除和查找元素。 以下是一个使用map的简单示例: ```cpp #include <iostream> #include <map> int main() { std::map<std::string, int> scores; scores.insert(std::make_pair("Alice", 90)); scores.insert(std::make_pair("Bob", 80)); scores.insert(std::make_pair("Charlie", 70)); // 查找并输出Bob的分数 std::cout << "Bob's score: " << scores["Bob"] << std::endl; // 遍历并输出所有键值对 for (const auto& pair : scores) { std::cout << pair.first << ": " << pair.second << std::endl; } return 0; } ``` 上述示例中,我们创建了一个存储string类型键和int类型值的map容器scores。通过insert函数依次插入了三个键值对。然后我们通过scores["Bob"]来获取Bob的分数,并输出结果为80。 接着我们使用范围-based for循环遍历map中的所有键值对,并输出每个键值对的键和值。 multimap的用法与map类似,只是它允许多个具有相同键的元素存在。 这些关联容器在查找和插入操作上具有较高的效率,特别适用于需要根据键进行快速查找的场景。在实际应用中,你可以根据自己的需求选择适合的容器类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值