Tenho tentado encontrar a interseção entre dois std :: set em C ++, mas continuo recebendo um erro.
Eu criei um pequeno teste de amostra para este
#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;
}
O último programa não gera nenhuma saída, mas espero ter um novo conjunto (vamos chamá-lo s3
) com os seguintes valores:
s3 = [ 1 , 3 ]
Em vez disso, estou recebendo o erro:
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>)’
O que entendi desse erro, é que não existe uma definição set_intersection
que aceite Rb_tree_const_iterator<int>
como parâmetro.
Além disso, suponho que o std::set.begin()
método retorna um objeto desse tipo,
existe uma maneira melhor de encontrar a interseção de dois std::set
em C ++? De preferência, uma função embutida?
Muito obrigado!
c++
std
stl-algorithm
stdset
Eu gosto de tacos
fonte
fonte
Respostas:
Você não forneceu um iterador de saída para set_intersection
Corrija isso fazendo algo como
Você precisa de um
std::insert
iterador, pois o conjunto está vazio agora. Não podemos usar back_ ou front_inserter, pois set não suporta essas operações.fonte
set<T>& set::isect(set<T>&)
método simples , que faz o necessário? (Eu pediria umset<T>& set::operator^(set<T>&)
, mas provavelmente é uma ponte longe demais.)<algorithm>
consistência, se nada mais. Este estilo também, presumo, dá flexibilidade. E permite que o algos seja usado com vários contêineres, embora isso possa não acontecer aqui .. Além disso, sua assinatura pode não funcionar, você provavelmente precisará retornar um valor. E que, nos dias anteriores à cópia, a semântica seria uma cópia dupla, eu acho. Eu não tenho feito c ++ por um tempo agora, então aceite isso com uma pitada de salset
contêiner que faz a interseção com outro conjunto. O tópico de passar um contêiner em vez de.begin()
-.end()
é outra coisa - será corrigido assim que o C ++ tiver conceitos.Dê uma olhada no exemplo no link: http://en.cppreference.com/w/cpp/algorithm/set_intersection
Você precisa de outro contêiner para armazenar os dados de interseção, o código abaixo deve funcionar:
fonte
back_inserter
não funcionaset
comoset
não tempush_back
função.Veja std :: set_intersection . Você deve adicionar um iterador de saída, onde armazenará o resultado:
Veja Ideone para uma lista completa.
fonte
Basta comentar aqui. Acho que é hora de adicionar a operação de união e interseção à interface definida. Vamos propor isso nos padrões futuros. Eu tenho usado o std por um longo tempo, cada vez que usei a operação de conjunto desejei que o std fosse melhor. Para alguma operação de conjunto complicada, como intersect, você pode simplesmente (mais fácil?) Modificar o seguinte código:
copiado de http://www.cplusplus.com/reference/algorithm/set_intersection/
Por exemplo, se sua saída for um conjunto, você pode output.insert (* first1). Além disso, sua função não pode ser modelada. Se seu código pode ser mais curto do que usar a função std set_intersection, vá em frente com ela.
Se você quiser fazer uma união de dois conjuntos, você pode simplesmente setA.insert (setB.begin (), setB.end ()); Isso é muito mais simples do que o método set_union. No entanto, isso não funcionará com vetor.
fonte
O primeiro comentário (bem votado) da resposta aceita reclama sobre a falta de um operador para as operações de conjunto padrão existentes.
Por um lado, entendo a falta de tais operadores na biblioteca padrão. Por outro lado, é fácil adicioná-los (para a alegria pessoal) se desejar. Eu sobrecarreguei
operator *()
para interseção de conjuntosoperator +()
para união de conjuntos.Amostra
test-set-ops.cc
:Compilado e testado:
O que eu não gosto é a cópia dos valores de retorno nas operadoras. Pode ser, isso poderia ser resolvido usando a atribuição de movimento, mas isso ainda está além das minhas habilidades.Devido ao meu conhecimento limitado sobre essas semânticas de movimento "nova fantasia", fiquei preocupado com os retornos do operador que poderiam causar cópias dos conjuntos retornados. Olaf Dietsche apontou que essas preocupações são desnecessárias, pois
std::set
já está equipado com o construtor / atribuição de movimento.Embora acreditasse nele, estava pensando em como verificar isso (algo como "autoconvencimento"). Na verdade, é bem fácil. Como os modelos devem ser fornecidos no código-fonte, você pode simplesmente avançar com o depurador. Assim, coloquei um ponto de interrupção bem no
return s;
deoperator *()
e continuei com uma única etapa que me levou imediatamente astd::set::set(_myt&& _Right)
: et voilà - o construtor de movimento. Obrigado, Olaf, pela (minha) iluminação.Para fins de integridade, implementei os operadores de atribuição correspondentes também
operator *=()
para interseção "destrutiva" de conjuntosoperator +=()
para união "destrutiva" de conjuntos.Amostra
test-set-assign-ops.cc
:Compilado e testado:
fonte
std::set
já implementa o construtor de movimento e o operador de atribuição necessários, portanto, não precisa se preocupar com isso. Além disso, o compilador provavelmente emprega otimização de valor de retorno