使用快速排序对可能包含无穷大的容器进行排序安全吗

Is it safe to sort a container which may contain infinities using quicksort?

本文关键字:排序 安全 无穷大 快速排序 包含      更新时间:2023-10-16

我已经意识到,为了使快速排序工作,所有的无穷大都必须相等。

换句话说,这样的标准是不够的:

class Entity
{
public: 
   float value() const;
   bool valueIsInfinite() const;
};
class Criterium
{
    bool operator()(Entity left, Entity right)const
    {
        if (left.valueIsInfinite())
            return false;
        return left.value() < right.value();
    }
}
const Criterium criterium;
QVector<Entity> container;
qSort<container.begin(), container .end(), criterium>

这种排序失败了,因为并不是所有的无穷大根据标准都是相等的。不相等性取决于实体输入运算符的顺序。我发现,这样的命令失败了。

我需要这样的东西:

class Criterium
{
    bool operator()(Entity left, Entity right)const
    {
        if (left.valueIsInfinite() && right.valueIsInfinite())
            return false;
        if (left.valueIsInfinite() && !right.valueIsInfinite())
            return false;
        if (!left.valueIsInfinite() && right.valueIsInfinite())
            return true;
        return left.value() < right.value();
    }
}

但假设不是

   float Entity::value() const;
   bool Entity::valueIsInfinite() const;

方法,我只想使用

   float Entity::value() const;

让它返回

std::numeric_limits<float>::infinity();

bool Entity::valueIsInfinite() const;

将返回true。

现在我测试了这种方法,它似乎有效。但我关心的是,无穷大可能以其他方式出现。例如:

float otherInfinity = exp(std::numeric_limits<float>::infinity());

这个无穷大似乎是一样的。但我想确定一下。我知道C++标准没有提到浮点运算实现的细节,但如果我使用gcc,它在所有情况下都安全吗?我的意思是,在gcc中,所有的无穷大都是相等的吗?对一个漂浮物容器进行分类安全吗?漂浮物容器可能包含在不同场合出现的无限量?

如果不存在NaNs,无穷大可以用正则运算符<:

  • +∞<+∞为false:<不可伸缩
  • 如果+∞<x为真,则x<+∞对于非无穷大值为假:<是反对称的
  • 如果+∞<x为真并且x<y为真,则+∞<y为真:<是可传递的
  • 如果+∞与x不可比(不小于,不大于),并且x与y不可比,则+∞与y不不可比:<显示等价的瞬态性

(类似性质对-∞有效)

给定这些属性,不带NaNs的浮点上的operator<是严格的弱排序,因此适用于标准库样式的排序操作。

然而,有了NaNs,反对称性就被打破了:NaN<1为假,并且1<NaN也是假的。您可以通过在所有非NaN之前或之后订购所有NaN来解决此问题,其方式类似于您提出的策略:

struct Criterion
{
    bool operator()(Entity left, Entity right)const
    {
        // NaNs come before non-NaNs
        if (isnan(left.value()) && isnan(right.value()))
            return false;
        if (!isnan(left.value()) && isnan(right.value()))
            return false;
        if (isnan(left.value()) && !isnan(right.value()))
            return true;
        return left.value() < right.value();
    }
}

isnan可以在C++11标准库中找到,或者很容易实现为return x != x;

由此,我们得到NaN<1为真,并且1<NaN为false,而其他属性仍然有效。

如果您使用这个:

bool operator()(Entity left, Entity right)const
{
    return !(left.valueIsInfinite() && right.valueIsInfinite())
        && left.value() < right.value();
}

那么不定式被认为是同一顺序的,因为没有一个在另一个之前。。。