2009-11-20 5 views
19

Der Standardweg zwei Sätze in C++ von sich schneid ist folgendes zu tun:In-Place-C++ Schnittmenge

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())); 

Wie würde ich über das Tun eine in-Place-Set Kreuzung gehen? Das heißt, ich möchte set_1 die Ergebnisse des Aufrufs von set_intersection haben. Offensichtlich kann ich einfach eine set_1.swap(the_intersection) machen, aber das ist viel weniger effizient als das Schneiden an Ort und Stelle.

Antwort

12

Ich glaube, ich habe es:

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()); 

Wer irgendwelche Probleme sehen? Scheint O (n) auf der Größe der zwei Sätze zu sein. Gemäß cplusplus.com ist std :: set Erase (Position) amortisiert, während Erase (first, last) ist O (log n).

+0

Die Fortsetzung ist redundant, und ich würde neu anordnen, um zu sein: if (* it1 <* it2) sonst if (* it2 <* it1) else ... 'so dass der einzige Vergleichsoperator, den Sie verwenden, kleiner ist als - So funktioniert 'set'. –

+0

Richtig! Weil es wenn-sonst wenn, etc. Ich dachte, dass die folgenden Bedingungen überprüft würden. Danke, ich werde die Antwort bearbeiten. – ChrisInEdmonton

+7

'set_1.erase (it1 ++)' ist falsch für einige Container (wie Vektor), auch wenn es in Ihrem Fall gültig ist. Sie sollten 'it1 = set_1.erase (it1)' verwenden, das für alle Container gültig ist. –

3

Sie können ganz einfach durch set_1 gehen, überprüfen Sie jedes Element, um zu sehen, ob es in set_2 vorhanden ist, und es zu löschen, wenn es nicht der Fall ist. Da die Sätze sortiert sind, können Sie sie in linearer Zeit vergleichen, und das Löschen eines Elements mit einem Iterator ist amortized constant time. Ich würde nicht darauf zählen, dass es effizienter ist als das, womit Sie begonnen haben, Benchmarking wäre jedoch sinnvoll, wenn es für Sie von Bedeutung ist.

+0

Wahr genug in allen Punkten. Es scheint mir intuitiv, dass es möglich sein sollte, beide Sätze auf einmal zu durchlaufen und die Kreuzung an Ort und Stelle zu machen. Ich sehe einfach nicht sofort wie. – ChrisInEdmonton

+0

Die Löschoperation für ein einzelnes Element eines ausgeglichenen Binärbaums wird in "O (log N)" ausgeführt. – ThomasMcLeod

+0

@ThomasMcLeod nein, es ist amortisierte Konstante. Ich wusste das nicht, als ich die Antwort schrieb, aber ich weiß es jetzt, und ich habe es aktualisiert, um das zu reflektieren. –