【问题标题】:Sort vector by multiple values按多个值对向量进行排序
【发布时间】:2014-01-20 00:53:00
【问题描述】:

我必须对向量进行排序。该向量包含指向“学生”类对象的指针。

评分指标如下所示:

  1. 最好的最终成绩
  2. 如果最终成绩相同,则尝试次数更少
  3. 如果相同的尝试,更少的 id
  4. 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 打破。

标签: c++ sorting vector


【解决方案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:比较不需要存储任何状态,所以一个独立的函数非常好,更容易。我也不会使用这个答案显示的巨大的|| == &amp;&amp; 链。但是 asQuirrel 给了你一个很大的线索。
  • @d0zer 根据是否经常使用比较器,函数对象比函数指针更便于内联。如果这不是问题,那么是的,函数指针也一样好。附言用您留下的评论的解释更新了答案。
  • 嘿,出差了,没时间看这个。我在哪里创建该结构?在我的学生班级内?
  • @d0zer,切换0次尝试相关的return true和return false。
【解决方案2】:

听起来你的比较函数的第一行应该是

if (left.attempts_ == 0)

从那里检查是否还有right.attempts_ == 0。如果是,请检查 ID。

如果没有,那么右边有一个档次,左边没有,右边更好。

继续执行其余规则。最终,您可以使用 if (left.attempts_ &lt; right.attempts_) 之类的规则,但前提是您已经处理了 0 次尝试。

【讨论】:

  • 我在您和 asQuirreL 的帮助下解决了这个问题。唯一的问题是,首先显示的是尝试次数为 0(最差指标)的学生。然后在那些尝试 0 次之后,排序是正确的。我怎样才能把那些尝试次数为 0 的人放在最后?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-15
  • 2012-02-19
  • 1970-01-01
  • 2023-02-05
  • 2021-12-22
相关资源
最近更新 更多