按降序对向量进行排序

发布于 2024-12-29 08:12:12 字数 259 浏览 4 评论 0原文

我应该使用

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

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

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

Should I use

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

or

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

to sort a vector in descending order? Are there any benefits or drawbacks with one approach or the other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

娇纵 2025-01-05 08:12:12

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

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

With c++14 you can do this:

std::sort(numbers.begin(), numbers.end(), std::greater<>());
迷爱 2025-01-05 08:12:12

使用第一个:

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

它清楚地表明了正在发生的事情 - 即使有注释,将 rbegin 误读为 begin 的可能性也较小。它清晰易读,这正是您想要的。

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

Use the first:

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

It's explicit of what's going on - less chance of misreading rbegin as begin, even with a comment. It's clear and readable which is exactly what you want.

Also, the second one may be less efficient than the first given the nature of reverse iterators, although you would have to profile it to be sure.

爺獨霸怡葒院 2025-01-05 08:12:12

这又如何呢?

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

What about this?

std::sort(numbers.begin(), numbers.end());
std::reverse(numbers.begin(), numbers.end());
不知所踪 2025-01-05 08:12:12

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

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

Instead of a functor as Mehrdad proposed, you could use a Lambda function.

sort(numbers.begin(), numbers.end(), [](const int a, const int b) {return a > b; });
〆一缕阳光ご 2025-01-05 08:12:12

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

此处报告了同样的情况。

正如 Xeo 所说,使用 -O3 他们大约使用相同的时间来完成。

According to my machine, sorting a long long vector of [1..3000000] using the first method takes around 4 seconds, while using the second takes about twice the time. That says something, obviously, but I don't understand why either. Just think this would be helpful.

Same thing reported here.

As said by Xeo, with -O3 they use about the same time to finish.

寄人书 2025-01-05 08:12:12

TL;DR

使用任何。它们几乎是一样的。

无聊的答案

像往常一样,有利有弊。

使用 std::reverse_iterator

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

时使用 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 报告了相同数量的缓存未命中。

TL;DR

Use any. They are almost the same.

Boring answer

As usual, there are pros and cons.

Use std::reverse_iterator:

  • When you are sorting custom types and you don't want to implement
    operator>()
  • When you are too lazy to type std::greater<int>()

Use std::greater when:

  • When you want to have more explicit code
  • When you want to avoid using obscure reverse iterators

As for performance, both methods are equally efficient. I tried the following benchmark:

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

With this command line:

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 demo
std::reverse_iterator demo

Timings are same. Valgrind reports the same number of cache misses.

婴鹅 2025-01-05 08:12:12

第一种方法是指:

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

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

First approach refers:

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

You may use the first approach because of getting more efficiency than second.
The first approach's time complexity less than second one.

帅气称霸 2025-01-05 08:12:12
bool comp(int i, int j) { return i > j; }
sort(numbers.begin(), numbers.end(), comp);
bool comp(int i, int j) { return i > j; }
sort(numbers.begin(), numbers.end(), comp);
枕花眠 2025-01-05 08:12:12

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

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

You can either use the first one or try the code below which is equally efficient

sort(&a[0], &a[n], greater<int>());
尴尬癌患者 2025-01-05 08:12:12

我认为您不应该使用问题中的任何一种方法,因为它们都很令人困惑,而第二种方法正如 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>());
}

I don't think you should use either of the methods in the question as they're both confusing, and the second one is fragile as Mehrdad suggests.

I would advocate the following, as it looks like a standard library function and makes its intention clear:

#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>());
}
千と千尋 2025-01-05 08:12:12

对于 C++20:

std::ranges::sort(numbers, std::ranges::greater());

这排除了传入无效迭代器对的任何可能性,例如:

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

For C++20:

std::ranges::sort(numbers, std::ranges::greater());

This rules out any possibility of passing in an invalid pair of iterators like:

std::sort(numbers.end(), numbers.begin(), std::greater<>());
std::sort(numbers.begin(), something_else.end(), std::greater<>());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文