I was looking for stl/boost container which can provide following functionality:
UPDATE
You need an order statistic tree. The C++ Standard Library doesn't have any, nor does it offer an easy way to implement one, see
Rank Tree in C++
How to find rank of an element in stl set in O(logn)
ith order statistic using C++'s STL
Nor does boost, see under Future work and at the question linked just above.
However, the good news is, that such a tree is available in libstdc++
as an extension!
GNU Policy-Based STL MAP implemented as order statistic tree
Example in the doc or here
(Original answer:)
- Auto insert element in sorted order. (log n)
- Return index/depth of element from starting node. (log n)
It seems to me that neither the C++ Standard Library nor boost offer a container that would provide these complexity guarantees out-of-the-box. You either have to implement this container yourself or relax your complexity requirements and allow O(n)
for at least one of them.
if not: What will be the best way to achieve this ? I am thinking a solution using double link list. Will it be good choice to solve this problem ?
std::list
is a doubly-linked list but you can only achieve linear time insertion. std::list
is a big performance killer due to its poor use of the cache.
You might be better off with boost::container::flat_set which also offers only linear time insertion but still may surprise you with its speed due the excellent use of the cache (thanks to the hardware prefetcher). And as a bonus, you get random access iterators, so the index can be found in O(1)
time if you already have the element.
If both complexity requirements are a must, then I don't see any easier way than implementing a self-balancing binary search tree and storing the subtree size as well on each parent node. Maintaining this extra information won't ruin the O(log n)
complexity. It is significant and non-trivial work to implement it, even if you start with one of the red-black tree implementation of std::map
(not guaranteed to be a red-black tree but in libstdc++
it is and it is open-source).
One more thing comes to mind: What is your usage pattern? Are your doing insertions and index look-ups completely at random, one after the other? If not, or at least mainly not, then you might switch datastructures in between and get away with one of the stl or boost containers.
A binary tree (B-tree) has logarithmic insertion and retrieval (equivalent to depth count) time in the average case and is naturally sorted when walked in-order.
Unfortunately, a B-tree insertion/retrieval time might degenerate to linear if the tree is unbalanced (worst case). If this is an issue, you should consider a Red-Black tree, which does not eliminate the problem, but mitigates it while keeping the insertion time logarithmic in the size of the tree.
Neither STL nor Boost implement a B- or RB- tree, although std::map is usually implemented as a RB.
Please keep in mind that a linked list has linear insertion time, even if double.
std::map
and std::set
acording to the standard guarantee O(log(N)) insertion and searching, they also satisfy the sorted order condition. Please see C++ standard at section 23.4.
Update after @StefanoSanfilippo constructive comment:
Have in mind though, that these containers allow only unique keys/elements. If you have multiple values you have to resort to std::multimap
and std::multiset
. These containers have almost the same properties with std::map
and std::set
but allow multiple keys/elements.
Now about with index/depth issue as far as it concerns STL containers, it's not guaranteed that std::map
and std::set
are implemented as binary-trees and as such there is no interface for accessing tree properties such as depth and index (please see How to find the depth of each node in std::map?). Making an educated guess, I think that the same goes for boost's tree like containers.
Update - Quoting from @Mooing Duck's comment:
boost trees also do not have ways to get the index.