2017-04-12 1 views
0

J'ai un vecteur de paires de ints, à savoir Est-il possible de modifier ou de "personnaliser" les opérateurs d'une classe existante?

std::vector< std::pair<int, int> > V; 

Je voulais trier ce vecteur, j'ai donc écrit une implémentation quicksort. Heureusement, std::pair définit déjà les opérateurs de comparaison intelligents tels que

[[3, 1], [1, 7], [3, 5]] 

sortes de

[[1, 7], [3, 1], [3, 5]] 

à-dire tri par le premier élément de chaque paire, en utilisant le second élément comme un bris d'égalité.

Mais ce que je veux réellement est de comparer le deuxième élément décroissant ordre. Ainsi, l'exemple ci-dessus doit être triée comme

[[1, 7], [3, 5], [3, 1]] 

Est-il possible de passer outre les opérateurs de comparaison de std::pair afin que je puisse trier en augmentant la première et la diminution deuxième élément? Si non, quelle est la meilleure façon d'y parvenir, en termes de design?

Je pensais à dériver une classe enfant de std::pair qui l'emportaient sur tous les opérateurs de comparaison, mais nécessaire reinterpret_cast ing std::pair<int, int>* aux pointeurs de ma classe enfant qui se sent très mal.

Est-ce qu'une classe d'assistance statique séparée est la seule solution? (Mis à part les hacks comme multiplier tous les deuxièmes éléments par -1, sachant que toutes les valeurs sont positives.)

Répondre

1

Vous devez suivre le principe général de la bibliothèque C++ et utiliser des comparateurs. Les modèles de conteneur associatif ordonnés, tels que std::set, possèdent un paramètre de modèle facultatif, une classe de comparateur qui définit l'ordre de tri. Par exemple:

std::set<int> 

vous donne un ensemble qui commande ses int valeurs dans le naturel, l'augmentation de l'ordre. L'itération sur cet ensemble de stock va parcourir ses valeurs de la plus petite à la plus haute valeur. Mais c'est seulement parce que std::set a vraiment un deuxième paramètre de modèle, le comparateur, par défaut std::less qui est, fondamentalement, un wrapper pour l'opérateur <. Ce std::set est vraiment:

std::set<int, std::less<int>> 

(Il y a aussi un troisième paramètre de modèle, qui ne sont pas pertinents aux fins de cette discussion).

Si vous vous vouliez pouvez déclarer, au contraire, un:

std::set<int, std::greater<int>> 

Et puis, si vous deviez itérer sur cet ensemble, vous découvrirez que vous serez itérez du plus grand au plus petit valeurs dans l'ensemble. À tous les autres égards, cet ensemble fonctionne comme un ensemble ordinaire.

De même, parlons de cette implémentation quicksort que vous avez écrite.Votre quicksort utilise l'opérateur < directement pour comparer votre std::pair s. Vous devez simplement réécrire votre implémentation de quicksort pour prendre un paramètre supplémentaire, un comparateur, qui spécifie l'ordre de tri. Au lieu de simplement utiliser l'opérateur surchargé <, votre implémentation de quicksort appelle le comparateur à la place, pour comparer les deux paires.

Maintenant, vous serez en mesure de trier rapidement vos paires dans n'importe quel ordre que vous pouvez spécifier avec un seul objet appelable qui prend deux std::pair s arbitraires, et calcule leur ordre relatif.

+0

Je vois, donc vous dites que la comparaison personnalisée devrait exister en dehors de toute relation avec 'std :: pair', implémentée à la place dans le cadre de l'implémentation de quicksort. Ça a l'air propre, je vais le faire comme ça. Pourtant, je suis curieux de quelque chose, plus d'un point de vue théorique: –

+0

Si, disons, un tas d'algorithmes dans '' ou une autre bibliothèque, manipulent et trie mon vecteur de 'std :: pair's très bien. Mais disons, maintenant, je veux que tous considèrent un ordre différent (par exemple, deuxième élément descendant). Alors ne semble-t-il pas inutile de demander à chaque algorithme de prendre un paramètre de comparaison? Avez-vous une idée de la raison pour laquelle «l'ordre» d'un type ne devrait pas être intrinsèque au type, par opposition à une responsabilité des choses manipulant ce type? –