我假设stdlib中的旧的qsort函数不稳定,因为手册页没有说明任何内容。这是我正在谈论的功能:
#include <stdlib.h>
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *));
我假设如果我将比较函数更改为也包含我正在比较的地址,它将是稳定的。那是对的吗?
例如:
int compareFoos( const void* pA, const void *pB ) {
Foo *pFooA = (Foo*) pA;
Foo *pFooB = (Foo*) pB;
if( pFooA->id < pFooB->id ) {
return -1;
} else if( pFooA->id > pFooB->id ) {
return 1;
} else if( pA < pB ) {
return -1;
} else if( pB > pA ) {
return 1;
} else {
return 0;
}
}
答案 0 :(得分:29)
不,不幸的是你不能依赖它。假设您有数组(每个记录中的两个字段用于检查,但只有第一个字段用于排序):
BBBB,1
BBBB,2
AAAA,3
Quicksort可以比较BBBB,1与AAAA,3并交换它们,给出:
AAAA,3
BBBB,2
BBBB,1
如果下一步是将BBBB,2与BBBB,1进行比较,则密钥将相同,并且由于BBBB,2的地址小于BBBB,1,因此不会进行交换。为了获得稳定的排序,您应该最终得到:
AAAA,3
BBBB,1
BBBB,2
唯一的方法是附加指针的起始地址(不是它的当前地址),并使用它和其他键进行排序。这样,原始地址就成为排序键的次要部分,因此BBBB,1
最终会在BBBB,2
之前结束,无论在排序过程中两条BBBB
行的位置如何。
答案 1 :(得分:7)
规范解决方案是使用额外的间接级别并回退到比较来制作(即分配内存并填充)指向原始数组元素的指针数组,并qsort
这个新数组当指向的东西相等时,指针值。这种方法有潜在的附带好处,你根本不修改原始数组 - 但是如果你想在最后对原始数组进行排序,你必须置换它以匹配指针数组中的顺序。 qsort
返回。
答案 2 :(得分:0)
这不起作用,因为在排序过程中,排序将发生变化,两个元素将不具有一致的输出。我做的很好的老式qsort稳定是在我的struct中添加初始索引并在将它传递给qsort之前初始化该值。
typedef struct __bundle {
data_t some_data;
int sort_score;
size_t init_idx;
} bundle_t;
/*
.
.
.
.
*/
int bundle_cmp(void *ptr1, void *ptr2) {
bundle_t *b1, *b2;
b1 = (budnel_t *) ptr1;
b2 = (budnel_t *) ptr2;
if (b1->sort_score < b2->sort_score) {
return -1;
}
if (b1->sort_score > b2->sort_score) {
return 1;
}
if (b1->init_idx < b2->init_idx) {
return -1;
}
if (b1->init_idx > b2->init_idx) {
return 1;
}
return 0;
}
void sort_bundle_arr(bundle_t *b, size_t sz) {
size_t i;
for (i = 0; i < sz; i++) {
b[i]->init_idx = i;
}
qsort(b, sz, sizeof(bundle_t), bundle_cmp);
}