C++中关于STL与其案例代码的各种问题

一.STL的介绍

1.什么是STL

        标准模板库 STL(Standard Template Library),是 C++ 标准库的一部分,不需要单独安装,只需要#include 头文件。

2.STL中的六大组件       

        容器:各种数据结构

        算法:各种常用的算法(冒泡,排序)

        迭代器:扮演了容器与算法之间的胶合剂(类似于指针等)

        仿函数:行为类似函数,可作为算法的某种策略

        适配器:一种用来修饰容器或者仿函数或迭代器接口的东西

        空间配置器:负责空间的配置与管理

3.关系

        STL六大组件的交互关系,容器通过空间配置器取得数据存储空间,算法通过迭代器存储容器中的内容,仿函数可以协助算法完成不同的策略的变化,适配器可以修饰仿函数。

二.STL中的三大组件

1.容器:序列式容器和关联式容器

        序列式容器:序列式容器就是容器元素在容器中的位置是由元素进入容器的时间和地点来决定

        关联式容器:关联式容器是指容器已经有了一定的规则,容器元素在容器中的位置由容器的规则来决定

2.算法:质变算法和非质变算法

        质变算法::是指运算过程中会更改区间内的元素的内容

        非质变算法:是指运算过程中不会更改区间内的元素内容

3.迭代器:双向迭代器和随机访问迭代器        

        双向迭代器:++,--可以访问下一个元素和上一个元素

        随机访问迭代器:+2,可以跳2个元素访问元素

4.关系

        容器存储数据,并且提供迭代器,算法使用迭代器来操作容器中的元素

三.STL的工作机制、

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//数组容器
template<class T>
class MyArray
{
public:

	//保护原生指针,给原生指针取别名
	typedef T* iterator;
	MyArray()
	{
		mCapacity = 10;
		mSize = 10;
		p = new T[mCapacity];
		for (int i = 0; i < mCapacity; i++)
		{
			p[i] = i + 1;
		}
	}

	//提供迭代器,开始位置的迭代器
	T* begin()
	{
		return p;
	}

	//返回结束位置的迭代器
	T* end()
	{
		return p + mSize;
	}


public:
	T* p;
	int mCapacity;
	int mSize;
};

//算法
template<class T>
void printArray(T begin,T end)
{
	for (; begin != end; ++begin)
	{
		cout << *begin << " ";
	}
	
}
void test01()
{
	MyArray<int> arr;

	//获取容器提供的开始位置迭代器
	MyArray<int>::iterator begin=arr.begin();
	//获取容器提供的结束位置迭代器
	MyArray<int>::iterator end = arr.end();

	printArray(begin, end);
}
int main()
{
	test01();
	system("pause");
	return EXIT_SUCCESS;
}

四.STL的hello world

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>//容器
#include<algorithm>//算法的头文件
#include<string>
using namespace std;

//加入算法的回调函数
void MyPrint(int val)
{
	cout << val << " ";
}
//1.存储数据
void test01()
{
	//容器
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);

	//获取开始位置的迭代器
	vector<int>::iterator begin = v.begin();
	//获取结束位置的迭代器
	vector<int>::iterator end = v.end();
	/*
	void _For_each(_InIt _First, _InIt _Last, _Fn1& _Func)
	{	
		for (; _First != _Last; ++_First)
			_Func(*_First);
	}
	*/
	//遍历算法
	for_each(begin, end, MyPrint);
	cout << endl;

}

//2.容器存储对象
class Maker
{
public:
	Maker(string name, int age)
	{
		this->name = name;
		this->age = age;
	}
public:
	string name;
	int age;
};
ostream &operator<<(ostream &out, Maker &m)
{
	out << "Name:" << m.name << " Age:" << m.age << endl;
	return out;
}

void test02()
{
	vector<Maker> v;
	//往容器中存储对象
	v.push_back(Maker("悟空", 18));
	v.push_back(Maker("小林", 19));
	v.push_back(Maker("贝吉塔", 25));
	v.push_back(Maker("龟仙人", 200));
	v.push_back(Maker("短笛", 180));

	//获取开始和结束位置的迭代器
	vector<Maker>::iterator begin = v.begin();
	vector<Maker>::iterator end = v.end();

	while (begin!=end)
	{
		cout << (*begin);
		begin++;

	}
}
//3.存储对象的指针
void test03()
{
	vector<Maker*> v;
	//创建数据
	Maker *m1 = new Maker("悟空", 18);
	Maker *m2 = new Maker("小林", 19);
	Maker *m3 = new Maker("贝吉塔",200 );
	Maker *m4 = new Maker("龟仙人",180 );
	Maker *m5 = new Maker("短笛", 18);

	v.push_back(m1);
	v.push_back(m2);
	v.push_back(m3);
	v.push_back(m4);
	v.push_back(m5);

	vector<Maker*>::iterator begin = v.begin();
	vector<Maker*>::iterator end = v.end();

	while (begin!=end)
	{
		cout << (*begin)->name << " " << (*begin)->age << endl;
		++begin;

	}

	delete m1;
	delete m2;
	delete m3;
	delete m4;
	delete m5;
}

//4.容器嵌套容器
void test04()
{
	vector<vector<int>> vs;

	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	vector<int> v4;
	vector<int> v5;

	for (int i = 0; i < 5; i++)
	{
		v1.push_back(i + 10);
		v2.push_back(i + 10);
		v3.push_back(i + 10);
		v4.push_back(i + 10);
		v5.push_back(i + 10);
	}

	vs.push_back(v1);
	vs.push_back(v2);
	vs.push_back(v3);
	vs.push_back(v4);
	vs.push_back(v5);

	vector<vector<int>>::iterator begin = vs.begin();
	vector<vector<int>>::iterator end = vs.end();

	while (begin!=end)
	{
		vector<int>::iterator sbegin = (*begin).begin();
		vector<int>::iterator send = (*begin).end();

		while (sbegin!=send)
		{
			cout << *sbegin << " ";
			++sbegin;
		}

		cout << endl;
		++begin;
	}
}

int main()
{
	test04();
	system("pause");
	return EXIT_SUCCESS;
}

五.STL中的容器及其案例代码

1.string容器

        1.数据结构

                连续的存储空间,用一个char*指向这片空间

        2.迭代器

                随机访问迭代器

        3.常用的api

                1.构造

                2.基本赋值

                3.存取字符

                4.拼接

                5.查找和替换

                6.比较

                7.子串

                8.插入和删除

                9.string和const char*转换

        4.常用的api中的注意:

                1.[]和at区别:[]如果越界,不抛异常,直接挂。at会抛异常

                2.字符串内存重新分配,[]和at获取的字符引用,再次使用时,可以能会出错

                3.string和char *的区别:string是一个类,char *是一个指针

void test10()
{
	string s = "abcde";
	char &a = s[2];
	char &b = s[3];

	a = '1';
	b = '2';
	cout << "a:" << a << endl;
	cout << "b:" << b << endl;
	cout << s << endl;
	cout << "字符串的原空间地址:" << (int*)s.c_str() << endl;

	s = "fdasfdasfdsafdasherewrkewhsaferew";
	cout << "字符串的空间地址:" << (int*)s.c_str() << endl;

	//原空间被释放,但是a还是被释放的s[2]空间的别名,如果操作非法的空间,会出错
	//a = '3';


}

2.vector容器

        1.数据结构

                连续存储空间

        2.迭代器

                随机迭代器

        3.vector容器动态增长原理

                1.当存储空不够时,会开辟另一块大的空间,然后把数据拷贝过去,最后在销毁原来的空间

                2.申请的空间,会比用户需求大一点

                3.重新分配空间,那么原来的迭代器就会失效

        4.常用的api

                1.构造

                2.赋值操作

                3.大小操作

                4.数据存取

                5.插入和删除

        5.常用的api中的注意

                1.resize开辟空间,并初始化。reserve开辟空间,但不初始化.没有初始化的空间不能访问

        6.reserve作用

                如果容器要存储大量数据时,要先开辟空间,避免多次申请空间

        7.swap作用

                缩小容器的容量

3.deque容器

        1.数据结构

                逻辑上是连续的存储空间,实际上的由很多块定量的块空间,通过中控制连接起来

        2.迭代器

                随机迭代器

        3.常用的api

​                    1.构造

​                    2.赋值

​                    3.大小

​                    4.双端插入和删除操作

​                    5.插入和删除操作

4.案例1:打分案例

        1.目的

                5个学生,10个评委,10个评委的分数去掉最高和最低分,取平均分就是学生的分数

        2.思路

                1.抽象学生

                2.使用vector容器存储学生

                3.把分数放入deque容器,然后对deque容器进行排序,之后删除首尾元素

        3.流程

                1.创建学生

                2.评委给学生打分

                3.根据学生的分数排名并打印

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<deque>
#include<string>
#include<algorithm>//算法头文件
#include<ctime>
using namespace std;
//目的:5个学生,10个评委,10个评委的分数去掉最高和最低分,取平均分就是学生的分数
//抽象学生
class Student
{
public:
	string name;
	int mScore;
};

//1.创建学生
void CreateStudent(vector<Student> &vstu)
{
	string setName = "ABCDE";
	for (int i = 0; i < 5; i++)
	{
		//创建学生
		Student stu;
		stu.name = "学生";
		stu.name += setName[i];
		stu.mScore = 0;
		vstu.push_back(stu);//把学生放入容器
	}
}
//2.评委给学生打分
void SetScore(vector<Student> &vstu)
{
	srand((unsigned int)time(NULL));
	//遍历学生
	for (vector<Student>::iterator it = vstu.begin(); it != vstu.end(); ++it)
	{
		//保存分数
		deque<int> dScore;
		//评委给学生打分
		for (int i = 0; i < 10; i++)
		{
			int score = rand() % 70 + 30;
			dScore.push_back(score);
		}
		//排序
		sort(dScore.begin(),dScore.end());
		//去掉最高分和最低分
		dScore.pop_back();
		dScore.pop_front();

		//求总分
		int tota = 0;
		for (deque<int>::iterator sit = dScore.begin(); sit != dScore.end(); ++sit)
		{
			tota += (*sit);
		}

		//求平均分
		int agescore = tota / dScore.size();

		//平均分存储到对象中
		it->mScore = agescore;

	}
}
//谓词
bool mycomapre(Student &s1, Student &s2)
{
	return s1.mScore > s2.mScore;
}
//3.排名并打印
void ShowStudentScore(vector<Student> &vstu)
{
	//排序算法,mycomapre改变sort的默认规则
	sort(vstu.begin(), vstu.end(), mycomapre);
	for (vector<Student>::iterator it = vstu.begin(); it != vstu.end(); ++it)
	{
		cout << "Name:" << it->name << " Score:" << it->mScore << endl;
	}


}
void test()
{
	//存储学生的容器
	vector<Student> vstu;

	//1.创建学生
	CreateStudent(vstu);
	//2.评委给学生打分
	SetScore(vstu);
	//3.排名并打印
	ShowStudentScore(vstu);

}

int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

5.stack容器

        1.数据结构

                连续的存储空间,只有一个出口,先进后出特性

        2.迭代器

                没有迭代器

        3.常用的api

                1.构造函数

                2.赋值

                3.数据存取

                4.大小操作

6.queue容器

        1.数据结构

                连续的存储空间,有两个口,一个是进入数据,一个是出数据,有先进先出的特性

        2.迭代器

                没有迭代器

        3.常用的api

                1.构造函数

                2.存取、插入和删除操作

                3.赋值

                4.大小操作

7.list容器

        1.数据结构

                双向循环链表

        2.迭代器

                双向迭代器

        3.常用的api

                1.构造

                2.数据元素的插入和删除

                3.大小操作

                4.赋值操作

                5.数据的存取

                6.反转和排序

        4.注意

                list容器不能使用常用的sort,只能使用自己的sort

8.电梯案例

        1.目的

                获取进出电梯人数及姓名,并打印出来

        2.思路

                1.抽象人员

                2.抽象电梯(list)

                3.进电梯的人(queue)

                4.把进电梯和出电梯的人拷贝一份放入vector中,待打印

        3.流程

                1.电梯上升

                2.创建人员

                3.判断进电梯条件,然后进电梯

                4.判断出电梯条件,然后出电梯

                5.打印出电梯和进电梯人员的人数和姓名

9.pair对组

        1.pair对组是一个类,类中有两个公有的成员变量

        2.对组通常用来接收key-vluae这样的元素

10.set/multimap容器

        1.set容器

                set是关联式容器,容器自身有规则,通过键值排序,set容器中的元素是键值也是实值

        2.set容器和multiset容器的区别

                multiset允许有相同的元素

        3.数据结构

                平衡二叉树

        4.迭代器

                双向迭代器

        5.常用的api

                1.构造

                2.赋值

                3.大小

                4.插入和删除

                5.查找操作

        6.改变规则

                默认是从小到大,改变规则,加入谓词到<>第二个参数中

        7.注意

                1.set容器插入相同元素时,不会报错,但是不插入数据

                2.set容器存储对象时,需要告诉set容器的规则

11.map/multimap容器

        1.map/multimap

                map/multimap也是关联式容器,容器自身有规则,通过键值排序,map容器中的元素是对组,对组的第一个元素是键值,不能改变,第二个元素是实值,可以改变

        2.数据结构

                平衡二叉树

        3.迭代器

                双向迭代器

        4.map容器和multimap容器的区别

                multimap允许有相同的元素

        5.常用的api

                1.构造

                2.赋值

                3.大小

                4.查找

                5.插入

                6.删除

12.案例2:分组案例

        1.目的

                公司今天招聘了5个员工,5名员工进入公司之后,需要指派员工在那个部门工作,指派完成后打印员工部门和员工信息

        2.思路

                1.抽象员工

                2.把未分组员工放入到vector容器中

                3.把分组好的员工信息放入到multimap中

        3.流程

                1.创建员工

                2.分组员工

                3.打印员工信息

六.STL的深浅拷贝问题

1.把对象放入容器,其实是拷贝一份对象到容器。

2.注意:

        1.拷贝构造要能被调用 ​

        2.注意要浅拷贝问题

 七.函数对象与函数对象适配

1.函数对象

        1.1 什么是函数对象

                1.类中重载了(),这个类实例化的对象叫函数对象(仿函数);

                2.一元仿函数是operator()中只需要一个参数。二元仿函数是operator()中需要二个参数

        1.2 有什么用

                1.做为算法的策略

void test()
{
	vector<int> v;
	v.push_back(8);
	v.push_back(1);
	v.push_back(6);
	v.push_back(3);
	v.push_back(7);


	sort(v.begin(), v.end(), greater<int>());

	for_each(v.begin(), v.end(), [](int val){cout << val << " "; });
	//[](int val){cout << val << " "; }//匿名函数


}

        1.3 函数对象和普通函数的区别

                1.函数对象可以有自己的状态

                2.普通函数没有类型,函数对象有类型

                3.函数对象比普通函数执行效率有可能更高(成员函数自动申请为内联函数)

        1.4 谓词

                1.谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。

                2.谓词可以作为一个判断式

                3.接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓词

        1.5 内建函数对象        

                1.使用内建的函数对象要加入头文件#include<functional>

2.函数对象适配

        2.1 什么是函数对象适配

                当函数对象的参数不够用,那么可以用适配器来配置函数对象。

        2.2 函数适配器

                bind1st,bind2nd,将二元函数对象配置为一元函数对象

//第一步:继承binary_function<参数1,参数2,返回类型>
struct Myfunc:public binary_function<int,int,void>
{
	void operator()(int v1,int v2)const //第二步:加上const成为常函数,参数变2个
	{
		//cout << v1 << " " << endl;
		cout << v1 + v2 << endl;//第三步:实现函数体
	}

};
//需求:打印时,每个元素加100然后打印出来
void test()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);

	//for_each(v.begin(), v.end(), Myfunc());
	//第四步:用bind2nd来绑定函数对象
	for_each(v.begin(), v.end(), bind2nd(Myfunc(),100));
}

        2.3  bind1st和bind2nd的区别

                bind1st把100绑定给第一个参数,bind2nd把100绑定给第二个参数

        2.4 函数对象适配器 not1 not2 取反

                1.not1和not2的区别:not1针对一元函数对象,not2针对二元函数对象

                2.使用not1和not2

//第一步:继承
struct MyNotfunc:public unary_function<int,bool>
{
	bool operator()(int v)const //第二步:变为常函数
	{
		return v >= 20;
	}
	 
};
//not1 和not2 
void myPrint(int val)
{
	cout << val << " ";
}

void test02()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(50);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);

	//find_if()

	/*
	_InIt _Find_if(_InIt _First, _InIt _Last, _Pr _Pred)
	{	// find first satisfying _Pred
		for (; _First != _Last; ++_First)
		if (_Pred(*_First))
			break;
		return (_First);
	}
	*/
	//第三步:适配
	vector<int>::iterator it=find_if(v.begin(), v.end(), not1(MyNotfunc()));
	if (it == v.end())
	{
		cout << "查找失败" << endl;
	}
	else
	{
		cout << "查找成功=" << *it << endl;
	}

	//not2的使用
	//less 二元函数对象
	vector<int> v2;
	v2.push_back(10);
	v2.push_back(50);
	v2.push_back(30);
	v2.push_back(40);
	v2.push_back(50);
	//release模式下可以
	sort(v2.begin(), v2.end(),not2(less<int>()));
	for_each(v2.begin(), v2.end(), myPrint);
}

        2.5 普通函数进行适配

//普通函数进行适配 ptr_fun
//第一步:把一个参数变为二个参数
void myprint2(int val,int val2)
{
	cout << val+val2<< " ";
}
void test03()
{
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);

	//第二步:把普通函数变为函数对象 ptr_fun
	for_each(v.begin(), v.end(), bind2nd(ptr_fun(myprint2),100));
}

        2.6 成员函数适配

                1.mem_fun : 如果存储的是对象指针,需要使用mem_fun

                2.mem_fun_ref : 如果存储的是对象,需要使用mem_fun_ref

class Maker
{
public:
	Maker(string name,int age)
	{
		this->name = name;
		this->age = age;
	}
	//成员函数
	void MyprintMaker()
	{
		cout << "Name:" << this->name << " Age:" << this->age << endl;
	}
public:
	string name;
	int age;
};
//void MyprintMaker(Maker m)
//{
//	cout << "Name:" << m.name << " Age:" << m.age << endl;
//}
void test04()
{
	vector<Maker> v;
	v.push_back(Maker("aaa", 10));
	v.push_back(Maker("bbb", 20));
	v.push_back(Maker("ccc", 30));
	//当容器存储的是对象,用mem_fun_ref适配他的成员函数
	for_each(v.begin(), v.end(), mem_fun_ref(&Maker::MyprintMaker));
	cout << "-------------" << endl;
	vector<Maker*> vp;
	vp.push_back(new Maker("aaa", 10));
	vp.push_back(new Maker("bbb", 20));
	vp.push_back(new Maker("ccc", 30));
	//当容器存储的是对象指针,用mem_fun适配他的成员函数
	for_each(vp.begin(), vp.end(), mem_fun(&Maker::MyprintMaker));
}

八.空间配置器

        如果申请的内存大小超过128,那么空间配置器就自动调用一级空间配置器。反之调用二级空间配置器。

九.STL中的算法问题

1.算法的概念

        1.算法通过迭代器来操作容器中元素

        2.算法的头文件:<algorithm><functional><numeric>

2.遍历算法    

        1.for_each:遍历打印

                1.for_each(开始迭代器,结束迭代器,函数对象)

        2.transform:搬运

                1.transform(源开始迭代器,源结束迭代器,目标开始迭代器,函数对象)

                2.transform(源1开始迭代器,源1结束迭代器,源2开始迭代器,目标开始迭代器,函数对象)

3.查找算法

        1.find:查找元素

                find(开始迭代器,结束迭代器,要查找的数值);

                find_if(开始迭代器,结束迭代器,谓词或函数对象);

        2.adjacent_find算法 查找相邻重复元素

                adjacent_find(开始迭代器,结束迭代器)

                adjacent_find(开始迭代器,结束迭代器,谓词或函数对象);

        3.binary_search算法 二分查找法

                (注意:数据必须要有序,返回值是bool)

                binary_search(开始迭代器,结束迭代器,数值);

                binary_search(开始迭代器,结束迭代器,对象,函数对象);

        注意:存储对象,如果使用less,那么数据要是升序,并且要重载<,greater这需要数据是降序,并且要重载>

        4.count 统计元素个数

                count(开始迭代器,结束迭代器,数值);

                count(开始迭代器,结束迭代器,谓词或函数对象);

4.排序算法

        1.merge算法

                容器元素合并,并存储到另一容器中

                1.如果数据是升序,那么第六个参数就不用写

                merge(开始迭代器1,结束迭代器1,开始迭代器2,结束迭代器2,目标开始迭代器);

        2.如果数据是降序,那么第六个参数就要写greater<int>()

                merge(开始迭代器1,结束迭代器1,开始迭代器2,结束迭代器2,目标开始迭代器,greater<int>());

        2.sort算法

                容器元素排序

                1.sort(开始迭代器,结束迭代器);

                2.存储的是对象时,sort(开始迭代器,结束迭代器,函数对象);

        3.random_shuffle

                洗牌

                定义随机种子:srand((unsigned int)time(NULL));

                random_shuffle(开始迭代器,结束迭代器)

        4.reverse算法

                反转指定范围的元素

                reverse(开始迭代器,结束迭代器)

5.拷贝和替换算法

        1.copy:拷贝

                copy(源开始迭代器,源结束迭代器,目标开始迭代器);

        2.replace算法

                将容器内指定范围的旧元素修改为新元素,replace_if算法 将容器内指定范围满足条件的元素替换为新元素

                1.replace(开始迭代器,结束迭代器,旧值,新值);

                2.replace_if(开始迭代器,结束迭代器,谓词,新值);

        3.swap,交换容器

                swap(容器1,容器2);

6.算术生成算法

        1.accumulate算法 计算容器元素累计总和

                1.int ret=accumulate(开始迭代器,结束迭代器,数值);//第三个参数是在总和上再加上0

                2.int ret=accumulate(开始迭代器,结束迭代器,数值,函数对象);//针对存储对象

        2.fill算法 向容器中添加元素

                1.要开辟容器的空间.v.resize(10);

                2.fill(开始迭代器,结束迭代器,要填充的数值)

7.集合算法

        1.注意:两个集合必须是有序序列

        2.set_intersection算法 求两个集合的交集

                set_intersection(源开始迭代器1,源结束迭代器1,源开始迭代器2,源结束迭代器2,,目标开始迭代器);

        3.set_union算法 求两个set集合的并集

                set_union(源开始迭代器1,源结束迭代器1,源开始迭代器2,源结束迭代器2,,目标开始迭代器);

        4.set_difference算法

                求两个set集合的差集 //假如A集合有1,2,3,4,5 B集合有2,3,4,5,6 A集合减B集合的结果就是1

                set_difference(源开始迭代器1,源结束迭代器1,源开始迭代器2,源结束迭代器2,,目标开始迭代器);

十.综合案例

1.定义演讲者

class Player
{
public:
	string name;
	int age;
	int mScore[3];//最多有三轮比赛成绩
};

2.思路

        1.用vector存储编号(编号对应选手)

        2.用map保存选手信息(键值是编号,实值是选手)

        3.每一轮的结果存储到vector中,只保存选手的编号

3.流程

        1.创建选手

        2.第一轮比赛:抽签,比赛,打印本轮晋级选手名单

        3.第二轮比赛:抽签,比赛,打印本轮晋级选手名单

        4.第三轮比赛:抽签,比赛,打印本轮晋级选手名单

4.比赛

        1.学生成绩存储到deque容器中,计算出分数

        2.评比:当选手计算出平均分时,把选手放入到multimap中,当该容器达到6位选手时,进行筛选,取前三名,然后清空容器;

5.详细代码

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
#include<deque>
#include<map>
#include<ctime>
#include<algorithm>
#include<numeric>
#include<functional>

using namespace std;

class Player
{
public:
	string name;
	int age;
	int mScore[3];
};
//创建选手
void CreatePlayer(vector<int> &v1, map<int, Player> &mlist)
{
	string setName = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	for (int i = 0; i < 24; i++)
	{
		//创建选手
		Player p;
		p.name = "选手";
		p.name += setName[i];
		p.age = 20;
		for (int j = 0; j < 3; j++)
		{
			p.mScore[j] = 0;
		}
		//生成选手编号
		int ID = 100 + i;
		//保存选手编号
		v1.push_back(ID);
		//保存选手信息
		mlist.insert(make_pair(ID, p));

	}
}

//1.抽签
void PlayerByRandon(vector<int> &v)
{
	random_shuffle(v.begin(), v.end());
}
//2.比赛
void StartMatch(int index, vector<int> &v1, map<int, Player> &mlist, vector<int> &v2)
{
	//定义multimap容器,键值是分数,实值是选手编号
	multimap<int, int, greater<int>> mGroups;
	for (vector<int>::iterator sit = v1.begin(); sit != v1.end(); ++sit)
	{
		//保存分数
		deque<int> dScore;
		for (int i = 0; i < 10; i++)
		{
			int score = rand() % 50 + 50;
			dScore.push_back(score);
		}
		//排序
		sort(dScore.begin(), dScore.end());
		//去掉最高和最低分
		dScore.pop_back();
		dScore.pop_front();

		//求总分
		int toScore = accumulate(dScore.begin(), dScore.end(), 0);
		//求平均分
		int avgScore = toScore / dScore.size();

		//保存到选手信息中
		mlist[*sit].mScore[index - 1] = avgScore;

		//把选手放入multimap容器中
		mGroups.insert(make_pair(avgScore, *sit));
		//评比
		if (mGroups.size() == 6)
		{
			//容器中一共有6个人,去掉后三名
			int cnt = 0;
			for (multimap<int, int, greater<int>>::iterator it = mGroups.begin(); it != mGroups.end()&& cnt<3;cnt++, ++it)
			{
				v2.push_back(it->second);

			}

			//清空容器
			mGroups.clear();
		}
		
	}
}

//3.打印本轮晋级选手的名单
void ShowPlayerScore(int index, vector<int> &v, map<int, Player> &mlist)
{
	cout << "第" << index << "轮晋级名单:" << endl;
	for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
	{
		cout << "Name:" << mlist[*it].name << " Age:" << mlist[*it].age << " Score:" << mlist[*it].mScore[index-1] << endl;
	}
}

void test()
{
	srand((unsigned int)time(NULL));
	vector<int> v1;//保存选手编号
	map<int, Player> mlist;//保存选手信息

	vector<int> v2;//保存第一轮晋级选手的编号
	vector<int> v3;//保存第二轮晋级选手的编号
	vector<int> v4;//保存第三轮晋级选手的编号

	//创建选手
	CreatePlayer(v1,mlist);

	//第一轮
	//1.抽签
	PlayerByRandon(v1);
	//2.比赛
	StartMatch(1,v1,mlist,v2);
	//3.打印本轮晋级选手的名单
	ShowPlayerScore(1, v2, mlist);

	//第二轮
	//1.抽签
	PlayerByRandon(v2);
	//2.比赛
	StartMatch(2, v2, mlist, v3);
	//3.打印本轮晋级选手的名单
	ShowPlayerScore(2, v3, mlist);

	//第三轮
	//1.抽签
	PlayerByRandon(v3);
	//2.比赛
	StartMatch(3, v3, mlist, v4);
	//3.打印本轮晋级选手的名单
	ShowPlayerScore(3, v4, mlist);
}

int main()
{
	test();
	system("pause");
	return EXIT_SUCCESS;
}

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值