it-swarm.com.de

Sortieren eines Vektors in absteigender Reihenfolge

Sollte ich es benutzen

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

oder

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

sortiere ich einen Vektor in absteigender Reihenfolge? Gibt es Vor- oder Nachteile bei der einen oder der anderen Vorgehensweise?

289
fredoverflow

Eigentlich ist der erste eine schlechte Idee. Verwenden Sie entweder das zweite oder das folgende:

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

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

Auf diese Weise wird Ihr Code nicht unbemerkt unterbrochen, wenn jemand entscheidet, dass numberslong oder long long anstelle von int.

107
Mehrdad

Verwenden Sie die erste:

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

Es ist explizit, was los ist - weniger Wahrscheinlichkeit, rbegin als begin falsch zu lesen, selbst mit einem Kommentar. Es ist klar und lesbar, was genau Sie wollen.

Außerdem ist der zweite möglicherweise weniger effizient als der erste, da es sich um Reverse-Iteratoren handelt, obwohl Sie ihn profilieren müssten, um sicherzugehen.

66
Pubby

Mit C++ 14 können Sie dies tun:

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

Was ist damit?

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

Anstelle eines Funktors, wie von Mehrdad vorgeschlagen, können Sie auch eine Lambda-Funktion verwenden.

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

Entsprechend meiner Maschine sortieren ein long long Vektor von [1..3000000] mit der ersten Methode dauert etwa 4 Sekunden, während die zweite Methode etwa doppelt so lange dauert. Das sagt natürlich etwas aus, aber ich verstehe auch nicht warum. Denke nur, das wäre hilfreich.

Gleiches berichtet hier .

Wie von Xeo gesagt, mit -O3 Sie brauchen ungefähr die gleiche Zeit, um fertig zu werden.

15
zw324

Erster Ansatz bezieht sich auf:

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

Sie können den ersten Ansatz verwenden, weil Sie effizienter sind als den zweiten.
Die zeitliche Komplexität des ersten Ansatzes ist geringer als die des zweiten.

10
rashedcs

Der kürzeste Ansatz ist:

std::sort(v.rbegin(), v.rend());
8
Alexey
bool comp(int i, int j) { return i > j; }
sort(numbers.begin(), numbers.end(), comp);
6
user7069426

Ich denke nicht, dass Sie eine der Methoden in der Frage anwenden sollten, da sie beide verwirrend sind und die zweite, wie Mehrdad vorschlägt, zerbrechlich ist.

Ich würde Folgendes befürworten, da es wie eine Standardbibliotheksfunktion aussieht und seine Absicht klar macht:

#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>());
}
1

Sie können entweder den ersten verwenden oder den folgenden Code ausprobieren, der gleichermaßen effizient ist

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

TL; DR

Verwenden Sie eine. Sie sind fast gleich.

Langweilige Antwort

Wie immer gibt es Vor- und Nachteile.

Verwenden Sie std::reverse_iterator:

  • Wenn Sie benutzerdefinierte Typen sortieren und operator>() nicht implementieren möchten
  • Wenn Sie zu faul sind, um std::greater<int>() einzugeben

Verwenden Sie std::greater, Wenn:

  • Wenn Sie mehr expliziten Code haben möchten
  • Wenn Sie die Verwendung von unklaren Reverse-Iteratoren vermeiden möchten

Was die Leistung betrifft, sind beide Methoden gleichermaßen effizient. Ich habe den folgenden Benchmark ausprobiert:

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

Mit dieser Befehlszeile:

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

Timings sind gleich. Valgrind meldet die gleiche Anzahl von Cache-Fehlern.

0
ivaigult