Элемент по индексу в 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!
}

Что-нибудь, что я могу сделать, чтобы исправить проблему?

Ответ 1

Это не вызывает сбой, он просто не компилируется. set не имеет доступа по индексу.

Вы можете получить n-й элемент следующим образом:

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

Предполагая my_set.size() > n, конечно. Вы должны знать, что эта операция занимает время, приблизительно пропорциональное n. В С++ 11 есть более удобный способ записи:

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

Опять же, вы должны знать, что n находится в первых пределах.

Ответ 2

Обычная реализация std:: set заключается в использовании двоичный поиск деревья, особенно самобалансирующиеся двоичные деревья поиска, такие как red -черные деревья

Они не дают вам постоянного доступа к n-му элементу. Тем не менее, вы, кажется, хотите первого. Поэтому попробуйте C++11:

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

Ответ 3

Это не ошибка в STD. В std::set нет произвольного доступа. Если вам нужен произвольный доступ по индексу, вы можете использовать std::vector

Ответ 4

Иногда есть веская причина для необходимости набора, в который вы можете индексировать. Мне пришлось реализовать эту функцию недавно, чтобы поддерживать устаревший 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 не равен range.second, удалите этот диапазон.

Ответ 5

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

Изменить: Отредактированный код. Вы не можете получить доступ к набору с использованием индекса, но указанный выше метод обеспечит "индекс" i, если вы хотите скопировать элементы из набора в массив, если вы создали массив достаточного размера перед началом работы.