关于c ++:std :: set中索引处的元素?

Element at index in a std::set?

我偶然发现了这个问题:我似乎无法在普通std::set中的索引位置选择项目。 这是STD中的错误吗?

下面是一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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!
}

我可以采取什么措施解决此问题?


它不会导致崩溃,只是不会编译。 set没有按索引的访问权限。

您可以这样获得第n个元素:

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

当然,假设my_set.size() > n。您应该注意,此操作花费的时间大约与n成比例。在C ++ 11中,有一种更好的编写方式:

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

同样,您必须知道n首先是界。


std :: set的通常实现是使用二进制搜索树,尤其是自平衡二进制搜索树,例如红黑树。

它们不能让您恒定时间访问第n个元素。但是,您似乎想要第一个。因此,请尝试在C ++ 11中:

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


您无法在恒定时间内访问它。

但是您可以在O(n)时间内到达任何元素。
例如。

1
2
3
4
std::set<int>::iterator it;
it=my_set.begin();
advance(it,n);
cout<<*it;

有时,有充分的理由需要您可以索引的集合。最近,我必须实现此功能以支持旧版API,该API具有返回项数和索引项的功能,以便调用者可以枚举项。

解决问题的方法是使用std :: vector,并使用std :: equal_range查找和插入或删除集合中的项目。例如,将新项目插入到集合中看起来像这样:

1
2
3
4
5
6
7
8
9
    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,则删除该范围。


这不是STD中的错误。 std::set中没有随机访问。如果需要按索引随机访问,则可以使用std::vector


1
2
3
4
5
6
7
8
9
10
11
12
13
14
  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];

编辑:编辑的代码。您无法使用索引访问集合,但是如果您想事先将集合中的元素复制到数组中,则上述方法将提供一个"索引",前提是您已事先创建了足够大的数组。