TL;DR
Utilisez n'importe lequel. Ils sont presque identiques.
Réponse ennuyeuse
Comme d'habitude, il y a des avantages et des inconvénients.
Utilisez std::reverse_iterator
:
- Lorsque vous triez des types personnalisés et que vous ne voulez pas mettre en œuvre
operator>()
- Quand vous êtes trop paresseux pour taper
std::greater<int>()
Utilisez std::greater
quand :
- Lorsque vous voulez avoir un code plus explicite
- Lorsque vous voulez éviter d'utiliser d'obscurs itérateurs inversés
En ce qui concerne les performances, les deux méthodes sont aussi efficaces l'une que l'autre. J'ai essayé le benchmark suivant :
#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;
}
Avec cette ligne de commande :
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
<a href="http://coliru.stacked-crooked.com/a/74aa4e783d6d5a04" rel="noreferrer"><code>std::greater</code> demo</a> <a href="http://coliru.stacked-crooked.com/a/85b330d4d493edc9" rel="noreferrer"><code>std::reverse_iterator</code> demo</a>
Les timings sont les mêmes. Valgrind rapporte le même nombre de manquements au cache.
4 votes
+1 Je pense que la réponse est évidente, mais cette question comporte une partie intéressante de trivium :)
5 votes
Je voterais pour la première option, juste parce qu'ainsi je n'aurais jamais à faire face à
reverse_iterator
's.4 votes
@wilhelmtell Une question de débutant mais pourquoi le deuxième trierait-il par ordre décroissant ? Nous donnons le même tableau comme entrée à la méthode de tri. C'est juste que nous le donnons dans l'ordre inverse, alors pourquoi devrait-il être trié par ordre décroissant et non croissant comme ce serait le cas avec ar.begin() et ar.end.
15 votes
@shshnk
std::sort(b, e);
met le minimum àb
(dans notre casrbegin
donc le dernier ) et le maximum àe
(dans notre casrend
donc le premièrement élément).0 votes
Cela répond-il à votre question ? Tri des éléments du vecteur par ordre décroissant