Можно ли получить один элемент набора в C++ STL?
У меня есть следующий код C++ с вектором C++ STL,
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
vector <int> v;
for (int i=0; i<15; i++)
v.push_back (i);
cout << v[10] << endl;
return 0;
}
Обычно он печатает элемент, который хранится в 10-м индексе. Выход будет 10.
Но я попробовал то же самое с набором C++ STL,
#include <iostream>
#include <set>
using namespace std;
int main ()
{
set <int> myset;
for (int i=0; i<15; i++)
myset.insert (i);
cout << myset[10] << endl;
return 0;
}
Это дает мне ошибку компиляции, показывая следующие сообщения:(
prog.cpp: в функции 'int main()':
prog.cpp: 12: 18: ошибка: нет совпадения для 'operator[]' (типы операндов: 'std:: set' и 'int') cout << myset[10] << endl;
Итак, мой вопрос: есть ли способ напечатать какой-либо элемент наборов STL, аналогично векторам STL в C++? если да, то как?
Между тем мы можем использовать итераторы, но, насколько я знаю, они могут работать с полным набором.:)
4 ответа
Да, это возможно, но не используя operator[]
,
std::set
не обеспечивает operator[]
поскольку это не контейнер с произвольным доступом. Вместо этого нужно использовать итераторы для доступа к его элементам.
auto first = myset.begin(); // get iterator to 1st element
std::advance(first, 9); // advance by 9
std::cout << *first; // 10th element
Обратите внимание, что std::set
является заказанным контейнером, и элементы не будут отображаться в том порядке, в котором вы их вставили.
Вы не можете получить доступ к элементам набора по индексу. Однако вы можете использовать std::advance
на итераторе.
set<int>::iterator it = myset.begin();
std::advance(it, 5); // advanced by five
std::next
также есть в C++11
,
auto it = std::next(myset.begin(), 5);
Разница между этими двумя версиями объясняется здесь: в чем разница между std::advance и std::next?
Проблема в том, что наборы не имеют доступа по индексу. но вы все еще можете сделать что-то вроде:
set<int>::iterator myIterator = myset.begin();
advance(myIterator , 9);
int theTenth= *myIterator;
который в основном получает интегратор и "продвигает его" вперед на 9 мест...
Вы не можете сделать это в чистом C++, но если вы используете GCC (и вы, вероятно, делаете это, основываясь на своей ошибке компиляции), вы можете создать набор на основе политик, который ведет себя как обычный набор STL, но поддерживает операцию, о которой вы спрашивали.
#include <iostream>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> indexed_int_set;
int main ()
{
indexed_int_set myset;
for (int i=0; i<15; i++)
myset.insert (i);
cout << *myset.find_by_order(10) << endl;
return 0;
}
В приведенном выше коде мы определяем структуру под названием indexed_int_set
, который имеет 2 дополнительных метода: find_by_order(int p)
а также order_of_key(int k)
, Первый - это то, что вы хотите, он возвращает итератор в p-й элемент. Второй похож на lower_bound, но возвращает итератор вместо индекса.