直接从qsort手册中说:
如果两个成员比较为相等,则它们在已排序数组中的顺序未定义。
但是,我希望qsort在相等的情况下保持排序不变。也就是说,如果两个元素具有用于排序的相同值,则保持它们在原始数组中的排序。
我不确定如何使用qsort来做到这一点。我宁愿不使用其他的排序库,也不愿意使用我自己的。
感谢,
编辑:现在我知道稳定和不稳定排序之间的区别了,我意识到这是一个重复。
你实际上是在问如何在不稳定排序的基础上实现稳定排序。
你能做的不多:你只能控制比较函数,所以你必须在这方面下功夫。
一种可能是为数组中每个元素附加第二个键ID,该键ID对应于该元素的原始索引。然后,如果两个元素比较相等,则根据它们的原始索引返回相应的顺序。
正如GNU libc手册所解释的,
使用qsort执行稳定排序的唯一方法是首先用某种单调计数器增加对象。
所以除非你可以修改你的比较函数,使你当前认为"相等"的对象可以被区分,否则你必须在排序之前显式地用索引注释你的对象,并在完成后删除索引。你可以用
struct indexed {
void *obj;
int index;
}
qsort
代表"Quick Sort",是一种快速但不稳定的排序算法。假设按升序排序。在这种情况下,如果排序算法不交换具有相同键的元素,则称为稳定。如果它可以交换键值相等的元素,那么它是不稳定的。
你的问题有不同的解决方案;我在这里推荐两种。
解决方案1
你可以在维基百科上找到一些有趣的关于排序算法的稳定性,包括在实际需要稳定算法时使用不稳定算法的方法:例如,如果您使用整数值排序,则扩展排序键。
假设你正在排序一个整数数组。相反,您创建一个包含两个元素的结构:第一个(KEY
)是您的整数。第二个(AUX_KEY
)是一个唯一的索引。在排序之前,您可以线性设置AUX_KEY
以反映原始顺序。当排序时,传递给qsort
一个函数,该函数将使用KEY
排序,但如果两个键相等,将恢复使用AUX_KEY
。
解决方案2
不要使用快速排序,使用像归并排序这样的稳定算法,你可能在你的编程环境中有(例如,这里有FreeBSD归并排序的管理页;在其他编程环境中也可以使用相同的名称(请检查),或者,如果您不太需要速度,可以使用插入排序(您可以自己编写代码—只需在伪代码中使用几行代码)。插入排序的时间复杂度为二次(与n^2成正比),而归并排序和快速排序的时间复杂度为O(n log(n))。
qsort在这里告诉你的是,他的算法不允许它保证两个相等成员的最终排序顺序。
你能做的是实现/使用另一种算法,或者强迫它们按原来的方式排序:
- 如果你的比较函数应该返回相等,看看它们最初是如何排序的,并以相同的方式排序。