web-dev-qa-db-ja.com

std :: setのインデックスの要素?

この問題に出くわしました。通常のstd::setのインデックスの位置にあるアイテムを選択できないようです。これはSTDのバグですか?

以下に簡単な例を示します。

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

問題を解決するためにできることはありますか?

24
hauron

それはクラッシュを引き起こさず、単にコンパイルしません。 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が最初に境界内にあることを知っておく必要があります。

58
Steve Jessop

std :: set の通常の実装は、 binary search trees を使用することです。特に red-balancing binary search trees など red -黒い木

これらは、n番目の要素への一定時間のアクセスを提供しません。しかし、あなたは最初のものが欲しいようです。 C++ 11 で試してください:

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

インデックスを作成できるセットが必要な理由がある場合があります。呼び出し元がアイテムを列挙できるように、アイテムの数とインデックスのアイテムを返す機能を備えたレガシーAPIをサポートするために、最近この機能を実装する必要がありました。

問題を解決する私の方法は、std :: vectorを使用し、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がnot range.secondと等しい場合、その範囲を削除します。

0
Graham Asher

一定の時間でアクセスできる方法はありません。

ただし、O(n)時間で任意の要素に到達できます。

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

これはSTDのバグではありません。 std::setにはランダムアクセスはありません。インデックスによるランダムアクセスが必要な場合は、std::vectorを使用できます

0
José D.