具体案例:
学校需要将不同学科的学生分配到一组。每个学生都必须学习指定的最小数目的学科。每个学习特定学科的学生都被保存到 set容器中,因为一个学生只能在一门特定课程中出现一次。
基本流程:
第一步:学生类
代码语言:javascript复制 #ifndef STUDENT_H
#define STUDENT_H
#include <string>
#include <ostream>
//两个成员函数,保存姓,名
class Student
{
private:
std::string first {};
std::string second {};
public:
Student(const std::string& name1, const std::string& name2) : first (name1), second (name2){}
//移动构造
Student(Student&& student) : first(std::move(student.first)),
second(std::move(student.second)){}
//复制构造
Student(const Student& student) : first(student.first), second(student.second){} // Copy constructor
Student() {} // Default constructor
bool operator<(const Student& student) const
{
return second < student.second || (second == student.second && first < student.first);
}
//友元函数重载了一个流插入运算符来辅助输出
friend std::ostream& operator<<(std::ostream& out, const Student& student);
};
inline std::ostream& operator<<(std::ostream& out, const Student& student)
{
out << student.first " " student.second;
return out;
}
#endif
第二步:输出类
代码语言:javascript复制#ifndef LIST_COURSE_H
#define LIST_COURSE_H
#include <iostream>
#include <string>
#include <set>
#include <algorithm>
#include <iterator>
#include "s.h"
using Subject = std::string;
using Group = std::set<std::weak_ptr<Student>, std::owner_less<std::weak_ptr<Student>>>;
using Course = std::pair<Subject, Group>;
class List_Course
{
public:
void operator()(const Course& course)
{
std::cout << "nn" << course.first << " " << course.second.size() << " students:n ";
std::copy(std::begin(course.second), std::end(course.second),
std::ostream_iterator<std::weak_ptr<Student>>(std::cout, " "));
}
};
inline std::ostream& operator<<(std::ostream& out, const std::weak_ptr<Student>& wss)
{
out << *wss.lock();
return out;
}
#endif
第三步:主函数
代码语言:javascript复制 #include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <random>
#include <algorithm> // For for_each(), count_if()
#include <memory> // For shared_ptr and weak_ptr
#include "s.h"
#include "l.h"
using std::string;
using Distribution = std::uniform_int_distribution<size_t>;
using Subject = string;
using Subjects = std::vector<Subject>;
//学生集合对象别名
using Group = std::set<std::weak_ptr<Student>, std::owner_less<std::weak_ptr<Student>>>;
//定义学生类别名
using Students = std::vector<std::shared_ptr<Student>>;
using Course = std::pair<Subject, Group>;
//课程容器
using Courses = std::map<Subject, Group>;
//随机数创建器
//分布对象是一个函数对象,它可以创建分布内的随机数,可以将随机数创建器对象作为参数传给分布对象的成员函数opemtor()()
static std::default_random_engine gen_value;
// 创建对象
Students create_students()
{
Students students;
string first_names[]{"Ann", "Jim", "Eve", "Dan", "Ted"};
string second_names[]{"Smith", "Jones", "Howe", "Watt", "Beck"};
for(const auto& first : first_names)
for(const auto& second : second_names)
{
students.emplace_back(std::make_shared<Student>(first, second));
}
return students;
}
// 为指定学科随机创 建一组学生
//第一个参数是一个包含 Student 对象的 vector,第二个参数是组中要求的学生个数,
//最后一个参数是分布的索引值,用来选择随机创建的学生
Group make_group(const Students& students, size_t group_size,
Distribution& choose_student)
{
Group group;
size_t count{};
std::pair<Group::iterator, bool> pr;
while(count < group_size)
{ //如果插入的元素已经在容器中,成员函数 insert() 不会插入新的对象。
pr=group.insert(students[choose_student(gen_value)]);//???????????????????
if(pr.second)
count;
}
//会通过移动而不是复制的方式返回局部的 group 对象
return group;
}
int main()
{
Students students = create_students();
//学科定义
// subjects 是一个包含 string 对象的 vector 容器。
Subjects subjects {"Biology", "Physics", "Chemistry", "Mathematics",
"Astronomy","Drama", "Politics", "Philosophy", "Economics"};
//一个包含全部课程的容器
Courses courses; //pair<string,set<>>
//需要学习的最少学科数
size_t min_subjects{4};
//每组的最少学生数都设为相同的 值
size_t min_group{min_subjects};
//每个学科组的最大学生数就是一个平均值
size_t max_group{(students.size()*min_subjects) / subjects.size()};
//一个用来在均匀分布中选择随机值的函数对象:
//创建 min_group〜max_group 范围内的随机数
Distribution group_size{min_group, max_group};
//创建students中的有效索引值。
Distribution choose_student{0, students.size() - 1};
//为 course 容器填充了一些表示课程信息的元素
for(const auto& subject : subjects)
courses.emplace(subject, make_group(students, group_size(gen_value), choose_student));
//创建 subjects 容器的一个有效索引值,可以用它来选择课程
Distribution choose_course{0, subjects.size() - 1};
//检查每个学生是否都选了足够的课程
//如果没有选择足够的课程,为他们申请其他的课程
for(const auto& student : students)
{
//count_if() 算法用来计算每个学生已报名参加的课程数
//count_if() 的第三个参数必须是一个二元函数,它的返回值必须是布尔值或其他可以隐式转换为布尔型的值
size_t course_count = std::count_if(std::begin(courses), std::end(courses),
[&student](const Course& course)
{ return course.second.count(student); });
if(course_count >= min_subjects)
continue;
size_t additional{min_subjects - course_count};
if(!course_count)
std::cout << *student << " is work-shy, having signed up for NO Subjects!n";
else
std::cout << *student << " is only signed up for " << course_count << " Subjects!n";
std::cout << "Registering " << *student << " for " << additional
<< " more course" << (additional > 1 ? "s" : "") << ".nn";
//为这些学生申请新的课程,直到他们申请的课程数目满足要求
while(course_count < min_subjects)
if((courses.find(subjects[choose_course(gen_value)])->second.insert(student)).second)
course_count;
}
// 输出课程
std::for_each(std::begin(courses), std::end(courses), List_Course());
std::cout << std::endl;
}
结果显示: