How i can access/search randomly in a priority queue?. for example, if have a priority queue like q={5,4,3,2,1} for example, i want to access 3rd value directly which is 3, i could not do this,is there any process to access randomly in priority queue?
Most priority queue implementations, including the C++ std::priority_queue type, don't support random access. The idea behind a priority queue is to sacrifice random access for fast access to the smallest element.
Depending on what you're trying to do, there are a number of other approaches you could use. If you always want access to the third element in the queue (and not any other arbitrary positions), it's probably fast enough to just dequeue two elements, cache them, then dequeue the value you want and put the other two elements back.
If you want access to the kth-smallest element at any point in time, where k is larger, one option is to store two different priority queues: a reverse-sorted priority queue that holds k elements (call it the left queue) and a regular priority queue holding the remaining n-k elements (call it the right queue). To get the kth-smallest element, dequeue from the left queue (giving back the kth-smallest element), then dequeue an element from the right and enqueue into the left to get it back up to k total elements. To do an enqueue, check if the number is less than the top of the left queue. If so, dequeue from the left queue, enqueue the removed element into the right queue, then enqueue the original element into the left. Otherwise, enqueue into the right. This guarantees O(log n) runtimes for each operation.
If you need true random access to a sorted sequence, consider using an order statistics tree. This is an augmented binary search tree that supports O(log n) access to elements by index. You can use this to build a priority queue - the minimum element is always at index 0. The catch (of course there's a catch) is that it's hard to find a good implementation of one and the constant factors hidden in the O(log n) terms are much higher than in a standard binary heap.
To add to the answer of #templatetypedef:
You cannot combine random access of elements with a priority queue, unless you use a very inefficient priority queue. Here's a few options, depending on what you need:
1- An inefficient priority queue would be a std::vector that you keep sorted. Pushing an element means finding where it should be inserted, and move all subsequent elements forward. Popping an element would be simply reading and deleting the last element (back and pop_back, these are efficient). Random access is efficient as well, of course.
2- You could use a std::multiset (or std::multimap) instead of a priority queue. It is a tree structure that keeps things sorted. You can insert instead of push, then read and remove the first (or last) element using a begin (or rbegin) iterator with erase. Insertion and finding the first/last element are log(n) operations. The data structure allows for reading all elements in order, though it doesn't give random access.
3- You could hack your own version of std::priority_queue using a std::vector and the std::push_heap and std::pop_heap algorithms (together with the push_back and pop_back methods of the std::vector). You'd get the same efficient priority queue, but also random access to all elements of the priority_queue. They are not sorted, all you know is that the first element in your array is the top priority element, and that the other elements are stored in a way that the heap property is satisfied. If you only occasionally want to read all elements in order, you can use the function std::sort_heap to sort all elements in your array by priority. The function std::make_heap will return your array to its heap status.
Note that std::priority_queue uses a std::vector by default to store its data. It might be possible to reinterpret_cast the std::priority_queue to a std::vector, so you get random access to the other elements in the queue. But if it works on your implementation of the standard library, it might not on others, or on future versions of the same library, so I don't recommend you do this! It's safer to create your own heap class using the algorithms in the standard library as per #3 above.
Related
I am just wondering, whether it's possible to implement a structure (list/deque) which would have O(1) complexity (const/amortized doesn't matter) for get_min(), push_back(), push_front(), pop_back(), pop_front() operations?
It's definitely possible to implement stack or even queue (for them push() and pop() are available only for one end) which will satisfy these conditions. But I wasn't able to reuse this logic to a dequeue case.
It's also possible to create structure which will have O(logn) complexity for pushes/pops and O(1) for get_min (just using simple list and min_heap in which deletion of arbitrary element for O(logn) is available).
But still amortized O(1) for all operations seems impossible for me. If that is the case, can the information about exact number of operations (or max possible number of elements in list) n helps (simpler case)? Can we somehow use O(n) (or even more) additional memory or smth like this?
It is indeed possible to build a min-deque where the push-front, push-back, and find-min operations work in worst-case time O(1) and the pop-front and pop-back operations take amortized time O(1). The easiest route that I know goes like this:
First, make a stack that supports push, pop, and find-min in time O(1). We’ll use this as a building block.
Use the construction that builds a deque out of three stacks, except using these min-stacks instead of regular stacks. You can then implement the find-min operation by querying each of the three stacks for its minimum element and returning the min of those values.
In case you haven’t seen how to do step (2), the idea is a generalization of how to make a queue from two stacks. You maintain two stacks representing the elements of the deque such that one stack represents the front of the deque in reverse order (stack top is the front of the deque, and deeper elements are the next elements of the deque) and the elements of the other stack represent the back of the deque (top element is the last element of the deque, deeper elements go backwards through the deque). For example, here’s one way to encode the deque 1, 2, 3, ..., 10:
front: | 7 6 5 4 3 2 1
back: | 8 9 10
To push onto the front or back of the deque, just do a push onto the appropriate deque. To pop the front or back of the deque, if the appropriate stack is nonempty, just pop from it. Otherwise, if the stack is empty, you need to move some number of elements from the other stack over. Specifically, to keep things balanced between the two stacks, you do a series of pushes and pops to put half the elements into each of the two stacks. That looks like this:
Pop half the elements from the other stack and push them onto a temporary stack.
Pop the remaining elements from the other stack and push them onto the empty stack.
Pop the elements from the temporary stack and push them back onto the other stack.
You can show using a potential argument (see Φ to be the absolute value of the difference in heights of the two stacks) that each operation takes amortized time O(1).
It may be possible to somehow speed this up to worst-case O(1) time per operation using some sort of scheduling scheme, but I’m not sure how to do this. I know there’s a way to implement a queue with four stacks with worst-case O(1) for each operation, so perhaps this idea could be generalized to work here?
I keep on hearing both from people and on documentation that std::deque is random access like an std::vector, and is constant time insertion and deletion like a linked list. In addition an std::deque can insert elements at the beginning and end in constant time, unlike a vector. I'm not sure whether the standard specifies a particular implementation of std::deque, but it's supposed to stand for double-ended queue, and that most likely the implementation combines vector-like allocation buffers linked together with pointers. A key difference is that the elements are NOT contiguous like an std::vector.
Given that they are not contiguous, when people say that they are random access like vectors am I right in thinking they mean this in an "amortized" sense and not in reality as vectors? This is because a vector involves just an offset address, guaranteeing true constant time access every time, while the double-ended queue, has to calculate how far along the requested element is in the sequence, and count how many linked buffers along it has to go in order to find that particular element.
Likewise, an insertion in a linked list involves only breaking one link and setting another, whereas an insertion in a double-ended queue (that isn't the last or first member, has to at least shift all the members after the insertion point one place at least for that particular linked buffer. So for example if one linked buffer had 10 members and you happened to insert at the beginning of that particular buffer, then it would have to at least move 10 members (and worse if it overran the buffer capacity and had to reallocate).
I'm interested in knowing this because I want to implement a queue, and in the standard library std::queue is what they call a container adaptor, meaning we're not told exactly what container type it is, as long as it functions the way a queue is meant to. I think it's usually a kind of a wrapper for std::deque or std::list. Given that I'm interested in just the simple functionality of a first-in first-out kind of thing, I'm almost certain that a linked list will be faster in inserting into the queue and popping off the end. And so I would be tempted to explicitly select that instead of an std::queue.
Also, I'm aware linked lists are less cache-friendly for iterating through, but we're comparing a linked list not with a vector but a double-ended queue, which as far as I know has to do a considerable amount of record-keeping in order to know how far along and in which particular buffer it is in when iterating through.
Edit: I've just found a comment on another question that is of interest:
"C++ implementations I have seen used an array of pointers to
fixed-size arrays. This effectively means that push_front and
push_back are not really constant-times, but with smart growing
factors, you still get amortized constant times though, so O(1) is not
so erroneous, and in practice it's faster than vector because you're
swapping single pointers rather than whole objects (and less pointers
than objects). – Matthieu M. Jun 9 '11"
From: What really is a deque in STL?
It's random access but the constant time insert and delete is only for the beginning and end of the sequence, in the middle it's O(n).
And it's O(1) to access an item but it's not as efficient an O(1) as for a vector. It's going to take the same number of calculations to figure out where an item is in a deque regardless of its position, even regardless of how many items are in the deque. Compare this with a list where to find the n'th item you have to walk the n-1 preceding items.
I want a structure to store (for example) numbers where I can insert and remove elements, my structure remains sorted always (like a priority queue) BUT with the possibility of knowing where is a given number, and every operation in logarithmic time.
Maybe with lower_bound, upper_bound, or just a binary search, but in priority_queue what blocks me to do binary search is that I cannot access the elements with an index, only the first one.
I think you’re looking for an order statistics tree, an augmented BST that supports all the regular BST operations in time O(log n), along with two others:
rank(elem): return which index elem would occupy in the sorted sequence.
index(k): given an index k, return the element at that index in the sorted sequence.
The two above operations run in O(log n) time, making them extremely fast.
You can treat an order statistics tree as a priority queue. Insertions work as normal BST insertions, and to extract the lowest/highest element you just remove the smallest/greatest element from the tree, which you can do in time O(log n) by just walking down the left or right spines of the tree.
A priority queue does not keep things in sorted order. At least, not typically. A priority queue makes it possible for you to quickly obtain the next item in the sequence. But you can't efficiently access, say, the 5th item in the queue.
I know of three different ways to build a priority queue in which you can efficiently access items by key:
Use a balanced binary search tree to implement the queue. Although all operations are O(log n), typical running time is slower than a binary heap.
Implement the heap priority queue as a skip list. This is a good option. I've seen some people report that a skip list priority queue outperforms a binary heap. A search for [C++ skip list] will return you lots of implementations.
What I call an indexed binary heap also works. Basically, you marry a hash map or dictionary with a binary heap. The map is indexed by key, and its value contains the index of the item in the heap array. Such a thing is not difficult to build, and is quite effective.
Come to think of it, you can make an indexed version of any type of heap.
You have a number of options. I rather like the skip list, myself, but your mileage may vary.
The indexed binary heap, as I pointed out, is a hybrid data structure that maintains a dictionary (hash map) and a binary heap. Briefly how it works:
The dictionary key is the field that you use to look up an item that you put into the heap. The value is an integer: the index of that item in the heap.
The heap itself is a standard binary heap implemented in an array. The only difference is that every time you move an item from one place to another in the heap, you update its location in the dictionary. So, for example, if you swap two items, you have to swap not only the items themselves in the array, but also their positions as stored in the dictionary. For example:
heap is an array of string references
dict is a dictionary, keyed by string
swap (a, b)
{
// swap item at heap[a] with item at heap[b]
temp = heap[a]
heap[a] = heap[b]
heap[b] = temp
// update their positions in the dictionary
dict[heap[a]] = b
dict[heap[b]] = a
}
It's a pretty simple modification of a standard binary heap implementation. You just have to be careful to update the position every time you move an item.
You can also do this with node-based heaps like Pairing heap, Fibonacci heap, Skew heap, etc.
I am implementing k nearest neighbor search in a tree data structure. I store the results in a priority queue, which will automatically sort the elements in a ascending order, and so the first k elements are the results. The priority_queue container in STL is really not a good option here because it support only a few functions such as push(), pop(), top(), size() empty(), etc. A big problem here is that when searching the whole tree, I need to visit a lot of nodes, and using push() will make the priority queue longer and longer, which will increase time cost for later operations. What I really want is a fixed-length priority queue, so when push() a new element into the queue, some elements with larger values will be automatically deleted. How can I implement this? Or is there any standard container I can use? Thank you.
What about using std::set? It stores elements in order, and if it grows above k elements you can just remove the largest one (in constant time). Each insertion is O(log k).
One way with priority_queue but changing the ordering (ascending to descending), and if it grows above k elements, remove the top element (which is the farther).
Is i have a priority queue with declaration
priority_queue<<Node>,vector<Node>,myComp> openQ
i am inserting node objects into it. but at some time i have to delete the element from it. (not to remove the top element)
Currently to delete it i am popping the element and putting it in array. if the top most element is desired then expect it i push other elements in array.
This is like linear search and delete. I know its not efficient and i am looking for some better ways
priority_queue class is designed for using as queue with priorities. And it designed to remove elements with pop function. If you want to get different behavior you should use different class. For instance, std::map.
If you're ready to manually control a consistence of the queue you may take a look on std::make_heap. It's easy to create a max-heap with it. But in this case you need to manually rebuild a queue each time you want to remove an element.
std::set are orderd and can erase elements by value. the underlying datastructure is a binary search tree, thats why its cheaper to erase elements by value.
a priority queue would have to linearly search through the queue, so its possible but just not very efficient, thats why they didnt include it.