C ++ qsort是否曾将元素与自身进行比较?

时间:2018-02-21 07:30:07

标签: c++ qsort

我需要用qsort稳定排序数组。为了确保结果稳定,我在比较函数中添加了一个额外的条件:

int compare(const void *p1, const void *p2)
{
    if(*(const Data*)p1 < *(const Data*)p2)
        return -1;
    if(*(const Data*)p2 < *(const Data*)p1)
        return 1;
    else
        return p1<p2 ? -1 : 1;
}

如果qsort从不调用compare(p,p),这将有效。否则我需要使用更复杂的条件。问题是,qsort是否曾经使用重复指针调用compare(),还是总是比较不同的指针?

更新:

我使用Ideone C ++编译器检查了这个:https://ideone.com/l026kM

对于注释中的小例子{8,8,1,1},提供的qsort()实现不会改变指针的顺序,也不会为同一元素调用compare。这似乎是合理的,因为每次反向交换都会影响性能,因为它需要稍后进行交换。我将使用随机生成的数组和不同的编译器来测试它。

更新:

在Ideone上测试了100000个随机数组,重复键的份额至少为80%。结果是100%稳定的排序数组。这是链接:https://ideone.com/KOYbgJ

VC ++ Express 2008编译器失败稳定排序,因为指针的顺序已更改。这基本上说明了VC ++实现与GCC实现的不同之处在于它不保持指针顺序。

2 个答案:

答案 0 :(得分:6)

隐式允许任何未明确禁止的内容;特别是,我记得调试版本中的VC ++在实际执行std::sort之前,在相同的元素(以及其他健全性测试)中明确地测试了比较器。不知道它是否与qsort相同,但允许它。

但最重要的是,您的比较器违反了qsort规定的要求;特别是:

  

当相同的对象(由size个字节组成, 而不管它们在数组中的当前位置 )被多次传递给比较函数时,结果应相互一致。也就是说,对于qsort,他们应该在数组上定义一个总排序,对于bsearch,同一个对象应始终以相同的方式与密钥进行比较。

(C99,§7.20.5¶4,重点补充)

最后,正如 Daniel Langr 已经概述的那样,即使采用“原谅”的实施方式,这也不一定能达到你所追求的目标。

这就是说:扔掉这个kludge并使用一个真正稳定的排序算法,该库已经提供了它(std::stable_sort)。

此外,由于std::stable_sort避免赋值运算符,因此这件事的重点似乎是std::sortqsort更快的排序:

  对于便宜的比较器,BTW qsort通常比std::sort慢,因为它需要间接调用每个比较,而在std::sort中,函数内联。   并且复制通常也较慢,因为std::sort必须使用memcpy(必须调用然后在运行时确定大小并相应地复制),同时内联赋值被内联(所以再次,如果你的元素很小,它会更便宜,否则,因为合成的分配类型的复制赋值/副本通常归结为memcpy

chat link

答案 1 :(得分:5)

  

如果qsort从不调用compare(p,p),这将有效。

不,这不能确保快速排序的稳定性。如果这样做会很好:)

考虑(8,8,1,1)相对于枢轴5的划分。首先,外部8与外部1交换,然后内部8与内部1交换.1和8s的顺序在之后改变分区时没有比较具有相同键的元素。

可以更明确地写出如下:

partition(8_left, 8_right, 1_left, 1_right) -> (1_right, 1_left, 8_right, 8_left)