C++ 对于较大的输入大小,按0到100之间的键对对象进行排序的高效算法

C++ 对于较大的输入大小,按0到100之间的键对对象进行排序的高效算法,c++,algorithm,sorting,C++,Algorithm,Sorting,我有以下代表学生信息的课程: struct Student { std::string name; int id = 0; short rank = 0; }; “评分”字段可以是0到100之间的任意数字。 我需要实现以下按降序排列学生的功能: void fast_sort(std::vector<Student>& students) { // TODO: } void快速排序(std::vector和students) { //待办事项:

我有以下代表学生信息的课程:

struct Student
{
    std::string name;
    int id = 0;
    short rank = 0;
};
“评分”字段可以是
0
100
之间的任意数字。 我需要实现以下按降序排列学生的功能:

void fast_sort(std::vector<Student>& students)
{
  // TODO:
}
void快速排序(std::vector和students)
{
//待办事项:
}
我能在适当的地方做这种事吗?对于大尺寸输入,最有效的方法是什么

我已经试着计算每个等级的学生人数:

std::map<short, int> counter;
for(size_t i = 0; i < students.size(); ++i)
{
    short rank = students[i].rank;
    ++counter[rank];
}
std::map计数器;
对于(size_t i=0;i

现在,我正在考虑如何在不使用额外的
std::vector

的情况下将学生放在正确的位置,
std::sort
可能对您有用,因为它允许使用用户定义的比较函数,如以下示例所示:

//排序算法示例
#include//std::sort
#include//std::vector
#包括“Student.h”//您学生的班级标题
bool-myfunction(constudent&x,constudent&y){

return(x.getRating()您几乎自己解决了这个问题,对计数代码做了一点更改

(完全未经测试的代码)

std::map计数器;
对于(size_t i=0;i

std::数组计数器;
对于(size_t i=0;i
其中values是连续不同值0..values-1的数量

然后使用计数排序(基数排序的基础)< /P>

std::array pos={0};
std::部分和(counter.begin(),std::prev(counter.end()),std::next(pos.begin());
现在你有了每个等级的起点

std::向量螺柱;
对于(int i=螺柱.size();i<螺柱.end();++i){
int=pos[studs[i].rank];
while(通缉!=i){
pos[studs[i].秩]++;
交换(螺柱[i],螺柱[需要]);
通缉犯=职位[钉[i].等级];
}
}
计数排序
  • 统计每个级别的学生人数
  • 使用累积计数查找每个级别的第一个学生的索引
  • 将学生放在第一个可用的排名索引中
  • 这三个步骤中的每一步都具有复杂性O(n+k),其中n是学生数量,k是等级数量

    我将展示一个有10名学生的例子,排名从0到2,而不是从0到100

    # define NBSTUDENTS 10
    # define NBRANKS 3
    
    struct Student students[NBSTUDENTS] =
      {("Alice", 0),  ("Bob", 2),     ("Charlie", 1), ("Daenerys", 1), ("Eleonore", 2),
       ("Farouk", 1), ("Gabriel", 0), ("Hector", 1),  ("Iris", 2),     ("Julien", 2)};
    
  • 计算每个等级的学生人数
  • 使用累积计数查找每个级别的第一个学生的索引
  • 您可以使用获取累积计数;请参阅

  • 将学生放在第一个可用的排名索引中
  • struct Student sorted_students[NBSTUDENTS]={}
    for(自动学生=学生.begin();学生<学生.end();++student)
    {
    已排序的学生[可用的学生索引[学生->排名]]=*学生;
    可用_索引[学生->排名]++;
    }
    
    std::sort

    std::sort
    的复杂度是O(n log(n))。上面的计数排序的复杂度是O(n+k)。这些O()符号隐藏了一个常数;您可以预期经过良好优化的
    std::sort
    的常数比自定义实现的排序小得多。当n趋于无穷大时,log(n)也趋于无穷大。但是对数增长非常缓慢。你的大尺寸输入有多大?我假设你的学生不到一百万。1000000的二进制对数是20。如果我们假设n<1000000,那么n log(n)<20 n.我们的自定义计数排序真的比
    std::sort
    快吗?

    计数排序..你不允许使用std::sort?计数排序。如果
    评级
    (显然,又称为
    等级
    ),你就是在攻击自己的脚效率。)域实际上是1..100。如果没有受限制的域(当然不是那么小的域),映射将更有意义,而且此时
    std::sort
    将是您的最佳选择。请在问题中澄清,您正在寻找比
    std::sort
    更好的映射(因为它是高效的)注意,即使a
    O(N)
    对于相当小的输入大小,排序不一定比
    std::sort
    快。您是否真的尝试过
    std::sort
    ,并且有证据表明它花费了太多的时间?您知道,现在您得到的答案对您提出的问题来说很好,但对您真正想提出的问题来说却不是;)这个问题并不清楚,但OP正在寻找比
    std::sort
    更好的方法。注意
    std::sort
    在一般情况下非常有效,但是当输入范围有限时,就会有复杂度更低的算法可用。无论如何,我投了你一票,因为
    std::sort
    是有效的;)我想一想这样使用
    std::partial_sum
    会得到一个偏移结果;也就是说,它会将
    {2,4,3,3}
    转换为
    {2,6,9,12}
    ,但是你想要的是
    {0,2,6,9}
    @stef是的,这是正确的,我马上就会找到正确的代码。
    int count_per_rank[NBRANKS] = {2, 4, 4};
    
    int available_index[NBRANKS] = {0, 0+2, 0+2+4};