Если важен произвольный доступ, и вы можете прожить со средним усилием O (N) для вставки, то обходной путь, приведенный в в этом документе , может быть удобен.
Основная идея заключается в том, чтобы использовать отсортированный вектор, а затем для поиска функцию std::lower_bound
. Это, поиск принимает O (log N) так же, как в обычном наборе. Кроме того, (случайная) вставка занимает O (N), поскольку все последующие элементы должны быть сдвинуты так же, как и в нормальном векторе (и, возможно, выполняется перераспределение). Однако вставка сзади постоянна (за исключением перераспределения. Этого можно избежать, вызвав reserve()
с достаточно большим хранилищем).
Наконец, основной вопрос: произвольный доступ - это O (1). Просто нарисуйте случайное число i
из равномерного распределения в [0, V.size()-1]
и верните соответствующий элемент V[i]
.
Вот кодовая база из бумаги, которая реализует этот отсортированный вектор. Расширьте его по мере необходимости:
template <class T, class Compare = std::less<T> >
struct sorted_vector {
using std::vector;
using std::lower_bound;
vector<T> V;
Compare cmp;
typedef typename vector<T>::iterator iterator;
typedef typename vector<T>::const_iterator const_iterator;
iterator begin() { return V.begin(); }
iterator end() { return V.end(); }
const_iterator begin() const { return V.begin(); }
const_iterator end() const { return V.end(); }
//...if needed, implement more by yourself
sorted_vector(const Compare& c = Compare()) : V(), cmp(c) {}
template <class InputIterator>
sorted_vector(InputIterator first, InputIterator last, Const Compare& c = Compare())
: V(first, last), cmp(c)
{
std::sort(begin(), end(), cmp);
}
//...
iterator insert(const T& t) {
iterator i = lower_bound(begin(), end(), t, cmp);
if (i == end() || cmp(t, *i))
V.insert(i, t);
return i;
}
const_iterator find(const T& t) const {
const_iterator i = lower_bound(begin(), end(), t, cmp);
return i == end() || cmp(t, *i) ? end() : i;
}
};
Для более сложной реализации, вы также можете рассмотреть эту страницу .
РЕДАКТИРОВАТЬ: или, что еще лучше, использовать boost::container::flat_set
, который реализует набор с использованием идеи, описанной выше, то есть в качестве отсортированного вектора.