2013-12-09 16 views
16

Ich bin über dieses Problem gestolpert: Ich kann nicht scheinen, das Einzelteil an der Indexposition in einem normalen std :: set auszuwählen. Ist das ein Fehler in STD?Element am Index in einem Std :: Set?

Im Folgenden ein einfaches Beispiel:

#include <iostream> 
#include <set> 

int main() 
{ 
    std::set<int> my_set; 
    my_set.insert(0x4A); 
    my_set.insert(0x4F); 
    my_set.insert(0x4B); 
    my_set.insert(0x45); 

    for (std::set<int>::iterator it=my_set.begin(); it!=my_set.end(); ++it) 
     std::cout << ' ' << char(*it); // ups the ordering 

    //int x = my_set[0]; // this causes a crash! 
} 

Alles, was ich tun kann, um das Problem zu beheben?

+4

'my_set [0]' sollte nicht kompilieren. – chris

+2

Sie stellen die falsche Frage, weil Sie den falschen Container verwenden. Jeder Standardcontainer wurde mit einer bestimmten Anzahl von Verwendungszwecken entworfen und lässt andere (direkt) nicht zu. Also, zuerst müssen Sie identifizieren, welche Operationen Sie benötigen, und dann [wählen Sie den richtigen Container] (http://stackoverflow.com/questions/10699265/how-can-i-efficiently-select-a-standard-library- container-in-c11/10701102 # 10701102) –

+0

Mögliches Duplikat von [Element aus beliebigem Index in Menge holen] (http: // stackoverflow.com/questions/8907435/get-element-von-arbitrary-index-in-set) –

Antwort

39

Es verursacht keinen Absturz, es kompiliert nur nicht. set hat keinen Zugriff per Index.

Sie können das n-te Element wie diese:

std::set<int>::iterator it = my_set.begin(); 
std::advance(it, n); 
int x = *it; 

my_set.size() > n Unter der Annahme, natürlich. Sie sollten sich bewusst sein, dass diese Operation ungefähr proportional zu n dauert. In C++ 11 gibt es eine schönere Art und Weise des Schreibens:

int x = *std::next(my_set.begin(), n); 

Auch hier müssen Sie wissen, dass n zuerst in Grenzen liegt.

+0

Natürlich, wenn OP erwartete 'my_set [0]', um '0x4A' zurückzugeben, wird dies immer noch nicht tun, was gewünscht wird. – Useless

+3

@Useless: wahr. Aber wenn sie erwarten, dass der erste Wert der Schleife früher in ihrem Code zurückgegeben wird, dann sind sie gut. Im Allgemeinen, wenn der Fragesteller nicht weiß, was ein 'Set' ist, werden sie eine Reihe von überraschenden Ergebnissen sehen, bis sie schließlich aufgeben und RTFM; -p –

+0

Verzeihen Sie mir dafür, aber die Frage sollte sein ein Witz (die Werte sind ASCII-Hex-Codes für "JOKE", Gedankensatz ist ungeordnet, daher ergibt Iterieren nicht das gleiche Ergebnis). Allerdings wusste ich nicht über Std :: Advance oder Std :: Next, also vielen Dank für das Teilen! – hauron

4

Eine übliche Implementierung von std::set ist binary search trees zu verwenden, insbesondere self-balancing binary search trees wie red-black trees

Sie haben nicht Sie konstante Zeit Zugriff auf das n-te Element geben. Sie scheinen jedoch das erste zu wollen. So versuchen Sie in C++11:

auto it = my_set.begin(); 
int first=0; 
if (it != my_set.end()) first = *it; 
+0

Danke für die Antwort - Entschuldigung dafür - Scherzfrage. Von C++ 11 scheint Ihr Code jedoch nur die neue Bedeutung von "auto" zu haben. – hauron

0

Dies ist kein Fehler in der STD. In einem std::set gibt es keinen wahlfreien Zugriff. Wenn Sie einen wahlfreien Zugriff per Index benötigen, können Sie std::vector

+1

Nun, da ist es. Standardmäßig verwendet es 'std :: less', um Dinge zu sortieren. – chris

+0

Sie haben Recht, ich dachte an 'std :: unordered_set'. Bearbeitet –

+1

Der Auftrag ist nicht implementierungsabhängig. Wie Chris sagt, verwendet es 'std :: less', wenn nicht anders angegeben, was im Fall von' int' nur eine phantastische Art ist, '<' zu sagen. –

0

verwenden. Manchmal gibt es einen guten Grund, ein Set zu brauchen, in das Sie sich einschreiben können. Ich musste diese Funktionalität kürzlich implementieren, um eine Legacy-API zu unterstützen, die Funktionen zum Zurückgeben der Anzahl von Elementen und das Element zu einem Index aufweist, so dass der Aufrufer die Elemente aufzählen kann.

Meine Weise, das Problem zu lösen, ist, std :: vector zu benutzen und std :: equal_range zu verwenden, um Einzelteile in der Menge zu finden und zu löschen oder einzufügen. Zum Beispiel sieht wie folgt ein neues Element in den Satz einfügen:

std:vector<std::string> my_set; 

    ... 

    std::string new_item("test"); 

    auto range = std::equal_range(my_set.begin(),my_set.end(),new_item); 
    if (range.first == range.second) 
     my_set.insert(range.first,new_item); 

Löschen ist sehr ähnlich: Verwenden Sie equal_range das Element zu finden, und wenn range.first nicht gleich range.second ist, löschen Sie, dass Angebot.

-2
std::set<int> my_set; 
    my_set.insert(0x4A); 
    my_set.insert(0x4F); 
    my_set.insert(0x4B); 
    my_set.insert(0x45); 

    int arr[my_set.size()]; 

    set<int>::iterator it = my_set.begin(); 
    for (int i = 0; i < my_set.size(); i++) { 
    arr[i] = *it; 
    it++; 
    } 
    cout << arr[0]; 

Bearbeiten: Bearbeiteter Code. Sie können nicht mit Index auf set zugreifen, aber die obige Methode würde einen "Index" i liefern, wenn Sie die Elemente aus einem Set in ein Array kopieren möchten, vorausgesetzt, Sie haben zuvor ein Array ausreichender Größe erstellt.

+0

Wie beantwortet das die Frage? Sie durchlaufen das Set nur auf eine etwas andere Art und Weise. – cpburnz

+0

@cpburnz Keine der anderen Antworten hat eine Menge mit einem Index iteriert. Es gibt eine Verwendung für das Iterieren eines Satzes mit Index, wie in meinem Beispiel gezeigt. – katta

Verwandte Themen