【问题标题】:Using qsort() for stable sort?使用 qsort() 进行稳定排序?
【发布时间】:2018-01-07 08:04:30
【问题描述】:

我正在尝试解决在线法官系统中的一个问题:https://acm.cs.nthu.edu.tw/problem/11519/ 它需要一个整数 n,后跟 n 行名称和等级。 问题是使用稳定的排序算法按等级对它们进行排序。 我使用 qsort() 并在 compar() 中给出人的顺序来稳定 qsort()。这是我的代码:

class People{
    public:
        char name[11];
        int grade;
        int order;
        void print(){ printf("%s %d\n", name, grade); }
};

int compar(const void *a, const void *b){
    People *A = (People*)a;
    People *B = (People*)b;
    if(A->grade > B->grade) return 1;
    else if(A->grade < B->grade) return -1;
    else if(A->order > B->order) return 1;
    else if(A->order < B->order) return -1;
}

int main(){
    int n;
    scanf("%d", &n);
    People *p = new People[n];
    for(int i=0;i<n;i++){
        scanf("%s %d", p[i].name, &p[i].grade);
        p[i].order = i;
    }
    qsort(p, n, sizeof(People), compar);
    for(int i=0;i<n;i++){
        p[i].print();
    }
}

在我所有的测试用例中,它都没有任何问题,但是在线法官一直给我提交的四个 WA(错误答案)。有人可以给我一些关于这个的线索吗?非常感谢!

【问题讨论】:

  • 如果你想要一个稳定的排序,C++ 标准库称之为std::stable_sort
  • @StoryTeller 但我使用变量“order”使其稳定。如果成绩相同,compar() 会比较唯一的顺序来决定顺序。
  • @Patricius 你不能用这个方法控制,qsort 不稳定,周期。
  • 您不知道qsort 在所有标准库版本中的实现。您添加的支票可能会破坏它的保证。另外还有你的比较函数缺少返回语句的问题。只需为您的项目编写适当的严格弱排序,然后使用std::stable_sort
  • 叹息。是的,qsort 不稳定:它不保证比较相等 的元素的相对顺序。这并不意味着这种方法行不通:显式地对本来会比较相等的元素进行排序就可以了,因为它们不再比较相等qsort 不是这里的反派。我怀疑一个愚蠢的评分算法说qsort是错误的答案。

标签: c++ algorithm sorting


【解决方案1】:

其实你的 intent 在比较函数中没有什么问题,使用原始排序将不稳定排序变成稳定排序是一个完全有效的解决方案。

那么,为什么它会被拒绝,我无法确定,至少在无法访问正在使用的测试数据的情况下。

可能名称可能包含空格,这会搞砸您的输入法,但 (1) 测试描述似乎没有说明; (2) 这会使输入变得更加困难,至少对于作业的目标水平而言。

但是,尽管您可能认为这不太可能,但 排序算法可能会在某些时候将对象与自身进行比较。这意味着它将返回一些任意值,因为您假设它们总是不同的,因为添加了order 检查。

您可能应该满足这一点,因为您在比较函数中要遵循的一个规则是一致性,如果 a &gt; bb &lt; a。所以,两个规则,真的:-)

此外,我建议的一件事是尽量减少使用遗留 C 的东西,如 printfscanf,因为 C++ 提供了更好的设施。

为此,我相信你会更好:

#include <iostream>
#include <cstdlib>

struct People {
    char name[11];
    int grade;
    int order;
    void print() { std::cout << name << " " << grade << std::endl; }
};

int compar(const void *a, const void *b) {
    People *A = (People*)a;
    People *B = (People*)b;

    // Use grade if different.

    if (A->grade > B->grade) return 1;
    if (A->grade < B->grade) return -1;

    // Otherwise, use order, unique in different objects.

    if (A->order > B->order) return 1;
    if (A->order < B->order) return -1;

    // But cater for the possibility you may compare an object with itself.

    return 0;
}

int main() {
    int n;
    std::cin >> n;

    People *p = new People[n];

    for (int i = 0; i < n; i++) {
        std::cin >> p[i].name >> p[i].grade;
        p[i].order = i;
    }

    qsort(p, n, sizeof(People), compar);

    for (int i = 0; i < n; i++) {
        p[i].print();
    }
}

您甚至可能还想考虑放弃旧版-C qsort,因为 C++ 提供了内置的稳定排序,特别是 &lt;algorithm&gt; 中的 stable_sort

【讨论】:

  • 实际上我已经用 vector 和 std::stable_sort 重写了代码,但仍然被拒绝。我可能会尝试用适当的空间处理来重写它。谢谢!
【解决方案2】:

最后我错过了描述中的一行:

输入包括多个测试用例。在每个测试用例中,第一行包含一个整数 N。

经过几种方法,我通过以下代码通过了:

class People{
    public:
        char name[11];
        int grade;
        int order;
        void print(){
            printf("%s %d\n", name, grade);
        }
};

int compar(const void *a, const void *b){
    People *A = (People*)a;
    People *B = (People*)b;
    if(A->grade > B->grade) return 1;
    else if(A->grade < B->grade) return -1;
    else if(A->order > B->order) return 1;
    else if(A->order < B->order) return -1;
    return 0;
}

int main(){
    int n;
    while(scanf("%d", &n)!=EOF){
        People *p = new People[n];
        for(int i=0;i<n;i++){
            scanf("%s %d", p[i].name, &p[i].grade);
            p[i].order = i;
        }
        qsort(p, n, sizeof(People), compar);
        for(int i=0;i<n;i++){
            p[i].print();
        }
        delete[] p;
    }
}

std::stable_sort 正常工作,但是,它收到了 TLE(超出时间限制),并且 cin/cout 也会导致 TLE。所以这就是我坚持使用 printf/scanf 的原因。

感谢大家回答这个问题! :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-12
    • 2010-10-21
    • 2019-05-23
    • 2021-12-31
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多