【问题标题】:Would it be legal to implement overloads of std::sort with radix sort?使用基数排序实现 std::sort 的重载是否合法?
【发布时间】:2016-01-03 04:26:50
【问题描述】:

对于适用的数据类型,良好的基数排序可以大大击败比较排序,但 std::sort 通常实现为 introsort。是否有理由不使用基数排序来实现std::sort?基数排序不足以实现std::sort,因为std::sort 只要求类型是可比较的,但对于比较和基于基数的排序产生相同答案的类型(例如int),这似乎是一个容易实现的目标未采摘。

在适当的时候使用基数排序的重载实现std::sort 是否合法? std::sort 的要求是否从根本上阻止了这种情况?

编辑:我应该更清楚一点。我在问标准库的实现是否合法。我不是在询问标准库实现的用户在std 命名空间中放置任何东西。我知道这样做是非法的,除非在特定情况下。

【问题讨论】:

  • 虽然你可以重载 std::sort,但你真的想弄乱标准命名空间吗?最好实现一个排序函数,在必要时调用 std::sort。
  • @DavidHaim 嗯?如果我正在实现 C++ 标准库,我会要求弄乱标准命名空间。
  • 如果您谈论标准库实现,那么一切都会发生。 'as-if' 规则适用。
  • @zch 这就是问题所在!基数排序能否满足std::sort 的“假设”规则?
  • 我认为你可以做到。不过std::stable_sort 是另一回事,因为它引入了平等的概念。

标签: c++ sorting language-lawyer standard-library


【解决方案1】:

cmets 引用“as-if”规则。这实际上是没有必要的。 std::sort 没有被指定为“好像使用了 introsort”。 std::sort 的规范很简短,只需要比较次数的效果(排序)和复杂度(O(N log N))。基数排序满足两者。

25.4.1.1 排序

template<class RandomAccessIterator> void sort(RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare> void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);

1 效果:对[first,last)范围内的元素进行排序。

2 要求:RandomAccessIterator 应满足 ValueSwappable (17.6.3.2) 的要求。 *first 的类型应满足 MoveConstructible(表 20)和 MoveAssignable(表 22)的要求。

3 复杂度:O(N log(N ))(其中 N == last - first)比较。

实际上,比较两个寄存器宽度值a&lt;b 比提取数字并比较这些数字的序列要快得多,即使我们使用位或十六进制数字也是如此。当然,这是一个常数因子差异,但提取和比较 32 个单独的位将比直接比较慢 100 倍左右。这超过了大多数理论上的担忧,尤其是因为log N 在当今的计算机上实际上不可能是 100。

【讨论】:

  • zch 在 cmets 中提出了一个很好的观点——基数排序可能需要动态分配内存。这有关系吗?
  • @Praxeolitic:不,标准没有提到这一点。实际上,大多数排序算法确实需要内存,但通常是从堆栈中获取的。
  • (Tangential nitpick - 面向性能的基数排序一次比较超过 1 位。自然,1 字节是一个不错的选择。)
  • @Praxeolitic:我假设 4 位(“十六进制数字”),但 8 位也可以。
  • 在某些环境中,在堆栈上分配大数组是不可能的,但 8 位基数应该适用于大多数情况。更大的基数可能需要堆分配,然后需要处理分配失败的情况。一些标准库算法明确允许在内存不足的情况下降低性能。
猜你喜欢
  • 2011-06-29
  • 2012-05-26
  • 2012-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多