【C++】STL综合案例

00. 目录

在这里插入图片描述

01. 题目要求

某市举行一场演讲比赛( speech_contest ),共有24个人参加。比赛共三轮,前两轮为淘汰赛,第三轮为决赛。

比赛方式:分组比赛,每组6个人;选手每次要随机分组,进行比赛;

第一轮分为4个小组,每组6个人。比如编号为: 100-123. 整体进行抽签(draw)后顺序演讲。当小组演讲完后,淘汰组内排名最后的三个选手,然后继续下一个

小组的比赛。

第二轮分为2个小组,每组6人。比赛完毕,淘汰组内排名最后的三个选手,然后继续下一个小组的比赛。

第三轮只剩下1组6个人,本轮为决赛,选出前三名。

比赛评分:10个评委打分,去除最低、最高分,求平均分每个选手演讲完由10个评委分别打分。

该选手的最终得分是去掉一个最高分和一个最低分,求得剩下的8个成绩的平均分。选手的名次按得分降序排列。

用STL编程,求解这个问题

1) 请打印出所有选手的名字与参赛号,并以参赛号的升序排列。

2) 打印每一轮比赛后,小组比赛成绩和小组晋级名单

02. 思路分析

需要把选手信息、选手得分信息、选手比赛抽签信息、选手的晋级信息保存在容器中,需要涉及到各个容器的选型。

选手可以设计一个类Person(姓名和得分)

所有选手的编号可以单独放在一个vector容器中,做抽签用

所有选手编号和选手信息,可以放在容器内:map<int, Person>

所有选手的编号名单,可以放在容器:vecter v1中

第1轮晋级编号名单,可以放在容器vecter v2中

第2轮晋级编号名单,可以放在容器vecter v3中

第3轮前三名名单,可以放在容器vecter v4中

每个小组的比赛得分信息,按照从大到小的顺序放在multimap<成绩, 编号, greater>中

03. 随机重排

算法:

random_shuffle
shuffle
随机重排范围中的元素

可能实现V1

template<class RandomIt>
void random_shuffle(RandomIt first, RandomIt last)
{
    typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
 
    for (diff_t i = last - first - 1; i > 0; --i)
    {
        using std::swap;
        swap(first[i], first[std::rand() % (i + 1)]);
        // rand() % (i + 1) 实际上不准确,因为生成的数对于多数 i 值不均匀分布。
        // 正确实现将实际上需要重新实现 C++11 std::uniform_distributtion,
        // 这超出了此示例的范畴。
    }
}

可能实现V2

template<class RandomIt, class RandomFunc>
void random_shuffle(RandomIt first, RandomIt last, RandomFunc&& r)
{
    typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
 
    for (diff_t i = last - first - 1; i > 0; --i)
    {
        using std::swap;
        swap(first[i], first[r(i + 1)]);
    }
}

可能实现V3

template<class RandomIt, class URBG>
void shuffle(RandomIt first, RandomIt last, URBG&& g)
{
    
    
    typedef typename std::iterator_traits<RandomIt>::difference_type diff_t;
    typedef std::uniform_int_distribution<diff_t> distr_t;
    typedef typename distr_t::param_type param_t;
 
    distr_t D;
    for (diff_t i = last - first - 1; i > 0; --i)
    {
    
    
        using std::swap;
        swap(first[i], first[D(g, param_t(0, i))]);
    }
}

程序示例:

#include <random>
#include <algorithm>
#include <iterator>
#include <vector>

using namespace std;


int main(void)
{
    
    

    random_device rd;
    mt19937 g(rd());

    vector<int> v {
    
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    shuffle(v.begin(), v.end(), g);

    copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    cout << endl;

    return 0;
}

运行结果:

deng@local:~/code$ ./a.out  
3 1 7 5 4 9 6 2 10 8 
deng@local:~/code$ ./a.out  
4 3 8 2 7 6 9 5 10 1 
deng@local:~/code$ ./a.out  
10 8 9 1 5 3 7 4 2 6 
deng@local:~/code$ ./a.out  
9 4 8 1 6 3 7 2 5 10 
deng@local:~/code$ ./a.out  
2 10 6 5 8 1 7 9 3 4 
deng@local:~/code$ ./a.out  
5 2 6 3 10 1 9 8 7 4 
deng@local:~/code$ ./a.out  
9 4 10 6 3 8 5 2 7 1 
deng@local:~/code$ ./a.out  
2 1 8 9 3 6 10 4 5 7 
deng@local:~/code$ ./a.out  
8 6 10 1 3 2 7 5 4 9 
deng@local:~/code$ 

04. 创建选手

程序示例:

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <map>

using namespace std;

//选手信息
class Person
{
    friend int showPerson(const map<int, Person> &m);
public:
    //无参构造函数
    Person()
    {

    }
    //有参构造函数
    Person(int num, string name)
    {
        mNum = num;
        mName = name;

        memset(mScore, 0, 3 * sizeof(float));
    }

private:
    //参赛号
    int mNum;
    //姓名
    string mName; 
    //得分 分别存储第1,2,3轮得分
    float mScore[3];
};

//创建选手
int createPerson(vector<int> &v, map<int, Person> &m)
{
    int i = 0;
    string name;
    string str = "ABCDEFGHIJKLMNOPQRSTUVWX";

    //24个选手
    for (i = 100; i < 124; i++)
    {
        //存放选手编号
        v.push_back(i);

        //选手编号和选手信息关联
        name = "选手";
        name += str[i - 100];


        m.insert(make_pair(i, Person(i, name)));
    }

    return 0;
}

//显示选手
int showPerson(const map<int, Person> &m)
{
    map<int, Person>::const_iterator it;

    for (it = m.begin(); it != m.end(); it++)
    {
        cout << "选手编号: " << it->first << " 选手姓名: " << it->second.mName << endl;
    }

    return 0;
}


int main(void)
{
    //使用vector容器存储选手编号 
    vector<int> v;
    //使用map容器存储编号和选手的信息
    map<int, Person> m;

    //创建选手
    createPerson(v, m);
    //显示选手信息
    showPerson(m);

    return 0;
}

运行结果

deng@local:~/code$ g++ test.cpp  
deng@local:~/code$ ./a.out  
选手编号: 100 选手姓名: 选手A
选手编号: 101 选手姓名: 选手B
选手编号: 102 选手姓名: 选手C
选手编号: 103 选手姓名: 选手D
选手编号: 104 选手姓名: 选手E
选手编号: 105 选手姓名: 选手F
选手编号: 106 选手姓名: 选手G
选手编号: 107 选手姓名: 选手H
选手编号: 108 选手姓名: 选手I
选手编号: 109 选手姓名: 选手J
选手编号: 110 选手姓名: 选手K
选手编号: 111 选手姓名: 选手L
选手编号: 112 选手姓名: 选手M
选手编号: 113 选手姓名: 选手N
选手编号: 114 选手姓名: 选手O
选手编号: 115 选手姓名: 选手P
选手编号: 116 选手姓名: 选手Q
选手编号: 117 选手姓名: 选手R
选手编号: 118 选手姓名: 选手S
选手编号: 119 选手姓名: 选手T
选手编号: 120 选手姓名: 选手U
选手编号: 121 选手姓名: 选手V
选手编号: 122 选手姓名: 选手W
选手编号: 123 选手姓名: 选手X
deng@local:~/code$ 

05. 抽签比赛

程序示例

#include <iostream>
#include <string>
#include <vector>
#include <cstring>
#include <map>
#include <deque>
#include <ctime>

#include <random>
#include <algorithm>
#include <iterator>

using namespace std;

//随机重排相关
random_device rd;
mt19937 g(rd());

//选手信息
class Person
{
    friend int showPerson(const map<int, Person> &m);
    friend int playGame(int index, vector<int> &v, map<int, Person> &m, vector<int> &v1);
public:
    //无参构造函数
    Person()
    {

    }
    //有参构造函数
    Person(int num, string name)
    {
        mNum = num;
        mName = name;

        memset(mScore, 0, 3 * sizeof(float));
    }

private:
    //参赛号
    int mNum;
    //姓名
    string mName; 
    //得分 分别存储第1,2,3轮得分
    float mScore[3];
};

//创建选手
int createPerson(vector<int> &v, map<int, Person> &m)
{
    int i = 0;
    string name;
    string str = "ABCDEFGHIJKLMNOPQRSTUVWX";

    //24个选手
    for (i = 100; i < 124; i++)
    {
        //存放选手编号
        v.push_back(i);

        //选手编号和选手信息关联
        name = "选手";
        name += str[i - 100];


        m.insert(make_pair(i, Person(i, name)));
    }

    return 0;
}

//显示选手
int showPerson(const map<int, Person> &m)
{
    map<int, Person>::const_iterator it;

    for (it = m.begin(); it != m.end(); it++)
    {
        cout << "选手编号: " << it->first << " 选手姓名: " << it->second.mName << endl;
    }

    return 0;
}

//参加比赛
//v存储参加比赛的选手编号, m存储选手信息 v1存储晋级选手编号
int playGame(int index, vector<int> &v, map<int, Person> &m, vector<int> &v1)
{
    int count = 0;
    
    int i = 0;


    //平均分
    float avg = 0;

    //存储选手得分
    deque<int> d;

    //存储分数和编号
    multimap<float, int, greater<float>> mul;

    //随机重排选手
    shuffle(v.begin(), v.end(), g);

#if 0
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
#endif

    cout << "-------------第" << index << "轮比赛-----------" << endl;

    //每6人一组
    vector<int>::iterator it;     
    for (it = v.begin(); it != v.end(); it++)
    {
        count++;
        
        //10评委评分
        for (i = 0; i < 10; i++)
        {
            d.push_back((float)(random() % 80 + 21));
        }

        //对容器进行排序
        sort(d.begin(), d.end());
        //去掉最高分和最低分
        d.pop_back();
        d.pop_front();

        //计算平均分
        avg = accumulate(d.begin(), d.end(), 0) / d.size();

        //将选手得分保存到容器中
        m[*it].mScore[index - 1] = avg; 

        //存储选手编号和得分
        mul.insert(make_pair(avg, *it));


        //刚好每6人一组
        if (0 == count % 6)
        {
            multimap<float, int, greater<float>>::iterator mit;

            int j = 0;

            //将前3名存储到晋级容器中
            mit = mul.begin();
            for (j = 0; j < 3; j++, mit++)
            {
                v1.push_back(mit->second);
            }

            cout << "\t------------第" << count / 6 << "组的成绩---------------" << endl;
            //遍历当前容器中所有人员的成绩
            for (mit = mul.begin(), j = 0; j < 6; j++, mit++)
            {
                cout << "\t\t" << m[mit->second].mName << " 编号: " << mit->second
                     << " 成绩: " << mit->first;
                if (j < 3)
                {
                    cout << "恭喜晋级" << endl;
                }
                else
                {
                    cout << endl;
                }

            }

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

    return 0;
}

int main(void)
{
    
    //设置随机种子
    srandom(time(NULL));

    //使用vector容器存储选手编号 
    vector<int> v;
    //使用map容器存储编号和选手的信息
    map<int, Person> m;

    //存储第一轮晋级名单
    vector<int> v1;
    
    //存储第二轮晋级名单
    vector<int> v2;
    
    //存储第二轮晋级名单
    vector<int> v3;

    //创建选手
    createPerson(v, m);
    //显示选手信息
    showPerson(m);
    
    cout << "====================================================" << endl;
    playGame(1, v, m, v1);
    cout << "====================================================" << endl;
    playGame(2, v1, m, v2);
    cout << "====================================================" << endl;
    playGame(3, v2, m, v3);

    return 0;
}

运行结果

deng@local:~/code$ ./a.out  
选手编号: 100 选手姓名: 选手A
选手编号: 101 选手姓名: 选手B
选手编号: 102 选手姓名: 选手C
选手编号: 103 选手姓名: 选手D
选手编号: 104 选手姓名: 选手E
选手编号: 105 选手姓名: 选手F
选手编号: 106 选手姓名: 选手G
选手编号: 107 选手姓名: 选手H
选手编号: 108 选手姓名: 选手I
选手编号: 109 选手姓名: 选手J
选手编号: 110 选手姓名: 选手K
选手编号: 111 选手姓名: 选手L
选手编号: 112 选手姓名: 选手M
选手编号: 113 选手姓名: 选手N
选手编号: 114 选手姓名: 选手O
选手编号: 115 选手姓名: 选手P
选手编号: 116 选手姓名: 选手Q
选手编号: 117 选手姓名: 选手R
选手编号: 118 选手姓名: 选手S
选手编号: 119 选手姓名: 选手T
选手编号: 120 选手姓名: 选手U
选手编号: 121 选手姓名: 选手V
选手编号: 122 选手姓名: 选手W
选手编号: 123 选手姓名: 选手X
====================================================
-------------第1轮比赛-----------
	------------第1组的成绩---------------
		选手D 编号: 103 成绩: 65恭喜晋级
		选手J 编号: 109 成绩: 62恭喜晋级
		选手F 编号: 105 成绩: 61恭喜晋级
		选手G 编号: 106 成绩: 59
		选手I 编号: 108 成绩: 58
		选手U 编号: 120 成绩: 57
	------------第2组的成绩---------------
		选手B 编号: 101 成绩: 60恭喜晋级
		选手K 编号: 110 成绩: 59恭喜晋级
		选手N 编号: 113 成绩: 58恭喜晋级
		选手H 编号: 107 成绩: 58
		选手W 编号: 122 成绩: 57
		选手V 编号: 121 成绩: 56
	------------第3组的成绩---------------
		选手L 编号: 111 成绩: 61恭喜晋级
		选手X 编号: 123 成绩: 60恭喜晋级
		选手R 编号: 117 成绩: 60恭喜晋级
		选手T 编号: 119 成绩: 59
		选手S 编号: 118 成绩: 59
		选手P 编号: 115 成绩: 58
	------------第4组的成绩---------------
		选手E 编号: 104 成绩: 61恭喜晋级
		选手M 编号: 112 成绩: 61恭喜晋级
		选手Q 编号: 116 成绩: 61恭喜晋级
		选手O 编号: 114 成绩: 61
		选手C 编号: 102 成绩: 61
		选手A 编号: 100 成绩: 61
====================================================
-------------第2轮比赛-----------
	------------第1组的成绩---------------
		选手D 编号: 103 成绩: 70恭喜晋级
		选手N 编号: 113 成绩: 64恭喜晋级
		选手X 编号: 123 成绩: 63恭喜晋级
		选手Q 编号: 116 成绩: 61
		选手B 编号: 101 成绩: 57
		选手F 编号: 105 成绩: 57
	------------第2组的成绩---------------
		选手L 编号: 111 成绩: 62恭喜晋级
		选手R 编号: 117 成绩: 61恭喜晋级
		选手E 编号: 104 成绩: 60恭喜晋级
		选手K 编号: 110 成绩: 60
		选手J 编号: 109 成绩: 59
		选手M 编号: 112 成绩: 58
====================================================
-------------第3轮比赛-----------
	------------第1组的成绩---------------
		选手L 编号: 111 成绩: 64恭喜晋级
		选手D 编号: 103 成绩: 58恭喜晋级
		选手R 编号: 117 成绩: 58恭喜晋级
		选手N 编号: 113 成绩: 57
		选手X 编号: 123 成绩: 57
		选手E 编号: 104 成绩: 56
deng@local:~/code$ 

06. 讨论

07. 附录

中文cppreference社区地址:http://zh.cppreference.com/w/Main_Page

英文cppreference社区地址:https://en.cppreference.com/w/Main_Page

cppreference社区FAQ:https://zh.cppreference.com/w/Cppreference:FAQ

猜你喜欢

转载自blog.csdn.net/dengjin20104042056/article/details/132397560