2009-07-11 3 views
35

Ich habe eine Std :: Map, die ich verwende, um Werte für x & y-Koordinaten zu speichern. Meine Daten sind sehr spärlich, daher möchte ich keine Arrays oder Vektoren verwenden, was zu einer enormen Speicherverschwendung führen würde. Meine Daten reichen von -250000 bis 250000, aber ich habe höchstens ein paar tausend Punkte.Was ist der beste Weg, um zwei Schlüssel mit einer std :: map zu verwenden?

Momentan erstelle ich eine std :: string mit den zwei Koordinaten (zB "12x45") und benutze sie als Schlüssel. Dies scheint nicht der beste Weg zu sein.

Meine anderen Gedanken waren die Verwendung eines Int64 und schieben Sie die beiden Int32s hinein und verwenden Sie es als Schlüssel.

Oder eine Klasse mit den zwei Koordinaten zu verwenden. Was sind die Anforderungen an eine Klasse, die als Schlüssel verwendet werden soll?

Was ist der beste Weg, dies zu tun? Ich würde lieber keine Karte von Karten verwenden.

+0

Sie könnte leicht und berechtigterweise zwei Long-Positionen in eine _int64 stopfen, oder wie in meiner Antwort unten, eine Seriennummer, PID, und NodeId. Da MAX_PID (1 << 22) unter Linux ist, hinterlässt dies tatsächlich 64 - (32 + 22) für die NodeId, die 10 Bits ist und einen beliebigen Wert bis (1 << 10) IE enthält: 1024 – RocketRoy

+0

Angenommen, Sie tun Wenn Sie die Map nicht in einer bestimmten Reihenfolge durchlaufen möchten, verwenden Sie eine Hash-Map wie std :: unordered_map. Viel effizienter, besonders wenn Sie so viele Werte haben. – hyde

Antwort

96

Verwendung std :: pair < int32, int32> für den Schlüssel:

std::map<std::pair<int,int>, int> myMap; 

myMap[std::make_pair(10,20)] = 25; 
std::cout << myMap[std::make_pair(10,20)] << std::endl; 
+4

ein Paar funktioniert, ist aber generisch. Vielleicht ist es eine gute Idee, einen benutzerdefinierten Typ zu definieren, der ausdrückt, was das Paar wirklich meint, kartesische Koordinaten oder was auch immer. – bames53

+2

@ bames53 Das Hauptproblem dabei ist, dass Sie dann einen Vergleichsoperator für den neuen Typ implementieren müssen, der möglicherweise keinen Sinn ergibt, wenn Sie nur die Eindeutigkeit sicherstellen möchten. –

+0

Wusste noch nicht mal, dass es Überladungen der Vergleichsoperatoren für std :: pair gibt. – zett42

3

-Boost hat eine Karte Container, der einen oder mehrere Indizes verwendet.

Multi Index Map

+0

Dies kann auch mit Boost-Tupeln erreicht werden. – Frizi

25

ich diese Art von Problem, wie dies in der Regel lösen:

struct Point 
{ 
    Point() : x(), y() {} 
    Point(int x, int y) : x(x), y(y) {} 
    int x, y; 
}; 

bool operator<(const Point & lhs, const Point & rhs) // lhs = left-hand side 
                 // rhs = right-hand side 
{ 
    if (lhs.x != rhs.x) 
    { 
     return lhs.x < rhs.x; 
    } 
    else 
    { 
     return lhs.y < rhs.y; 
    } 
} 

int main() 
{ 
    Point p1(0, 1); 
    Point p2(0, 2); 
    std::map<Point, std::string> mapping; 
    mapping[p1] = "p1"; 
    mapping.insert(std::make_pair(p2, "p2")); 
} 
+8

Dies ist explizit, das ist gut. Beachten Sie, das ist das gleiche wie 'typedef std :: pair Punkt;' – GManNickG

+9

Heh, bis jetzt wusste ich nicht, dass std :: pair hat operator StackedCrooked

+2

@GManNickG mit Ausnahme der Schnittstelle von 'x' und' y', die 'first' und' second' für ein 'std :: pair' ist. – rubenvb

5

Was sind die Voraussetzungen für eine Klasse, die als Schlüssel verwendet werden soll?

Die Karte muss in der Lage zu sagen, ob ein Schlüssel des Wert kleiner als ein anderer Wert des Schlüssels: Standardmäßig bedeutet dies, dass (key1 < key2) muss eine gültige boolean Ausdruck sein, dh, dass der Schlüsseltyp das Gerät sollte "weniger als" Betreiber.

Die Map-Vorlage implementiert auch einen überladenen Konstruktor, mit dem Sie einen Verweis auf ein Funktionsobjekt vom Typ key_compare übergeben können, das den Vergleichsoperator implementieren kann: Alternativ kann der Vergleich als eine Methode dieser externen Funktion implementiert werden Objekt, statt in jedem Typ gebacken zu werden, aus dem dein Schlüssel besteht.

+0

Eine weitere Voraussetzung ist, dass der Schlüssel konstant sein muss und – Emiliano

0

Verwenden Sie std :: pair. Verwenden Sie besser QHash<QPair<int,int>,int>, wenn Sie viele solcher Zuordnungen haben.

0

In erster Linie, ziehen Sie die Saite und verwenden Sie 2 Ints, die Sie jetzt möglicherweise getan haben. Kudos, um herauszufinden, dass ein Baum der beste Weg ist, eine spärliche Matrix zu implementieren. Normalerweise scheint es ein Magnet für schlechte Implementierungen zu sein.

FYI, ein Dreifach-Verbundschlüssel funktioniert auch, und ich nehme auch ein Paar Paare an.

Es macht für einige hässliche Sub-Scripting obwohl, so ein wenig Makro Magie wird Ihr Leben leichter machen. Ich habe diesen allgemeinen Zweck verlassen, aber die Argumente im Makro zu schreiben ist eine gute Idee, wenn Sie Makros für bestimmte Karten erstellen. Die TresKey12 ist getestet und läuft gut. QuadKeys sollte auch funktionieren.

HINWEIS: Solange Ihre Schlüsselteile grundlegende Datentypen sind, brauchen Sie NICHT mehr zu schreiben. AKA, keine Notwendigkeit, sich über Vergleichsfunktionen zu ärgern. Die STL hat dich abgedeckt. Codiere es einfach und lass es krachen.

using namespace std; // save some typing 
#define DosKeys(x,y)  std::make_pair(std::make_pair(x,y)) 
#define TresKeys12(x,y,z) std::make_pair(x,std::make_pair(y,z)) 
#define TresKeys21(x,y,z) std::make_pair(std::make_pair(x,y),z)) 

#define QuadKeys(w,x,y,z) std::make_pair(std::make_pair(w,x),std::make_pair(y,z)) 


map<pair<INT, pair<ULLNG, ULLNG>>, pIC_MESSAGE> MapMe; 
MapMe[TresKey12(Part1, Part2, Part3)] = new fooObject; 

Wenn jemand will, um mich beeindrucken, zeigt mir, wie einen Operator vergleichen zu machen für TresKeys, die nicht auf Brutpaare angewiesen ist, damit ich ein einziger struct mit 3 Mitgliedern nutzen kann und eine Vergleichsfunktion verwenden.

PS: TresKey12 gab mir Probleme mit einer Karte als Paar deklariert, z wie es x macht, paar, und diese beiden nicht schön spielen. Kein Problem für DosKeys oder QuadKeys. Wenn es aber ein heißer Sommer Freitag ist, können Sie eine unerwartete Nebenwirkung der Eingabe in DosEquis finden ... ähm .. DosKeys ein paar Mal, ist ein Durst nach mexikanischen Bier. Vorbehalt Emptor. Wie Sheldon Cooper sagt: "Was ist das Leben ohne Laune?".

+4

Das ist hübsch hässlich. Warum ein Makro für was sollte eine Funktion sein? Und das ist viel zu viele verschachtelte Paare. Um Ihre Frage zu beantworten, wie Sie es lösen können: 'struct location {int x, y, z; }; bool operator <(konstante Position & lhs, konstante Position & rhs) {return std :: Bindung (lhs.x, lhs.y, lhs.z) GManNickG

+2

@GManNickG, danke für die Antwort. Werde es versuchen und melden. Ja, dieser Typ wird lächeln, wenn das klappt! – user2548100

+0

@GManNickG, Kompiliert das nicht ganz. Ich werde es hier in VS 2012 C++ fuzz machen. Wahrscheinlich funktioniert es, aber wenn du eine Minute übrig hast, poste vielleicht etwas, das kompiliert wird? TVMIA – user2548100

1

Dies stopft mehrere Integer-Schlüssel in eine große Ganzzahl, in diesem Fall ein _int64. Es vergleicht als _int64, AKA long long (Die hässlichste Typdeklaration überhaupt. Kurz kurz kurz kurz, wäre nur etwas weniger elegant. Vor 10 Jahren hieß es vlong. Viel besser. So viel zum "Fortschritt"), also kein Vergleich Funktion ist erforderlich.

#define ULNG unsigned long 
#define BYTE unsigned char 
#define LLNG long long 
#define ULLNG unsigned long long 

// -------------------------------------------------------------------------- 
ULLNG PackGUID(ULNG SN, ULNG PID, BYTE NodeId) { 
    ULLNG CompKey=0; 

    PID = (PID << 8) + NodeId; 
    CompKey = ((ULLNG)CallSN << 32) + PID; 

    return CompKey; 
} 

diese Antwort gegeben hat, ich bezweifle, dass dies für Sie arbeiten wird, wie Sie zwei getrennte und unterschiedliche Schlüssel müssen mit

in 2 Dimensionen, X und Y.

Auf der anderen Seite navigieren, Wenn Sie bereits die XY-Koordinate haben und nur einen Wert mit diesem Schlüssel verknüpfen möchten, dann funktioniert dies auf spektakuläre Weise, da ein _int64-Vergleich die gleiche Zeit wie jeder andere Ganzzahlvergleich auf Intel X86-Chips benötigt - 1 Takt.

In diesem Fall ist der Vergleich 3X so schnell auf diesem synthetischen Schlüssel, verglichen mit einem Dreifachverbindungsschlüssel.

Wenn Sie dies verwenden, um ein dünn besiedeltes Arbeitsblatt zu erstellen, würde ich RX mit zwei verschiedenen Bäumen verwenden, von denen der eine ineinander verschachtelt ist. Machen Sie die Y-Dimension zum "Boss" und suchen Sie zuerst in Y-Raum nach der Auflösung, bevor Sie zur X-Dimension weitergehen. Kalkulationstabellen sind größer als breit und Sie möchten immer, dass die erste Dimension in einem zusammengesetzten Schlüssel die größte Anzahl eindeutiger Werte aufweist.

Diese Anordnung würde eine Zuordnung für die Y-Dimension erstellen, die eine Zuordnung für die X-Dimension als Daten hätte. Wenn Sie zu einem Blatt in der Y-Dimension gelangen, beginnen Sie mit der Suche nach seiner X-Dimension für die Spalte in der Kalkulationstabelle.

Wenn Sie ein sehr leistungsfähiges Tabellenkalkulationssystem erstellen möchten, fügen Sie auf dieselbe Weise eine Z-Dimension hinzu und verwenden Sie diese beispielsweise für Organisationseinheiten. Dies ist die Grundlage für ein sehr leistungsfähiges Budgetierungs-/Prognostizierungs-/Buchhaltungssystem, das es Admin-Einheiten ermöglicht, viele detaillierte Konten zu haben, um Verwaltungskosten und dergleichen zu verfolgen, und diese Konten nicht Platz für Linieneinheiten nehmen, die ihre eigenen Arten haben Details zu verfolgen.

+2

Ich glaube, zwei Longs in ein _int64 stopfen, vorausgesetzt, das High Long ist Y, und Low Long ist X, wird Y-Raum zuerst suchen, und dann X-Raum, wie alle Werte mit der gleichen hohen Long (gleicher Y-Wert) gleich sein wird , lassen Sie die niedrige lange (X-Raum), um die Krawatte zu brechen. – user2548100

-1

Hoffe, dass Sie es nützlich finden werden:

map<int, map<int, int>> troyka = { {4, {{5,6}} } }; 
troyka[4][5] = 7; 
+0

OP sagt, er würde lieber keine Karte von Karten verwenden, daher ist diese Antwort nicht sehr hilfreich. Darüber hinaus können einige Erläuterungen des Codes für andere hilfreich sein, um Ihre Lösung zu verstehen. Tut mir leid, wenn ich mich zu sehr beschwere, aber Sie haben eine sehr alte Frage von 2009 beantwortet, die bereits eine Antwort mit vielen Upvotes hat. Es ist also sehr unwahrscheinlich, dass Ihre Antwort etwas Neues oder noch Besseres als die angenommene Antwort liefert. – zett42

Verwandte Themen