Nếu truy cập ngẫu nhiên là quan trọng và bạn có thể sống với nỗ lực trung bình O (N) để chèn, thì cách giải quyết được đưa ra trong this paper có thể thuận tiện.
Ý tưởng chính là sử dụng một véc tơ được sắp xếp, và sau đó để tra cứu hàm std::lower_bound
. Điều này, tra cứu lấy O (log N) giống như trong một tập bình thường. Hơn nữa, (ngẫu nhiên) chèn lấy O (N), vì tất cả các phần tử sau đây phải được dịch chuyển giống như trong một vectơ bình thường (và có thể một sự tái phân bổ được thực hiện). Tuy nhiên, chèn ở phía sau là hằng số (ngoại trừ việc phân bổ lại. Bạn có thể tránh điều này bằng cách gọi số reserve()
với bộ nhớ đủ lớn).
Cuối cùng, điểm chính của câu hỏi: Truy cập ngẫu nhiên là O (1). Chỉ cần vẽ một số ngẫu nhiên i
từ phân phối đồng đều trong [0, V.size()-1]
và trả về phần tử tương ứng V[i]
.
Đây là cơ sở mã trên giấy, thực hiện vectơ được sắp xếp này. Hãy mở rộng nó khi cần:
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;
}
};
Để thực hiện tinh vi hơn, bạn cũng có thể xem xét this page.
CHỈNH SỬA: hoặc thậm chí tốt hơn, sử dụng boost::container::flat_set
, triển khai tập hợp bằng cách sử dụng ý tưởng ở trên, tức là vectơ được sắp xếp.
Hãy cẩn thận khi sử dụng mô đun (%) trong việc tạo số ngẫu nhiên, phân phối có thể không chính xác ngay cả (phần tử cuối cùng ít có khả năng hơn các phần tử khác). –
[Modulo bias là một cái gì đó bạn nên xem xét khi s.size() là lớn so với 'RAND_MAX'] (http://stackoverflow.com/a/16006723/111307) – bobobobo
Có thể trùng lặp của https://xkcd.com/ 221/ –