【问题标题】:Determining if std::sort(begin, end) modified the range确定 std::sort(begin, end) 是否修改了范围
【发布时间】:2011-02-06 22:06:03
【问题描述】:

确定对std::sort(begin, end) 的调用是否实际修改了范围的最优雅方法是什么?

这是我的两个想法:

(a) 检查是否已经排序 O(n):

if (already_sorted(begin, end)) { return false; }
std::sort(begin, end);
return true;

(b) 跟踪比较器的变化(这样安全吗?):

bool modified = false;
std::sort(begin, end, [&modified](T a, T b){ modified |= a<b; return a<b; });
return modified;

有没有更好的办法?

【问题讨论】:

  • 在我的脑海中,我不认为 (b) 是安全的:算法可以测试 comp(b, a) 而不是 comp(a, b),如果结果是 false 则交换。跨度>
  • 我认为一个更好的问题是为什么你需要知道范围是否已经排序——也许你应该选择一种排序算法,以“安​​全”的方式处理已经排序的范围,所以你不要'不必关心范围是否已排序?
  • @Jeff:我的应用程序有一个可能产生排序范围的过程。如果不是,则需要重复几个步骤。
  • (a) 的效率将取决于在您的上下文中数据通常是否已经排序。如果它通常是排序的,那么你已经完成了 O(N) 操作并为自己节省了 O(N log N)。但是,如果大部分数据还没有排序,那么你会不断地将 O(N) 添加到 O(N log N) 中,无论如何你总是这样做。在这种情况下,不检查直接排序可能是最有效的。特别是因为如果数据已经排序,我认为 std::sort 是 O(N) ......
  • (b) 对于典型的基于枢轴的排序方法肯定是错误的。在预先排序的范围内,他们会选择中间元素作为枢轴,并且 50% 的元素会小于枢轴。因此,对于包含 3 个或更多元素的预排序容器,至少与枢轴进行比较将设置为 modified

标签: c++ sorting stl std


【解决方案1】:

除非你从“开始”到“结束”遍历结构,否则你无法知道它是否已经排序,所以你能做到的最好是在 O(n) 中。

我会选择第一个,已经排序的。

【讨论】:

  • 注意:is_sorted(FwdIt begin, FwdIt end)的典型实现是return std::adjacent_find(begin, end, std::greater&lt;value_type&gt;()) == end;
【解决方案2】:

我认为你不能比 O(n) 检查数组返回的顺序是否与它开始时不同的顺序更好。如果不能保证顺序正常工作,则劫持比较器以查看是否有问题,因为理论上排序函数可以进行它喜欢的任何比较,而不必移动任何东西。此外,跟踪是否执行了任何交换并不一定会告诉您顺序是否发生了变化,因为排序还可以移动事物并在排序结束时将它们恢复到相同的顺序(例如,想想堆排序)。

【讨论】:

    【解决方案3】:

    如果交换两个相等的值,您是否考虑修改范围?在这种情况下, already_sorted 变体将不起作用。

    否则应该是最快的方式。

    【讨论】:

    • 嗯...我认为使用std::stable_sort 可以解决这个问题。
    【解决方案4】:

    如果要排序的对象属于类类型,您可以引入一个具有operator = 重载的子对象,该重载将由std::swap 调用。但是,如果对象被交换然后交换回来,理论上这仍然可能出现误报。

    您可能应该坚持使用already_sorted,直到您确定它会占用大量的总执行时间。

    【讨论】:

      猜你喜欢
      • 2012-12-04
      • 2020-10-14
      • 1970-01-01
      • 2012-10-16
      • 2010-09-10
      • 1970-01-01
      相关资源
      最近更新 更多