2013-12-09 33 views
16

我已經偶然發現了這個問題:我似乎無法在正常的std :: set的索引位置選擇該項目。這是STD中的錯誤嗎?在一個std :: set的索引處的元素?

下面一個簡單的例子:

#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! 
} 

什麼我可以做些什麼來解決這個問題?

+4

'my_set [0]'不應該編譯。 – chris

+2

您在問錯誤的問題,因爲您使用的是錯誤的容器。每個標準容器的設計都考慮到了一定的用途,反過來又不允許其他用戶(直接)使用。所以,首先,你需要確定你需要什麼操作,然後[選擇合適的容器](http://stackoverflow.com/questions/10699265/how-can-i-efficiently-select-a-standard-library- container-in-c11/10701102#10701102) –

+0

[從集合中的任意索引獲取元素](http:// stackoverflow。com/questions/8907435/get-element-from-arbitrary-index-in-set) –

回答

39

它不會導致崩潰,它只是不編譯。 set沒有按索引訪問。

你可以得到的第n個元素是這樣的:

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

假設my_set.size() > n,當然。您應該意識到此操作需要大約與n成比例的時間。在C++ 11有寫它的一個更好的方式:

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

同樣,你要知道,n是在界限第一。

+0

當然,如果OP期望'my_set [0]'返回'0x4A',這仍然不會做任何想要的事情。 – Useless

+3

@Useless:true。但是如果他們期望它在代碼中早先返回循環中的第一個值,那麼它們就很好。一般來說,如果提問者不知道'set'是什麼,他們將看到一系列令人驚訝的結果,直到他們最終放棄並RTFM; -p –

+0

請原諒我,但問題應該是一個笑話(值爲「JOKE」的ASCII十六進制代碼,思想集是無序的,因此迭代不會產生相同的結果)。 但是,我不知道std :: advance或std :: next,所以感謝分享! – hauron

4

一個通常的實現的std::set是使用binary search trees,特別是self-balancing binary search treesred-black trees

他們不會給你的第n個元素不變時間訪問。但是,你似乎想要第一個。所以試試C++11

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

謝謝你對此的回答 - 對不起 - 笑話問題。但是,從C++ 11開始,您的代碼似乎只是採用了'auto'的新含義。 – hauron

0

這不是性病的bug。 std::set中沒有隨機訪問。如果您需要通過索引隨機訪問,你可以使用std::vector

+1

好吧,有。默認情況下,它使用'std :: less'來排序。 – chris

+0

你說得對,我正在考慮'std :: unordered_set'。編輯 –

+1

訂單不依賴於實施。正如克里斯所說,除非另有說明,否則它使用'std :: less',在'int'的情況下,這只是說'''的一種奇特方式。 –

0

有時候有需要爲一組,你可以索引到一個很好的理由。我最近必須實現這個功能來支持一個遺留的API,它具有返回項目數量和索引項目的功能,以便調用者可以枚舉項目。

我解決這個問題的方法是在集中使用的std ::向量,並使用std :: equal_range找到並插入或刪除項目。例如,將一個新的項目進入設置如下:

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

刪除非常相似:用equal_range尋找項目,如果range.first是等於range.second,刪除範圍。

-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]; 

編輯:編輯的代碼。你不能使用索引來訪問set,但是如果你想將set中的元素複製到一個數組中,只要你事先創建了一個足夠大小的數組,那麼上面的方法將提供一個「索引」。

+0

這是如何回答這個問題的?你只是以略微不同的方式遍歷集合。 – cpburnz

+0

@cpburnz其他答案的非其他答案與索引迭代一個集合。如我的示例中所示,有一個使用索引迭代集合的用法。 – katta

相關問題