Ich habe versucht, den Schnittpunkt zwischen zwei std :: set in C ++ zu finden, aber es wird immer wieder ein Fehler angezeigt.
Ich habe dafür einen kleinen Beispieltest erstellt
#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;
}
Das letztere Programm generiert keine Ausgabe, aber ich erwarte eine neue Menge (nennen wir es s3
) mit den folgenden Werten:
s3 = [ 1 , 3 ]
Stattdessen erhalte ich den Fehler:
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>)’
Was ich aus diesem Fehler verstehe, ist, dass es keine Definition gibt set_intersection
, die Rb_tree_const_iterator<int>
als Parameter akzeptiert .
Außerdem nehme ich an, dass die std::set.begin()
Methode ein Objekt dieses Typs zurückgibt.
Gibt es einen besseren Weg, um den Schnittpunkt von zwei std::set
in C ++ zu finden? Am liebsten eine eingebaute Funktion?
Vielen Dank!
c++
std
stl-algorithm
stdset
Ich mag Tacos
quelle
quelle
Antworten:
Sie haben keinen Ausgabe-Iterator für set_intersection bereitgestellt
Beheben Sie dies, indem Sie so etwas tun
Sie benötigen einen
std::insert
Iterator, da der Satz ab sofort leer ist. Wir können back_ oder front_inserter nicht verwenden, da set diese Operationen nicht unterstützt.quelle
set<T>& set::isect(set<T>&)
Methode, die das Notwendige tut? (Ich würde um eine bittenset<T>& set::operator^(set<T>&)
, aber das ist wahrscheinlich eine Brücke zu weit.)<algorithm>
so Konsistenz, wenn nichts anderes. Ich nehme an, dieser Stil gibt Ihnen auch Flexibilität. Und ermöglicht die Verwendung der Algen mit mehreren Containern, obwohl dies hier möglicherweise nicht der Fall ist. Auch Ihre Signatur funktioniert möglicherweise nicht, Sie müssen wahrscheinlich einen Wert zurückgeben. Und dass in den Tagen vor der Kopiersemantik eine Doppelkopie gewesen wäre, denke ich. Ich habe C ++ schon eine Weile nicht mehr gemacht, also nimm das mit einer Prise oder 3 Salzset
Containermethode geben könnte, die sich mit einer anderen Menge schneidet. Das Thema, einen Container zu übergeben, anstatt.begin()
-.end()
ist eine andere Sache - dies wird behoben, sobald C ++ Konzepte hat.Schauen Sie sich das Beispiel im Link an: http://en.cppreference.com/w/cpp/algorithm/set_intersection
Sie benötigen einen anderen Container, um die Schnittpunktdaten zu speichern. Der folgende Code soll funktionieren:
quelle
back_inserter
funktioniert nicht mitset
daset
hat keinepush_back
funktion.Siehe std :: set_intersection . Sie müssen einen Ausgabe-Iterator hinzufügen, in dem Sie das Ergebnis speichern:
Siehe Ideone für eine vollständige Auflistung.
quelle
Einfach hier kommentieren. Ich denke, es ist an der Zeit, der Set-Schnittstelle eine Union-Intersect-Operation hinzuzufügen. Lassen Sie uns dies in den zukünftigen Standards vorschlagen. Ich benutze den Standard schon lange. Jedes Mal, wenn ich die eingestellte Operation verwendete, wünschte ich mir, der Standard wäre besser. Für einige komplizierte Mengenoperationen wie intersect können Sie einfach (einfacher?) Den folgenden Code ändern:
kopiert von http://www.cplusplus.com/reference/algorithm/set_intersection/
Wenn Ihre Ausgabe beispielsweise eine Menge ist, können Sie output.insert (* first1) ausgeben. Darüber hinaus wird Ihre Funktion möglicherweise nicht als Vorlage verwendet. Wenn Ihr Code kürzer sein kann als die Verwendung der Funktion std set_intersection, fahren Sie fort.
Wenn Sie eine Vereinigung von zwei Mengen durchführen möchten, können Sie einfach setA.insert (setB.begin (), setB.end ()); Dies ist viel einfacher als die set_union-Methode. Dies funktioniert jedoch nicht mit Vektor.
quelle
Der erste (gut abgestimmte) Kommentar der akzeptierten Antwort beklagt einen fehlenden Operator für die vorhandenen Standardsatzoperationen.
Einerseits verstehe ich das Fehlen solcher Operatoren in der Standardbibliothek. Auf der anderen Seite ist es einfach, sie (für die persönliche Freude) hinzuzufügen, wenn dies gewünscht wird. Ich habe überladen
operator *()
für Schnittmenge von Mengenoperator +()
zur Vereinigung von Mengen.Beispiel
test-set-ops.cc
:Zusammengestellt und getestet:
Was mir nicht gefällt, ist die Kopie der Rückgabewerte in den Operatoren. Möglicherweise könnte dies mithilfe der Zugzuweisung gelöst werden, aber dies liegt immer noch außerhalb meiner Fähigkeiten.Aufgrund meines begrenzten Wissens über diese "neue ausgefallene" Bewegungssemantik war ich besorgt über die Operatorrückgaben, die Kopien der zurückgegebenen Sätze verursachen könnten. Olaf Dietsche wies darauf hin, dass diese Bedenken unnötig sind, da sie
std::set
bereits mit einem Bewegungskonstruktor / einer Zuweisung ausgestattet sind.Obwohl ich ihm glaubte, dachte ich darüber nach, wie ich das überprüfen sollte (für etwas wie "selbstüberzeugend"). Eigentlich ist es ganz einfach. Da Vorlagen im Quellcode bereitgestellt werden müssen, können Sie einfach mit dem Debugger durchgehen. So legte ich einen Haltepunkt direkt an die
return s;
von deroperator *()
und ging mit einstufiges , die mich sofort verbleit instd::set::set(_myt&& _Right)
: et voilà - unterwegs Konstruktor. Danke, Olaf, für die (meine) Erleuchtung.Der Vollständigkeit halber habe ich auch die entsprechenden Zuweisungsoperatoren implementiert
operator *=()
für "destruktive" Schnittmenge von Mengenoperator +=()
für "destruktive" Vereinigung von Mengen.Beispiel
test-set-assign-ops.cc
:Zusammengestellt und getestet:
quelle
std::set
implementiert bereits den erforderlichen Verschiebungskonstruktor und Zuweisungsoperator, sodass Sie sich darüber keine Sorgen machen müssen. Auch der Compiler verwendet höchstwahrscheinlich eine Rückgabewertoptimierung