45 votes

Est-ce que std::sort vérifie si un vecteur est déjà trié ?

Je crois que la norme C++ pour std::sort ne garantit pas des performances O(n) sur une liste déjà triée. Mais tout de même, je me demande si, à votre connaissance, les implémentations de la STL (GCC, MSVC, etc.) font le choix de la méthode de tri de la liste. std::is_sorted vérifier avant d'exécuter l'algorithme de tri ?

En d'autres termes, quelles sont les performances que l'on peut attendre (sans garantie, bien sûr) de l'exécution d'un programme de type std::sort sur un conteneur trié ?

Note complémentaire : j'ai posté quelques points de repère pour GCC 4.5 avec C++0x activé sur mon blog. Voici les résultats :

Comparison of std::sort and std::is_sorted

6 votes

Aimerait voir sur une échelle log-log

33voto

Eelke Points 7687

Les implémentations sont libres d'utiliser tout algorithme de tri efficace qu'elles souhaitent, ce qui dépend fortement de l'implémentation.

Cependant, j'ai vu une comparaison des performances de libstdc++ tel qu'utilisé sur linux et contre libc++ la nouvelle bibliothèque C++ développée par Apple/LLVM. Ces deux bibliothèques sont très efficaces sur des données triées ou triées à l'envers (beaucoup plus rapidement que sur une liste aléatoire), la nouvelle bibliothèque étant considérablement plus rapide que l'ancienne et reconnaissant beaucoup plus de modèles.

Pour en être certain, vous devriez envisager de faire vos propres tests de référence.

19 votes

Il y a quelques mois, j'ai demandé à Howard Hinnant comment il mettait en place la std::sort dans libc++. Son implémentation vérifie les entrées triées et triées à l'envers, non seulement au niveau "complet", mais aussi à chaque niveau de la récursion, de sorte que les entrées partiellement triées bénéficient également de l'accélération. Il a estimé que c'était suffisamment important pour sacrifier quelques performances dans le cas "chaotique".

6 votes

La STL disponible avec msvc 2010 (Dinkumware, je crois) fait également quelque chose de similaire à ce que Matthieu mentionne. Ce n'est pas la même chose que d'appeler is_sorted sur les entrées, mais construit plutôt une vérification des sous-gammes partiellement triées dans la partition quicksort, donc utile pour les séquences partiellement triées.

18 votes

Clarification. libc++ ne fait pas réellement un is_sorted vérifier à chaque niveau (ce qui consommerait trop de cpu). Mais c'est proche de cela. Je crois que libc++ fait 2N comparaisons (et pas de permutation) sur une séquence triée ( is_sorted ne fait que N comparaisons sur une séquence triée). libc++ compte les échanges pendant chaque phase de partition. Si aucun échange n'est effectué, libc++ passe à un tri par insertion "partiel" pour chaque partition. Ce tri par insertion s'arrêtera si plus de quelques éléments doivent être insérés. Rappelons que le tri par insertion n'effectue que N comparaisons (et aucun déplacement) pour une séquence triée.

24voto

iammilind Points 29275

Non . De plus, il n'est pas logique d'avoir is_sorted() appelé pour toute implémentation STL. Depuis, is_sorted() est déjà disponible en version autonome. Et de nombreux utilisateurs peuvent ne pas vouloir gaspiller inutilement des cycles d'exécution pour appeler cette fonction lorsqu'ils savent déjà que leur conteneur n'est pas trié.

La STL devrait également suivre la philosophie du C++ : " paiement à l'utilisation ".

2 votes

Qu'entendez-vous par "paiement à l'utilisation" ?

15 votes

@Lex Fridman : cela signifie que quelque chose coûte seulement si vous l'utilisez. std::sort n'a pas voulu appeler std::is_sorted parce qu'alors std::sort encourrait les coûts de std::is_sorted en plus de la sienne. En d'autres termes, si vous voulez éviter que NlogN ne soit possible pour std::sort dans une liste triée, il revient à vous pour payer le prix de l'appel std::is_sorted . De plus, si vous avez des listes qui sont presque triées, vous devriez utiliser un tri à bulles ou autre chose qui présente de bonnes caractéristiques de tri pour les listes presque triées.

2 votes

@Lex, selon les mots de Bjarne Stroustrup, "Pay only for what you use." Je ne me souviens pas dans quelle interview il a dit cela. Mais cette phrase est facilement disponible sur le net.

12voto

Howard Hinnant Points 59526

Wow ! Est-ce que tu as optimisé au maximum ?

Here's les résultats de votre code sur ma plateforme (notez les valeurs sur l'axe vertical).

0 votes

Cool, tu as raison, je n'ai pas activé l'optimisation. La question est mise à jour. Pourtant, il semble que pour vous, std::sort fait beaucoup mieux que pour moi. Je me demande pourquoi ?

2 votes

Voir le troisième commentaire sous stackoverflow.com/questions/6567326/

4voto

Mikael Persson Points 7174

Je vous suggère de lire cette comparaison des algorithmes de tri Il compare un certain nombre d'algorithmes de tri entre eux et avec l'implémentation de std::sort par GCC. Vous remarquerez, dans les graphiques sur le lien donné, que les performances de std::sort pour "presque trié" et "presque inversé" sont linéaires dans le nombre d'éléments à trier, c'est-à-dire O(n). Donc, pas de garantie, mais vous pouvez facilement vous attendre à ce qu'une liste presque triée soit triée en temps presque linéaire. Mais, bien sûr, il ne fait pas de vérification is_sorted, et même s'il trie un tableau trié en temps linéaire, ce ne sera pas aussi rapide que de faire une vérification is_sorted et de sauter complètement le tri. C'est à vous de déterminer s'il est préférable de vérifier avant de trier ou non.

4voto

phresnel Points 20082

La norme sanctionne uniquement std::sort implémentations avec une complexité O(n log n) :

La complexité : Approximativement N log N (où N == last - first ) comparaisons sur la moyenne.

Voir la section 25.3.1.1 Le tri [lib.sort] (ISO/IEC 14882:2003(E)).

Ainsi, l'ensemble des fonctions de tri autorisées est limité, et vous avez raison de dire que cela ne garantit pas une complexité linéaire.

Le comportement idéal pour un tri est O(n), mais cela n'est pas possible dans le cas moyen.

Bien sûr, le cas moyen n'est pas nécessairement le cas exact que vous avez en ce moment, donc pour les cas particuliers, il n'y a pas beaucoup de garantie.

0 votes

Le problème est que, selon l'algorithme, un vecteur trié peut présenter le pire des cas. O(n log n) en moyenne ne dit rien sur le pire cas - il peut donc être O(n^2) comme pour le quicksort standard.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X