按降序对向量进行排序

问题描述 投票:0回答:12

我应该使用

std::sort(numbers.begin(), numbers.end(), std::greater<int>());

std::sort(numbers.rbegin(), numbers.rend());   // note: reverse iterators

按降序对向量进行排序?一种方法或另一种方法有什么优点或缺点吗?

c++ sorting stl vector iterator
12个回答
146
投票

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

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

std::sort(numbers.begin(), numbers.end(), greater());

这样,当有人决定

numbers
应该保留
long
long long
而不是
int
时,你的代码就不会默默地崩溃。


140
投票

使用 c++14 你可以这样做:

std::sort(numbers.begin(), numbers.end(), std::greater<>());

80
投票

使用第一个:

std::sort(numbers.begin(), numbers.end(), std::greater<int>());

它清楚地表明了正在发生的事情 - 即使有评论,也能减少将

rbegin
误读为
begin
的可能性。它清晰易读,这正是您想要的。

此外,鉴于反向迭代器的性质,第二个可能比第一个效率低,尽管您必须对其进行分析才能确定。


33
投票

这个怎么样?

std::sort(numbers.begin(), numbers.end());
std::reverse(numbers.begin(), numbers.end());

32
投票

您可以使用 Lambda 函数,而不是 Mehrdad 提出的函子。

sort(numbers.begin(), numbers.end(), [](const int a, const int b) {return a > b; });

19
投票

根据我的机器,使用第一种方法对 [1..3000000] 的

long long
向量进行排序大约需要 4 秒,而使用第二种方法大约需要两倍的时间。显然,这说明了一些问题,但我也不明白为什么。只是觉得这会有帮助。

同样的事情报告这里

正如 Xeo 所说,使用

-O3
他们大约用相同的时间来完成。


15
投票

第一种方法是指:

    std::sort(numbers.begin(), numbers.end(), std::greater<>());

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


11
投票

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;
}

使用此命令行:

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

std::greater
演示
std::reverse_iterator
演示

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


9
投票
bool comp(int i, int j) { return i > j; }
sort(numbers.begin(), numbers.end(), comp);

6
投票

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

sort(&a[0], &a[n], greater<int>());

2
投票

我认为你不应该使用问题中的任何一种方法,因为它们都很令人困惑,而第二种方法正如 Mehrdad 所建议的那样脆弱。

我会提倡以下内容,因为它看起来像标准库函数并且其意图很明确:

#include <iterator>

template <class RandomIt>
void reverse_sort(RandomIt first, RandomIt last)
{
    std::sort(first, last, 
        std::greater<typename std::iterator_traits<RandomIt>::value_type>());
}

0
投票

对于 C++20:

std::ranges::sort(numbers, std::ranges::greater());
© www.soinside.com 2019 - 2024. All rights reserved.