+2  A: 

Use std::priority_queue with the largest item at the head. For each new item, discard it if it is >= the head item, otherwise pop the head item and insert the new item.

Side note: Standard containers will only grow if you make them grow. As long as you remove one item before inserting a new item (after it reaches its maximum size, of course), this won't happen.

Marcelo Cantos
Don't forget to put the first N items in the queue to prime it. That is, don't start tossing out elements til your queue is full. Otherwise, if you have 1 2 3 4 5 6 7 8, you'll wind up with only one element in the queue.
cHao
@cHao, that's what I meant by, "(after it reaches its maximum size, of course)".
Marcelo Cantos
std::priority_queue is no good, because it doesn't allow free access to queue. std::make_heap (it is used within priority_queue) with approach you suggested is too slow (even a bit slower than linear array) because of high number of function calls (operators, etc).
SigTerm
I'm not going to use stl for queues, but I'll accept your answer, because the idea about using "largest-sorted" heap is good. Removing root this way will help to deal with limited space. Unfortunately, in this case operation will take O(2log(N)) (first remove root, then add new node), but it will be still better than walking entire array.
SigTerm
FYI, Big-O notation generally ignores multipliers. O(2log(N)) is considered the same as O(log(N)). I understand the point you are making; just don't use Big-O to express it. BTW, I'm surprised about the performance issues. Are you compiling with optimisations on?
Marcelo Cantos
A: 

If amount of priorities is small and fixed than you can use ring-buffer for each priority. That will lead to waste of the space if objects is big, but if their size is comparable with pointer/index than variants with storing additional pointers in objects may increase size of array in the same way.
Or you can use simple single-linked list inside array and store 2*M+1 pointers/indexes, one will point to first free node and other pairs will point to head and tail of each priority. In that cases you'll have to compare in avg. O(M) before taking out next node with O(1). And insertion will take O(1).

ony
Not a solution. Linked list eventually requires to walk entire list.There are 2^31 possible priorities, ringbuffers are not possible. I already have O(N) comparisons with linear array, I'm looking for something else.
SigTerm
A: 

If you construct an STL priority queue at the maximum size (perhaps from a vector initialized with placeholders), and then check the size before inserting (removing an item if necessary beforehand) you'll never have dynamic allocation during insert operations. The STL implementation is quite efficient.

Chris
tried it, it is even a bit slower than currently used linear array due to the number of function it calls.
SigTerm
A: 

Most priority queues I work are based on linked lists. If you have a pre-determined number of priority levels, you can easily create a priority queue with O(1) insertion by having an array of linked lists--one linked list per priority level. Items of the same priority will of course degenerate into either a FIFO, but that can be considered acceptable.

Adding and removal then becomes something like (your API may vary) ...

listItemAdd (&list[priLevel], &item);      /* Add to tail */
pItem = listItemRemove (&list[priLevel]);  /* Remove from head */

Getting the first item in the queue then becomes a problem of finding the non-empty linked-list with the highest priority. That may be O(N), but there are several tricks you can use to speed it up.

  1. In your priority queue structure, keep a pointer or index or something to the linked list with the current highest priority. This would need to be updated each time an item is added or removed from the priority queue.
  2. Use a bitmap to indicate which linked lists are not empty. Combined with a find most significant bit, or find least significant bit algorithm you can usually test up to 32 lists at once. Again, this would need to be updated on each add / remove.

Hope this helps.

Sparky
Arent't most priority queues actually based on heaps?
Helper Method
I can not speak for most; I can only speak of those on which I have worked.
Sparky
+5  A: 

Array based heaps seem ideal for your purpose. I am not sure why you rejected them.

You use a max-heap.

Say you have an N element heap (implemented as an array) which contains the N smallest elements seen so far.

When an element comes in you check against the max (O(1) time), and reject if it is greater.

If the value coming in is lower, you modify the root to be the new value and sift-down this changed value - worst case O(log N) time.

The sift-down process is simple: Starting at root, at each step you exchange this value with it's larger child until the max-heap property is restored.

So, you will not have to do any deletes which you probably will have to, if you use std::priority_queue. Depending on the implementation of std::priority_queue, this could cause memory allocation/deallocation.

So you can have the code as follows:

  • Allocated Array of size N.
  • Fill it up with the first N elements you see.
  • heapify (you should find this in standard text books, it uses sift-down). This is O(N).
  • Now any new element you get, you either reject it in O(1) time or insert by sifting-down in worst case O(logN) time.

On an average, though, you probably will not have to sift-down the new value all the way down and might get better than O(logn) average insert time (though I haven't tried proving it).

You only allocate size N array once and any insertion is done by exchanging elements of the array, so there is no dynamic memory allocation after that.

Check out the wiki page which has pseudo code for heapify and sift-down: http://en.wikipedia.org/wiki/Heapsort

Moron
This a solution I found myself after a bit of sleep.
SigTerm
A: 

Matters Computational see page 158. The implementation itself is quite well, and you can even tweak it a little without making it less readable. For example, when you compute the left child like:

int left = i / 2;

You can compute the rightchild like so:

int right = left + 1;
Helper Method
A: 
SigTerm