按多个值对向量进行排序
Posted
技术标签:
【中文标题】按多个值对向量进行排序【英文标题】:Sort vector by multiple values 【发布时间】:2014-01-20 00:53:00 【问题描述】:我必须对向量进行排序。该向量包含指向“学生”类对象的指针。
评分指标如下所示:
-
最好的最终成绩
如果最终成绩相同,则尝试次数更少
如果相同的尝试,更少的 id
0 次尝试的学生比 2 次尝试和期末 5 的学生差,将 0 次尝试的学生按较少的 id 排序
学生长这样:
private:
std::string name_;
int id_;
int attempts_; //max 2, if 0, exam not taken
int grade1_;
int grade2_;
int finalGrade_; // grade 5 for failed exam but still better than 0 attempts in rating
我的问题是我不知道如何处理尝试。因为最佳尝试次数是 1 次,并且比 2 次尝试次数要好。但 2 次尝试在评分中优于 0。
我希望你能理解我的问题并能帮助我。谢谢 :)
【问题讨论】:
您需要一种不同类型的容器,它可能是一个多映射或您有一个键和一个值的东西。 @user2485710:这不是真的,sort
可以采用任意复杂的比较函数。
@BenVoigt 我不认为sort
可以很好地处理多个字段,可能你想要一个稳定的排序。无论如何,我认为向量是错误的数据结构。
@user2485710:规则似乎防止出现平局(平局由 ID 打破,这可能是唯一的),因此排序的稳定性无关紧要。
@user2485710:问题已经说了。请注意,平局最终会出现在排序级别 3 和 4 中,它们会被 ID 打破。
【参考方案1】:
在 STL 中有一个可用的函数,称为 std::sort
,它可以采用比较器函数(函数指针或函数对象)。
比较器函数必须返回一个布尔值,说明第一个元素是否应该严格出现在第二个元素之前。
这是我想出的比较器:
struct compare_student
inline bool
operator() (Student *left, Student *right) const
if(left->attempts_ == 0 && right->attempts_ == 0)
return left->id_ < right->id_;
else if(left->attempts_ == 0)
return false;
else if(right->attempts_ == 0)
return true;
return
left->finalGrade_ < right->finalGrade_ || // Compare final grade
left->finalGrade_ == right->finalGrade_ && ( // If final grade same:
left->attempts_ < right->attempts_ || // Compare attempts
left->attempts_ == right->attempts_ && ( // If attempts same:
left->id_ < right->id_ // Compare id's
)
);
;
显然,您的所有字段都是私有的,因此您需要使用它们的访问器方法,而不是直接访问它们,但以下是您的使用方法:
vector<Student *> students ...;
std::sort(students.begin(), students.end(), compare_student);
std::sort
不稳定,这意味着如果两个元素被认为是相等的,那么它们不一定会保持它们的相对顺序,这对你来说可能很重要。如果是,那么还有一个名为std::stable_sort
的函数确实有这样的保证,并且使用方式完全相同:
std::stable_sort(students.begin(), students.end(), compare_students);
编辑 实施说明
compare_students
是一个只有一个公共成员的类,所以不要这样做:
class compare_student
public:
...
;
我把它缩短为:
struct compare_student
...
;
(两者在 C++ 中是等价的,struct 只是一个具有默认公共访问权限的类。)
那么inline bool operator()
是什么意思。
inline
是给编译器的一个提示,这个函数可以内联,也就是说,用代码本身替换调用。
bool
是函数的返回类型。
operator()
是函数的名称,它是一个特殊情况的函数,当您将对象视为函数时会调用它:
Student *a, *b;
compare_student comparator ;
comparator(a, b); // calls comparator::operator()(a, b)
【讨论】:
谢谢,我在家的时候试试这个。只是几个问题。我需要“struct”吗?“inline bool operator()”是什么意思?到目前为止,当我编写排序函数时,我只是编写了 bool sortSomething(Student *k, Student *j) ... 然后将此比较函数用作 stl::sort 函数中的第三个参数 thx buddy @d0zer:比较不需要存储任何状态,所以一个独立的函数非常好,更容易。我也不会使用这个答案显示的巨大的|| == &&
链。但是 asQuirrel 给了你一个很大的线索。
@d0zer 根据是否经常使用比较器,函数对象比函数指针更便于内联。如果这不是问题,那么是的,函数指针也一样好。附言用您留下的评论的解释更新了答案。
嘿,出差了,没时间看这个。我在哪里创建该结构?在我的学生班级内?
@d0zer,切换0次尝试相关的return true和return false。【参考方案2】:
听起来你的比较函数的第一行应该是
if (left.attempts_ == 0)
从那里检查是否还有right.attempts_ == 0
。如果是,请检查 ID。
如果没有,那么右边有一个档次,左边没有,右边更好。
继续执行其余规则。最终,您可以使用 if (left.attempts_ < right.attempts_)
之类的规则,但前提是您已经处理了 0 次尝试。
【讨论】:
我在您和 asQuirreL 的帮助下解决了这个问题。唯一的问题是,首先显示的是尝试次数为 0(最差指标)的学生。然后在那些尝试 0 次之后,排序是正确的。我怎样才能把那些尝试次数为 0 的人放在最后?以上是关于按多个值对向量进行排序的主要内容,如果未能解决你的问题,请参考以下文章