按降序对矢量进行排序

fre*_*low 296 c++ sorting iterator stl vector

我应该用吗?

std::sort(numbers.begin(), numbers.end(), std::greater<int>());
Run Code Online (Sandbox Code Playgroud)

要么

std::sort(numbers.rbegin(), numbers.rend());   // note: reverse iterators
Run Code Online (Sandbox Code Playgroud)

按降序对矢量进行排序?一种方法或另一种方法有任何好处或缺点吗?

Meh*_*dad 110

实际上,第一个是个坏主意.使用第二个,或者:

struct greater
{
    template<class T>
    bool operator()(T const &a, T const &b) const { return a > b; }
};

std::sort(numbers.begin(), numbers.end(), greater());
Run Code Online (Sandbox Code Playgroud)

这样,当有人决定numbers应该持有longlong long代替时,你的代码不会默默地破坏int.

  • 提及N3421的链接,你得到我的upvote;) (9认同)
  • 为什么不只是`std :: greater <typename decltype(numbers):: value_type>()`或者什么? (6认同)
  • 这个答案已经过时了 - 从 C++14 开始,你可以使用 `std::greater&lt;&gt;()`。 (6认同)
  • FWIW:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3421.htm (4认同)
  • @FredOverflow:您在评论中获得了荣誉;) (2认同)
  • 或坚持第一个.使用typedef作为numberContainer - 一个好主意,这样有人可以换成long long - 并写:std :: sort(numbers.begin(),numbers.end(),std :: greater <numContainer :: value_type>( )); (2认同)

Pub*_*bby 68

使用第一个:

std::sort(numbers.begin(), numbers.end(), std::greater<int>());
Run Code Online (Sandbox Code Playgroud)

这是明确的是怎么回事的-误读的机会较少rbeginbegin,甚至有评论.它清晰可读,正是您想要的.

此外,第二个可能效率低于第一个给定反向迭代器的性质,尽管你必须对其进行分析以确定.


小智 61

使用c ++ 14,您可以这样做:

std::sort(numbers.begin(), numbers.end(), std::greater<>());
Run Code Online (Sandbox Code Playgroud)

  • C++17 `std::sort(numbers.begin(), Numbers.end(), std::greater{});` C++20 `std::ranges::sort(numbers, std::ranges) ::更大());` (20认同)

sho*_*hin 26

那这个呢?

std::sort(numbers.begin(), numbers.end());
std::reverse(numbers.begin(), numbers.end());
Run Code Online (Sandbox Code Playgroud)

  • @greg O(n*log(n))= O(n*log(n)+ n).它们是定义同一组的两种方式.你的意思是说"这可能会慢一点". (29认同)
  • 原因可能是避免额外的复杂性:O(n*log(n))+ O(n)vs O(n*log(n)) (11认同)
  • @pjvandehaar格雷格很好.他明确没有说,O(n*log(n)+ n),他说O(n*log(n))+ O(n).你的措辞不明确是对的(尤其是他滥用复杂词这个词),但你可以用更好的方式回答.例如:也许您打算使用"计算"​​一词而不是"复杂性"这个词.反转这些数字是对其他方面相同的O(n*log(n))步骤的不必要的O(n)步骤. (4认同)
  • @OfekGila我的理解是big-O表示法是关于函数集的,涉及`=`和`+`的表示法只是方便的意思,意思是`∈`和`∪`。在这种情况下,O(n * log(n))+ O(n)是O(n * log(n))∪O(n)的简便表示法,与O(n)相同* log(n))`。“计算”一词是一个很好的建议,您对音调是正确的。 (3认同)

Jul*_*rcq 21

您可以使用Lambda函数代替Mehrdad提出的仿函数.

sort(numbers.begin(), numbers.end(), [](const int a, const int b) {return a > b; });
Run Code Online (Sandbox Code Playgroud)


zw3*_*324 16

根据我的机器,long long使用第一种方法对[1..3000000] 的矢量进行排序大约需要4秒,而使用第二种方法需要大约两倍的时间.显然,这说了些什么,但我也不明白为什么.试想这会有所帮助.

同样的事情这报道.

正如Xeo所说,-O3他们几乎用同一时间完成.

  • 您是否可能只是在打开优化的情况下进行编译?听起来非常像`reverse_iterator`操作没有内联,并且鉴于它们只是实际迭代器的包装器,难怪它们在没有内联的情况下花费了两倍的时间. (12认同)
  • @Xeo:我把它拿回来; 标准实际上是_mandates_,`std :: vector <> :: reverse_iterator`是用`std :: reverse_iterator <>`实现的.奇怪的; 今天我学到了 :-P (3认同)

ras*_*dcs 11

第一种方法是:

    std::sort(numbers.begin(), numbers.end(), std::greater<>());
Run Code Online (Sandbox Code Playgroud)

您可以使用第一种方法,因为它比第二种方法获得更高的效率.
第一种方法的时间复杂度小于第二种方法.

  • 这与 mrexciting 的答案相同。关于复杂性的评论我也不清楚。 (3认同)

小智 7

bool comp(int i, int j) { return i > j; }
sort(numbers.begin(), numbers.end(), comp);
Run Code Online (Sandbox Code Playgroud)

  • 要获得有效答案,您应该考虑写一些关于OP提及方法的优点/缺点的信息 (4认同)

Kri*_*not 6

您可以使用第一个或尝试下面的代码,它同样有效

sort(&a[0], &a[n], greater<int>());
Run Code Online (Sandbox Code Playgroud)


iva*_*ult 6

TL; 博士

使用任何。它们几乎相同。

无聊的回答

像往常一样,有利有弊。

使用std::reverse_iterator

  • 当您对自定义类型进行排序并且不想实现时 operator>()
  • 当你懒得打字时 std::greater<int>()

std::greater在以下情况下使用:

  • 当您想要更明确的代码时
  • 当你想避免使用晦涩的反向迭代器时

至于性能,这两种方法同样有效。我尝试了以下基准测试:

#include <algorithm>
#include <chrono>
#include <iostream>
#include <fstream>
#include <vector>

using namespace std::chrono;

/* 64 Megabytes. */
#define VECTOR_SIZE (((1 << 20) * 64) / sizeof(int))
/* Number of elements to sort. */
#define SORT_SIZE 100000

int main(int argc, char **argv) {
    std::vector<int> vec;
    vec.resize(VECTOR_SIZE);

    /* We generate more data here, so the first SORT_SIZE elements are evicted
       from the cache. */
    std::ifstream urandom("/dev/urandom", std::ios::in | std::ifstream::binary);
    urandom.read((char*)vec.data(), vec.size() * sizeof(int));
    urandom.close();

    auto start = steady_clock::now();
#if USE_REVERSE_ITER
    auto it_rbegin = vec.rend() - SORT_SIZE;
    std::sort(it_rbegin, vec.rend());
#else
    auto it_end = vec.begin() + SORT_SIZE;
    std::sort(vec.begin(), it_end, std::greater<int>());
#endif
    auto stop = steady_clock::now();

    std::cout << "Sorting time: "
          << duration_cast<microseconds>(stop - start).count()
          << "us" << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用此命令行:

g++ -g -DUSE_REVERSE_ITER=0 -std=c++11 -O3 main.cpp \
    && valgrind --cachegrind-out-file=cachegrind.out --tool=cachegrind ./a.out \
    && cg_annotate cachegrind.out
g++ -g -DUSE_REVERSE_ITER=1 -std=c++11 -O3 main.cpp \
    && valgrind --cachegrind-out-file=cachegrind.out --tool=cachegrind ./a.out \
    && cg_annotate cachegrind.out
Run Code Online (Sandbox Code Playgroud)

std::greater demo std::reverse_iterator demo

时间是一样的。Valgrind 报告相同数量的缓存未命中。