【问题标题】:Is it safe to sort a container which may contain infinities using quicksort?使用快速排序对可能包含无穷大的容器进行排序是否安全?
【发布时间】:2012-07-25 01:51:15
【问题描述】:

我已经意识到,为了使快速排序起作用,所有的无穷大都需要相等。

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

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 中创建的所有无穷大都是平等的吗?对可能包含在不同场合出现的无穷大的浮动容器进行分类是否安全?

【问题讨论】:

  • 所有的无穷大都是平等的,但有些比其他的更平等。

标签: c++ algorithm qt sorting gcc


【解决方案1】:

在没有 NaN 的情况下,正则运算符 &lt; 可以使用无穷大:

  • +∞ < 是不自反的;
  • 如果 +∞ < 反对称;
  • 如果 +∞ < 是可传递的;
  • 如果 +∞ 与 x 不可比(不小于,不大于),并且 x 与 y 不可比,则 +∞ 与 y 不可比:&lt; 显示等价传递性。

(类似的性质对-∞有效)

考虑到浮点数上的那些属性operator&lt;没有 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

【讨论】:

    【解决方案2】:

    如果你使用这个:

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

    然后无限被认为是相同的顺序,因为没有一个在另一个之前......

    【讨论】:

    • 谢谢,但这不是我问的。我想完全消除 valueIsInfinite() 方法
    猜你喜欢
    • 2010-11-03
    • 1970-01-01
    • 2019-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-13
    • 1970-01-01
    相关资源
    最近更新 更多