std::set mit Benutzer-definierter Typ, wie um sicherzustellen, dass keine Duplikate
Also ich habe einen std::set, die braucht, um bestimmte Bestell -, sowie der nicht erlaubt, die Duplikate von einem Benutzer definiert wird (von mir) geben. Jetzt kann ich die Bestellung ordnungsgemäß durch überlastung des '<' - operator in mein Typ. Jedoch das set nicht angemessen Erkennung von Duplikaten, und um ehrlich zu sein, ich bin mir nicht ganz sicher, wie dies geschieht intern. Ich habe überlastet das '= = ' - operator, aber irgendwie bin ich nicht sicher, dass dies ist, was der Satz eigentlich mit? Die Frage ist also, wie die Menge ermitteln Sie Duplikate, wenn Sie Werte hinzufügen? Hier ist der relevante code:
Den Benutzer definierten Typ:
//! An element used in the route calculation.
struct RouteElem {
int shortestToHere; //Shortest distance from the start.
int heuristic; //The heuristic estimate to the goal.
Coordinate position;
bool operator<( const RouteElem& other ) const
{
return (heuristic+shortestToHere) < (other.heuristic+other.shortestToHere);
}
bool operator==( const RouteElem& other ) const
{
return (position.x == other.position.x && position.y == other.position.y);
}
};
Also die Elemente sind äquivalent, wenn Ihre position entspricht, und ein element kleiner als ein anderes, wenn seine kombinierte funktionelle weniger als die der anderen. Die Sortierung funktioniert, aber der Satz wird an die zwei Elemente der gleichen position.
InformationsquelleAutor DeusAduro | 2009-07-11
Du musst angemeldet sein, um einen Kommentar abzugeben.
operator==
ist nichtstd::set
. Elementea
undb
als gleich betrachtet werden, iff!(a < b) && !(b < a)
Es ist nicht möglich, trennen Sie die Vergleich-Funktion von Sortier-Funktion. Der Grund liegt auf der Hand. Ein
set
ist ein binärer Baum intern. Wenn ein element erfüllt Gleichheit Kriterien (nicht größer, noch kleiner), sollte es in dieselbe statt.Sie können die Verwendung von std::unique entfernen, Duplikate von Ihrem set.
Ein Satz ist wahrscheinlich unpassend, wenn Sie definieren Gleichberechtigung in einem anderen Sinn als Bestellung. Gleichheit im set bedeutet im wesentlichen, dass die beiden element haben, die gleiche Stelle in sortierte Sequenz von Elementen.
std::unique erfordert die Elemente bereits sortiert, so dass gleiche Elemente nebeneinander liegen. Ich denke, diese Art von stellt sich die Frage, da das problem DeusAduro ist zu lösen versucht, ist, dass sein Kriterium für die Duplizierung nicht mit seiner Art um.
InformationsquelleAutor Paul
std::set
unterstützt, die eine Vergleichsfunktion angeben. Der Standardwert istless
dieoperator <
zu überprüfen Gleichheit. Sie können eine benutzerdefinierte Funktion definieren, um zu überprüfen, Gleichheit und verwenden, dass man statt:Beachten Sie, dass es nicht möglich ist, trennen Sie die Vergleich-Funktion von Sortier-Funktion.
std::set
ist ein binärer Baum, und wenn ein element in einem binären Baum ist nicht kleiner oder größer als ein spezifisches element ist, sollte es in der gleichen Stelle. Es tut sich etwas, wie dies in den Ort finding-Algorithmus:Die Vergleich-Funktion in der
set
template-Parameter ist ein kleiner-als-Vergleich in dem Fall die Dinge, an die man vergleicht, nicht schon so ein Vergleich-member-Funktion. Dies ist nicht eine Gleichheit test-Funktion. Siehe: sgi.com/tech/stl/set.htmlIn der Tat. Es verwendet das weniger als - Funktion sowohl für die Bestellung und als eine Nebenwirkung, die Gleichheit.
Das stimmt, und als Folge davon löst es nicht das problem bereits in der Frage. Alle es tut, ist, bewegen Sie die weniger-als Implementierung der Funktion an anderer Stelle.
Nein, tut es nicht. Dies liegt in der Natur der
set
Klasse. Ich glaube nicht, dass diese Daten-Struktur passt sich das problem (der Grund warum ich erwähnte im letzten Absatz).InformationsquelleAutor Mehrdad Afshari
rlbond der Komparator nicht verhindern, dass die Einfügung der Elemente, die im Vergleich gleich. Anscheinend ist es schwer zu beweisen, dies in den Kommentaren, angesichts der Zeichenbegrenzung, weil rlbond scheint denkt, dass std::set garantiert, dass es nie enthalten zwei Elemente mit
!compare(a,b) && !compare(b,a)
für seine Komparator. Allerdings rlbond der Komparator definiert nicht eine strenge Ordnung, und daher ist kein Gültiger parameter an std::set.Ausgabe:
Duplikate. Die Magie Komparator ist fehlgeschlagen. Verschiedene Elemente im set haben den gleichen Wert
equality
, und damit zu vergleichen, das gleiche mitoperator==
, weil beim einführen der Satz nie Vergleich des neuen Elementes auf seinen duplizieren. Die einzige doppelte, die ausgeschlossen wurde, war 4, da die zwei 4 hatte Sortierreihenfolgen 4 und 6. Diese legte Sie nahe genug zusammen, in der festgelegt werden miteinander verglichen.Aus der C++ - standard: 25.3:3 "Für die algorithmen korrekt arbeiten, comp hat zu veranlassen, eine strenge schwache Bestellung auf die Werte".
25.3:4 "... die Anforderungen sind, dass comp und equiv beide werden transitive Beziehungen:
Betrachten Sie nun die Elemente
a = BrokenOrder(1,1)
,b = BrokenOrder(2,2)
, undc = BrokenOrder(9,1)
, undcomp
natürlich gleich die Magie Komparator. Dann:comp(a,b)
ist wahr, da 1 != 2 (Gleichheit) und 1 < 2 (um)comp(b,c)
ist wahr, da 2 != 1 (Gleichheit) und 2 < 9 (Reihenfolge)comp(a,c)
ist falsch, da 1 == 1 (Gleichheit)Ich hatte nicht erwartet, dass Sie möchten, zu löschen, Ihre Antwort: was Sie sagen, über Einen* sah wirklich nützlich, da es zeigte, dass die OP nicht wirklich wollen, um das problem zu lösen, die er gestellt (d.h. er hat nicht wollen, Duplikate ausschließen, er wollte zu wählen das beste von Dubletten).
gut gemacht, eine der besten Erklärungen der strenge schwache Bestellung, die ich gelesen habe.
InformationsquelleAutor
Den STL-set-Umsetzung etwas tut im Prinzip wie das erkennen der Geschlechter:
Ist, wenn zwei Elemente sind beide nicht weniger als die anderen, dann müssen Sie gleich sein. Sie können in der Lage sein zu überprüfen, indem Sie einen Haltepunkt in Ihrem
operator==()
Methode und überprüfen, um zu sehen ob es überhaupt aufgerufen wird, auf allen.Ich würde generell misstrauisch sein Vergleichsoperatoren Sie, dass der check völlig verschiedene Dinge. Ihre
<
operator definiert ist, in Bezug auf zwei Dinge, die getrennt von dem, wie Ihr==
- operator definiert ist. In der Regel werden Sie wollen, solche Vergleiche zu verwenden konsistente Informationen.InformationsquelleAutor Greg Hewgill
Könnten Sie versuchen, etwas wie das folgende:
Ganz offensichtlich ist die Kopie in der Mitte, die sieht langsam. Aber jede Struktur, welche Indizes die Elemente von zwei verschiedenen Kriterien wird also eine Art extra-overhead pro Element verglichen mit einem Satz. Der ganze code oben ist O(n log n), vorausgesetzt, dass Ihre Implementierung von std::sort verwendet introsort.
Wenn Sie es haben, nach diesem Schema, die Sie nutzen könnten
unordered_set
stattset
zu tun, die ersten uniqueifying. Da der hash würde nur davon abhängen, x und y, es sollte schneller sein als die O(log N) Vergleiche benötigt, um einfügen in eine Gruppe.Edit: gerade bemerkt, dass Sie sagte, Sie wollte zu "halten" Sortierreihenfolge, nicht, dass Sie wollten Prozess alles in einer batch. Tut mir Leid, dass. Wenn Sie möchten, um effizient die Aufrechterhaltung der Ordnung und Duplikate ausschließen, während das hinzufügen von Elementen, dann würde ich empfehlen, mit der set-oder der ungeordnete, die ich oben definieren, basierend auf der position, und auch eine
std::multiset<RouteElem>
, die zur Aufrechterhaltung deroperator<
um. Für jedes neue element haben:Obwohl Bedenken Sie, dass diese Angebote keine Ausnahme-Garantie. Wenn die zweite insert wirft, dann die routeset wurde so verändert, dass der Staat nicht mehr konsistent. Also ich denke wirklich du brauchst:
Oder ein äquivalent mit RAII, welches Ausführlicher ist, ob es nur eine Stelle im code, die Sie jemals verwenden Sie die RAII-Klasse, aber besser, wenn es viel Wiederholung.
Zur gleichen Zeit, die Einführung eines linear-array-ich denke, ich kann es besser machen. Eine insert-operation muss zunächst prüfen, für doppelte, gegeben, dass die sortierte Reihenfolge nicht direkt mit der "duplizieren" - Kriterien muss dies O(n). Wenn das element nicht in der Liste müssen wir nun die entsprechende position (binäre Suche -> O(log n). Also ist die Gesamtzeit O(n + log n) + im schlimmsten Fall O(n) verschiebt.
Vielleicht habe ich falsch, was Sie vorgeschlagen sind, aber wenn jeder insert-operation beinhaltet einen O(n) doppelte, dann die Summe ist O(n^2), da gibt es n Elemente einfügen.
Vielleicht seinen mein Missverständnis von Big O-notation. Aber wenn meins ist O(n^2) per definition dann habt Ihr so gut, zumindest in meiner Verwendung. Grundsätzlich füge ich ein einzelnes element in die Liste ein, nach denen Sie sortiert werden muss. Also mit der Implementierung vor ich wäre die Umwandlung in s/w-set und vector für jede operation, so hätten wir O(n^2) - Kopie-Operationen für n Elemente. Obwohl ja die oben genannten Umsetzung ist besser, wenn ich war, um alle Elemente in einem einzigen Punkt, dann tun Sie das kopieren/Sortieren nur einmal.
Es war mir, wer war verwirrt über diesen Punkt, du hast ganz Recht, dass mein Erster Vorschlag ist Müll für die Erhaltung der Art über mehrere separate insert-Operationen. Ich glaube, ich habe es angesprochen, jetzt in einem edit. Mein Big-O war für das einsetzen aller n Elemente, deiner war zum einlegen 1. Mein neuer Vorschlag ist O(log N) für einfügen eines neuen Elements bei gleichzeitiger Ablehnung von Duplikaten und die Aufrechterhaltung der Ordnung, sondern benutzt fast doppelt so viel Speicher als einen einzigen container.
InformationsquelleAutor Steve Jessop
Hüten Sie sich vor den Auswirkungen dieser. Es sieht aus wie Sie versuchen, etwas zu tun, wie Ein* und wenn Sie versuchen, fügen Sie eine "doppelte" er wird ignoriert werden, selbst wenn es eine "bessere" route.
HINWEIS: Diese Lösung funktioniert nicht, siehe onebyone Erklärung unten
Ich Stimme mit onebyone hier, wie einige der anderen Plakate erwähnt, gegeben, dass die Satz ist ein Baum, der intern die entsprechenden Elemente verloren. So weit wie dein letzter Satz geht, ich bin dabei Eine*. Ich bin mir nicht sicher, ob ich dem Folgen, was Sie sagen. Es klingt wie Sie sagen, dass, wenn ich ein "duplizieren", um die Liste öffnen, das ist nicht ein Problem? Das würde die Dinge einfacher für Sie sicher, dass... könnten Sie das noch näher erläutern?
Blick auf den Vergleich funktors verwendet wird.
wenn Sie versuchen, Eine*, du machst es falsch. Sie wollen die std::priority_queue-Adapter für die open set und std::set für die geschlossene Gruppe. Dann nehmen Sie das oberste element der open set; wenn Sie in die geschlossene Gruppe schon, es zu entsorgen, ansonsten verarbeiten. Das problem ist, dass die Regeln für Eine* sagt, dass in der open-set, bereits vorhandenen Knoten ERSETZT werden soll, durch diejenigen, die mit besseren g-Werte (oder was dasselbe ist, f-Werte). Wenn du std::set, "schlechter" - Strecken werden niemals durch bessere abgelöst werden.
Es gibt andere Möglichkeiten, es zu tun mit einem std::set, aber eine priority queue ist viel einfacher IMO. Sie sollten in der Lage sein, es zu tun in rund 30-40 Zeilen für die wichtigsten Körperfunktionen mit priority_queue.
InformationsquelleAutor rlbond