J'ai essayé de trouver l'intersection entre deux std :: set en C ++, mais j'obtiens toujours une erreur.
J'ai créé un petit exemple de test pour cela
#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
int main() {
set<int> s1;
set<int> s2;
s1.insert(1);
s1.insert(2);
s1.insert(3);
s1.insert(4);
s2.insert(1);
s2.insert(6);
s2.insert(3);
s2.insert(0);
set_intersection(s1.begin(),s1.end(),s2.begin(),s2.end());
return 0;
}
Ce dernier programme ne génère aucune sortie, mais je m'attends à avoir un nouvel ensemble (appelons-le s3
) avec les valeurs suivantes:
s3 = [ 1 , 3 ]
Au lieu de cela, j'obtiens l'erreur:
test.cpp: In function ‘int main()’:
test.cpp:19: error: no matching function for call to ‘set_intersection(std::_Rb_tree_const_iterator<int>, std::_Rb_tree_const_iterator<int>, std::_Rb_tree_const_iterator<int>, std::_Rb_tree_const_iterator<int>)’
Ce que je comprends de cette erreur, c'est qu'il n'y a pas de définition set_intersection
qui accepte Rb_tree_const_iterator<int>
comme paramètre.
De plus, je suppose que la std::set.begin()
méthode renvoie un objet de ce type,
y a-t-il une meilleure façon de trouver l'intersection de deux std::set
en C ++? De préférence une fonction intégrée?
Merci beaucoup!
c++
std
stl-algorithm
stdset
J'aime les tacos
la source
la source
Réponses:
Vous n'avez pas fourni d'itérateur de sortie pour set_intersection
Corrigez cela en faisant quelque chose comme
Vous avez besoin d'un
std::insert
itérateur car l'ensemble est désormais vide. Nous ne pouvons pas utiliser back_ ou front_inserter car set ne prend pas en charge ces opérations.la source
set<T>& set::isect(set<T>&)
méthode , qui fait le nécessaire? (Je demanderais unset<T>& set::operator^(set<T>&)
, mais c'est probablement un pont trop loin.)<algorithm>
cohérence si rien d'autre. Ce style aussi, je suppose, vous donne de la flexibilité. Et permet aux algos d'être utilisés avec plusieurs conteneurs, bien que cela ne se produise pas ici. De plus, votre signature peut ne pas fonctionner, vous devez probablement renvoyer une valeur. Et que dans les jours qui ont précédé la copie, la sémantique aurait été une double copie, je pense. Je n'ai pas fait de c ++ depuis un moment maintenant, alors prenez cela avec une pincée ou 3 de selset
conteneur qui fait l'intersection avec un autre ensemble. Le sujet du passage d'un conteneur au lieu de.begin()
-.end()
est une autre chose - cela sera corrigé une fois que C ++ aura des concepts.Jetez un œil à l'exemple dans le lien: http://en.cppreference.com/w/cpp/algorithm/set_intersection
Vous avez besoin d'un autre conteneur pour stocker les données d'intersection, sous le code supposé fonctionner:
la source
back_inserter
ne fonctionne pas avecset
commeset
n'a aucunepush_back
fonction.Voir std :: set_intersection . Vous devez ajouter un itérateur de sortie, dans lequel vous stockerez le résultat:
Voir Ideone pour la liste complète.
la source
Juste commenter ici. Je pense qu'il est temps d'ajouter l'union, l'opération d'intersection à l'interface définie. Proposons cela dans les futures normes. J'utilise le std depuis longtemps, chaque fois que j'utilisais l'opération set, j'aurais souhaité que le std soit meilleur. Pour une opération d'ensemble compliquée, comme l'intersection, vous pouvez simplement (plus facilement?) Modifier le code suivant:
copié de http://www.cplusplus.com/reference/algorithm/set_intersection/
Par exemple, si votre sortie est un ensemble, vous pouvez output.insert (* first1). De plus, votre fonction peut ne pas être modélisée.Si votre code peut être plus court que l'utilisation de la fonction std set_intersection, continuez avec.
Si vous voulez faire une union de deux ensembles, vous pouvez simplement setA.insert (setB.begin (), setB.end ()); C'est beaucoup plus simple que la méthode set_union. Cependant, cela ne fonctionnera pas avec le vecteur.
la source
Le premier commentaire (bien voté) de la réponse acceptée se plaint d'un opérateur manquant pour les opérations existantes de l'ensemble std.
D'une part, je comprends l'absence de tels opérateurs dans la bibliothèque standard. D'autre part, il est facile de les ajouter (pour la joie personnelle) si vous le souhaitez. J'ai surchargé
operator *()
pour l'intersection d'ensemblesoperator +()
pour l'union d'ensembles.Échantillon
test-set-ops.cc
:Compilé et testé:
Ce que je n'aime pas, c'est la copie des valeurs de retour dans les opérateurs. Peut-être, cela pourrait être résolu en utilisant l'affectation de déménagement, mais cela dépasse toujours mes compétences.En raison de ma connaissance limitée de cette sémantique de mouvement «nouvelle fantaisie», j'étais préoccupé par les retours d'opérateurs qui pourraient provoquer des copies des ensembles retournés. Olaf Dietsche a souligné que ces préoccupations sont inutiles car il
std::set
est déjà équipé d'un constructeur de déménagement / d'une affectation.Bien que je l'ai cru, je pensais comment vérifier cela (pour quelque chose comme "auto-convaincant"). En fait, c'est assez facile. Comme les modèles doivent être fournis dans le code source, vous pouvez simplement parcourir le débogueur. Ainsi, j'ai placé un point de rupture juste à la fin
return s;
de laoperator *()
et j'ai procédé à une seule étape qui m'a immédiatement conduit àstd::set::set(_myt&& _Right)
: et voilà - le constructeur de mouvement. Merci, Olaf, pour (ma) illumination.Par souci d'exhaustivité, j'ai également implémenté les opérateurs d'affectation correspondants
operator *=()
pour l'intersection "destructive" d'ensemblesoperator +=()
pour l'union "destructive" d'ensembles.Échantillon
test-set-assign-ops.cc
:Compilé et testé:
la source
std::set
implémente déjà le constructeur de déplacement et l'opérateur d'affectation nécessaires, donc pas besoin de s'inquiéter à ce sujet. De plus, le compilateur utilise très probablement l' optimisation de la valeur de retour