9
votes

Tri uniquement en utilisant l'opérateur moins que l'opérateur par rapport à une fonction de comparaison de trivalue

en tri c ++ / stl se fait en utilisant uniquement l'opérateur moins que l'opérateur. Algorithmes de tri réellement impliqué, je suppose que les autres opérations sont créées implicite: xxx

comparé à l'utilisation d'une fonction de trivalue * comparer la fonction, comme par exemple, Java, est-ce que ceci Bon pour la performance, ou pourquoi cette décision de conception a-t-elle été faite?

Mon hypothèse est que toute fonction de comparète trivalue doit toujours mettre en œuvre ces comparaissons en soi, ce qui entraîne la même performance.

* * Par la fonction de comparaison de trivalue, je veux dire une fonction de comparaison qui retourne -1, 0 et 1 pour moins que, égale et supérieure à *

mise à jour: Il semble qu'un vaisseau spatial <=> est arrivé en C ++ 20, donc évidemment le comité pensait qu'il y avait des inconvénients d'utiliser uniquement l'opérateur << / code>.


1 commentaires

Cela a été récemment discuté sur comp.lang.c ++. Modérées: groups.google.com/group/comp.lang.c ++. Modéré / Browse_frm / ...


3 Réponses :


1
votes

Je suppose en C ++, il a été fait simplement pour réduire la duplication de code: une fois que vous avez défini un comparateur OP sur une classe / type, vous ne pouvez pas seulement comparer ces objets en écrivant simplement un

Quant au tri, nous n'avons besoin que de moins que l'opérateur, pourquoi introduire des choses supplémentaires? :)


0 commentaires

0
votes

Si vous faites référence à STD :: Trier (), son utilisation seulement moins (), car il n'a pas besoin de préserver un ordre relatif de l'élément équivalent, il aura donc besoin d'un opérateur moins () et implicitement plus grand ( ) Opérateur.

tandis que STD :: Stable_Sort le préservera, mais il est plus lent. Il a besoin d'un opérateur moins () et d'un itérateur bidirectionnel en échange d'un opérateur égal () pour construire «trivalue» comparer la fonction


1 commentaires

Je ne sais pas que je suivais votre point sur la nécessité d'avoir besoin d'itérateurs bidirectionnels. Les deux ont besoin d'itérateurs d'accès aléatoire (par exemple ne trieront pas une liste).



11
votes

Dans un sens, les deux autres sont implicites, mais plus précis seraient de dire qu'un type de comparaison ne doit pas réellement besoin un comparateur tri-values, et la sorte de C ++ sont implémentés de manière à ce que n'utilise-t-il pas l'un afin de minimiser le comportement requis du comparateur.

Ce serait faux pour STD :: Trier pour définir et utiliser exclusivement quelque chose comme ceci: xxx

... parce que vous finisez avec un algorithme inefficace dans TERMES DE NOMBRE D'APPELS AUX MOASTHAN . Si votre algorithme ne fait rien d'utile avec la différence entre un retour 1 et un retour 0, vous avez perdu une comparaison.

C ++ fait référence à "des commandes strictes faibles". Si << / code> est une commande faible stricte, et ! (A , il ne pas nécessairement que a == b . Ils sont juste "au même endroit" dans la commande, et ! (A est une relation d'équivalence. Donc le comparateur requis par trier commandes cours d'équivalence d'objets, il ne fournit pas une commande totale.

la seule différence qu'il fait est ce que vous Dis quand ! (a . Pour une commande totale stricte, vous déduiriez B <= A , lu "inférieur ou égal à". Pour un ordre faible strict, vous ne pouvez pas définir b <= a pour signifier b et que cela soit vrai. C ++ est pédant à ce sujet, et puisqu'il permet à l'opérateur la surcharge de l'opérateur, elle doit être, car les personnes surchargeant des opérateurs ont besoin du jargon afin de dire aux utilisateurs de leur code ce qu'ils peuvent s'attendre en ce qui concerne la relation des opérateurs. Java parle du comparateur et le HASHCODE est cohérent avec des égaux, ce qui est tout ce dont vous avez besoin. C ++ doit traiter avec <,>, ==, <=,> =, la post-condition de l'affectation, etc.

C ++ prend une approche mathématique assez pure dans l'API, alors Tout est défini en termes de relation binaire unique. Java est plus convivial à certains égards et préfère des comparaisons à trois voies où la définition de l'unité fondamentale (la comparaison) est un peu plus complexe, mais la logique qui mène de cela est plus simple. Cela signifie également que l'algorithme de tri reçoit plus d'informations par comparaison, ce qui est parfois utile. Pour un exemple, reportez-vous à l'optimisation QuickSort "Drapeau néerlandais", qui est un avantage lorsqu'il y a beaucoup de doublons "au même endroit" dans les données.

Dans ce cas, un comparateur de trois valeurs est un gain de vitesse. Mais C ++ utilise une définition cohérente d'un comparateur pour trier et aussi pour définir et mappe , inférieur_bound et ainsi de suite, ce qui bénéficie à peine d'une -Value comparateur (peut-être sauver une comparaison, peut-être pas). Je suppose qu'ils ont décidé de ne pas compliquer leur belle interface générale dans l'intérêt de gains d'efficacité potentiels spécifiques ou limités.


0 commentaires