【问题标题】:why do std::sort and partial_sort require random-access iterators?为什么 std::sort 和 partial_sort 需要随机访问迭代器?
【发布时间】:2014-07-18 04:32:56
【问题描述】:

我想知道为什么 c++ 标准要求 std::sort 只应采用随机访问迭代器?我看不出有什么优势,因为std::sortstd::list::sort 的复杂度都是N*log(N)。将std::sort 限制为随机访问迭代器 (RAI) 似乎使得有必要为具有相同复杂性的列表编写单独的函数。

这同样适用于partial_sort,直到今天,列表is simply missing 的非RAI 对应部分。

这种设计是不是因为人们过去使用quick_sort 的变体来实现std::sort

如果在 RAI 容器上编写排序算法有优势,是否让std::sort 更通用,让像std::vector 这样的 RAI 容器提供专门的v.sort

【问题讨论】:

  • 你说人们使用快速排序来“历史地”实现 std::sort。您认为他们今天使用什么?
  • @JohnZwinck 他们今天不能使用(未修改的)快速排序。 C++11 标准要求 std::sort 在所有情况下都是 O(N log N),快速排序是 O(N^2) 最坏的情况。
  • @JohnZwinck:你确定在 C++ 中 O(N log N)O(N^2) 不同吗?请注意,在 C++ 中,N 有一个上限。
  • @6502:你的意思是SIZE_MAX?按照这个逻辑,所有算法(停止)都是 O(1)。但这不是描述复杂性的非常有用的方式。
  • @6502 原则上您是对的,但我们大多数人默认只计算渐近行为,直到渐近线超出图形并趋向无穷大之前的某一点。显式多项式基本上没有什么不同。系数被加回,但它们仅在一定程度上有效。如果您真的要为现实世界的软件构建模型,您将考虑内存缓存效应和其他任何因素 - 使用经验测量和分析作为基础,而不是抽象数学。

标签: c++ sorting complexity-theory c++-standard-library


【解决方案1】:

O(N*log(N)) 复杂性并不意味着容器按顺序迭代,也不意味着对它的更改仅按扫描顺序进行。使用顺序迭代器需要O(N) 内存成本来存储所有这些迭代器。

【讨论】:

    【解决方案2】:

    算法复杂性并不能说明一切。实际上在 C++ 中(从正式的角度来看)它什么也没说,因为你不能将 N 增长到无穷大(size_t 不是任意精度数)因此用 C++ 编写的每个排序算法(正式)也是O(1).

    从实际的角度来看,std::sortqsort 的孙子,它很可能是作为快速排序的一种变体实现的。

    对数组使用合并排序将需要与数组大小成比例的额外存储空间(指向下一个元素的链接),而对列表使用合并排序不需要任何额外空间,因为您可以重用节点中已经存在的链接(无论如何它都会被排序销毁)。

    在不知道您正在处理哪种容器的情况下进行编程的想法主要是一种错觉,因此使用两种不同的显式方法来有效地对两种不同类型的容器进行排序本身并不被认为是坏事。

    std::sort 不包含列表迭代器的特化确实很烦人(我不是模板元编程专家,但它看起来很简单)。

    【讨论】:

    • “恼人的是 std::sort 不包含列表迭代器的特化”——除此之外,这可以让您对 list 的子范围进行排序,其中 @987654329 @ 不允许直接使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-19
    • 2022-11-14
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 2011-07-19
    • 1970-01-01
    相关资源
    最近更新 更多