使用 qsort() 进行稳定排序?

Using qsort() for stable sort?

本文关键字:排序 qsort 使用      更新时间:2023-10-16

我试图解决在线裁判系统中的问题: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 %dn", 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(错误答案)。有人可以给我一些线索吗?非常感谢!

在比较函数中的意图实际上没有错,使用原始排序将不稳定排序转换为稳定排序是一个完全有效的解决方案。

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

名称可能包含空格,这会搞砸您的输入法,但 (1) 测试描述似乎没有指示; (2)这将使输入更加困难,至少对于作业似乎针对的级别而言。

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

您可能应该满足这一点,因为您在比较函数中要遵循的一个规则是一致性,如果a > b,那么b < 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();
}
}

您甚至可能还想考虑放弃 legacy Cqsort,因为C++提供了内置的稳定排序,特别是<algorithm>中的stable_sort

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

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

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

class People{
public:
char name[11];
int grade;
int order;
void print(){
printf("%s %dn", 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的原因。

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