views:

209

answers:

2

Hi,

I am looking for a special template class, hopefully either a QT template or a self-contained open source library. This template class is intended to act as a container for a set of objects. Each object in the set has an integer-valued weight function but the weight function itself is arbitrary. It could range uniformly from 10 to 100 or vary non-uniformly from 1000 to 10000 or be a constant value.

The template would keep a list of objects sorted by this weight (resolving ties arbitrarily). It would allow me to quickly retrieve the object having nth highest weight from the list, by order, not value (random access using an integer, like QList). The template also allow me to quickly add and remove arbitrary elements while keeping the list ordered by weight (like a QMap).

Just quickly finding objects within an order of magnitude would be enough for my purposes - IE, finding the 1st, the 10th, the 100th, the 1000th and so-forth elements in my ordered list would suffice.

I could implement a data structure like this myself (as an array of lists of increasing size or as a modified a binary tree having a count of n elements below each node). But it seems better to use a standard, commonly available, well documented template to solve the problem. I would prefer to avoid STL but if there's an STL solution, I would be interested.

Edit: I'm looking for, at the least, orders of magnitude - not just the first but the 1st, the 10th, the 100th ordered by weight on up to the end (the internal ordering of a heap data structure would be great but I don't see any functions that directly access this). I can see that STL provides a "random access iterator" but after paging through a fair amount of documentation, I still can't find if this iterator would give the nth value without needing to sort the list for each call - indeed, my vague impression is that it would. STL also provides an "nth element" function but it appears that this is relatively costly if you are calling it for each access to the list.

Edit2: Reason one can't simply use a QMap iterator and do it2 = it.begin()+1000; (from QT's documentation):

iterator iterator::operator+ ( int j ) const

Returns an iterator to the item at j positions forward from this iterator. (If j is negative, the iterator goes backward.)

This operation can be slow for large j values.

See also operator-().

A: 

QMap sorts based on the key, so you could just use that. e.g.

QMap<int, YourValueType>

You can then use iterators to retrieve the n-th last item, e.g. the last: map.end() - 1, next to last, map.end() - 2, ...

Full example:

#include <QMap>
#include <QString>
#include <QDebug>

int main()
{
    QMap<int, QString> foo;

    foo.insert(2, "foo");
    foo.insert(1, "bar");
    foo.insert(5, "baz");

    qDebug() << (foo.end() - 1).value();
    qDebug() << (foo.end() - 2).value();

    return 0;
}

Produces:

"baz" 
"foo"
scotchi
What is the complexity of integer addition/subtraction on QMap iterators? `O(lg n)` is possible on a binary tree, but not all implementations actually provide this.
bdonlan
QMap's are a skip-list, not a red-black-tree, but its lookups are traversing a linked list; whether or not that matters depends on how far back in the list you care to look.
scotchi
I don't think this is what I'm looking for. I can't see anything that keeps the integers sorted in the same order as my weighted objects.
Joe Soul-bringer
@Je Soul-bringer: I assume the idea was for your weight to be stored by the int. This would work assuming you didn't change the weight mid-stream and expect it to be automatically resorted (to do that, you'd have to remove then re-add the object with the new weight).
Caleb Huitt - cjhuitt
Read my original question - your answer doesn't give a *quick* way of finding the 100th or 1000th highest-weight element of a large list, which is what I'm looking for.
Joe Soul-bringer
+1  A: 

The data structure you're looking for is a heap. The stdlib has std::make_help, push_heap, and pop_heap. There is also std::priority_queue. (I'm not sure why you'd avoid these, unless there's some other requirement you haven't told us about.)

A tree such as a map will also work, but it will sort every item. If you need, for example, only the 'best' three out of 1,000,000, then sorting all of them would be wasteful.

Roger Pate
I'm would prefer a non-STL solution because my app currently uses only QT and I'd like the avoid the overhead of another library
Joe Soul-bringer
That's a fair enough requirement, if you choose; however, that really prevents using anything other than what Qt provides, unless you write it yourself. Also remember STL is a specific library; not the same thing as the C++ standard library (stdlib), nor does it mean all the templates in the stdlib.
Roger Pate
Also, while it's clear a heap data structure offers the possibility of getting the approximate 1000th highest-weight element in a large set of element, I haven't been able to determine *how* exactly to do this, even scanning consider online documentation. Do you create a random-access iterator? I haven't seen an example. Thanks!
Joe Soul-bringer
OK, now I understand...
Joe Soul-bringer