2009-11-20 33 views
19

La forma estándar de intersección de dos conjuntos en C++ es hacer lo siguiente:-C++ establecer intersección

std::set<int> set_1; // With some elements 
std::set<int> set_2; // With some other elements 
std::set<int> the_intersection; // Destination of intersect 
std::set_intersection(set_1.begin(), set_1.end(), set_2.begin(), set_2.end(), std::inserter(the_intersection, the_intersection.end())); 

¿Cómo voy a ir haciendo un conjunto de intersección en el lugar? Es decir, quiero que set_1 tenga los resultados de la llamada a set_intersection. Obviamente, puedo hacer un set_1.swap(the_intersection), pero esto es mucho menos eficiente que intersectar en el lugar.

Respuesta

12

creo que ya lo tengo:

std::set<int>::iterator it1 = set_1.begin(); 
std::set<int>::iterator it2 = set_2.begin(); 
while ((it1 != set_1.end()) && (it2 != set_2.end())) { 
    if (*it1 < *it2) { 
     set_1.erase(it1++); 
    } else if (*it2 < *it1) { 
     ++it2; 
    } else { // *it1 == *it2 
      ++it1; 
      ++it2; 
    } 
} 
// Anything left in set_1 from here on did not appear in set_2, 
// so we remove it. 
set_1.erase(it1, set_1.end()); 

Alguien ve algún problema? Parece ser O (n) en el tamaño de los dos conjuntos. De acuerdo con cplusplus.com, std :: set erase (position) se amortiza constantemente, mientras que erase (first, last) es O (log n).

+0

Los continuos son redundantes, y me gustaría reorganizarlos para que sean 'if (* it1 <* it2) else if (* it2 <* it1) else ...' de modo que el único operador de comparación que está utilizando sea menor que - así es como funciona 'set '. –

+0

¡Correcto! Porque es if-else if, etc. Estaba pensando que los siguientes condicionales serían verificados. Gracias, editaré la respuesta. – ChrisInEdmonton

+7

'set_1.erase (it1 ++)' es incorrecto para algunos contenedores (como vector), incluso si es válido en su caso. Debe usar 'it1 = set_1.erase (it1)' que sea válido con todos los contenedores. –

3

Puede ir fácilmente a través de set_1, verifique cada elemento para ver si existe en set_2, y bórrelo si no lo hace. Como los conjuntos están ordenados, puede compararlos en tiempo lineal, y borrar un elemento usando un iterador es amortized constant time. Sin embargo, no confiaría en que sea más eficiente que con lo que comenzaste, la evaluación comparativa sería sabia si es importante para ti.

+0

Lo suficientemente cierto en todos los puntos. Me parece intuitivamente que debería ser posible iterar a través de ambos conjuntos a la vez y hacer la intersección en su lugar. Simplemente no veo de inmediato cómo. – ChrisInEdmonton

+0

La operación de borrado en un solo elemento de un árbol binario equilibrado se ejecuta en 'O (log N)'. – ThomasMcLeod

+0

@ThomasMcLeod no, se amortiza constantemente. No lo sabía cuando escribí la respuesta, pero ahora la sé y la actualicé para reflejarla. –