Cpp Libs Priority_Queue
# C++ Standard Library: ``
In C++, `std::priority_queue` is a container adapter provided by the Standard Template Library (STL) under the `` header. It is designed to model a queue where elements are ordered by priority rather than their insertion order.
A priority queue allows for fast $O(1)$ access to the element with the highest (or lowest) priority, while insertions and deletions are performed in logarithmic time $O(\log n)$.
---
## Key Characteristics
* **Heap-Based Implementation:** By default, `std::priority_queue` is implemented as a **max-heap**. This means the element at the top of the queue always holds the largest value according to the comparison criteria.
* **Container Adapter:** It is not a standalone container but an adapter that wraps around an underlying sequential container (such as `std::vector` or `std::deque`) and provides a heap-based interface.
* **No Iterators:** It does not support iterators or random access. You can only access the top element.
---
## Syntax and Template Parameters
To use `std::priority_queue`, you must include the `` header:
```cpp
#include
```
### Template Definition
```cpp
template<
class T,
class Container = std::vector,
class Compare = std::less
> class priority_queue;
```
* **`T`**: The type of the elements stored in the queue.
* **`Container`**: The underlying container type used to store the elements. It must support random-access iterators and front/back operations (typically `std::vector` or `std::deque`). Defaults to `std::vector`.
* **`Compare`**: A binary predicate that takes two arguments of the element type and returns a `bool`. Defaults to `std::less`, which creates a **max-heap**.
### Basic Declarations
```cpp
// 1. Default Max-Heap (Highest value at the top)
std::priority_queue max_pq;
// 2. Min-Heap using std::greater (Lowest value at the top)
std::priority_queue, std::greater> min_pq;
// 3. Custom Type with Custom Comparator Struct
struct CustomCompare {
bool operator()(int a, int b) {
return a > b; // Returns true if 'a' should have lower priority than 'b' (Min-Heap behavior)
}
};
std::priority_queue, CustomCompare> custom_pq;
```
---
## Common Member Functions
| Member Function | Description | Time Complexity |
| :--- | :--- | :--- |
| `top()` | Returns a reference to the top element (highest priority) without removing it. | $O(1)$ |
| `push(const T& val)` | Inserts a new element into the priority queue and reorders the heap. | $O(\log n)$ |
| `emplace(Args&&... args)` | Constructs an element in-place directly inside the container. | $O(\log n)$ |
| `pop()` | Removes the top element from the priority queue. | $O(\log n)$ |
| `empty()` | Checks whether the priority queue is empty. | $O(1)$ |
| `size()` | Returns the number of elements in the priority queue. | $O(1)$ |
---
## Code Examples
### Example 1: Default Max-Heap
The following example demonstrates how to create a default max-heap, insert elements, and retrieve them in descending order.
```cpp
#include
#include
int main() {
// Create a priority queue of integers (default: Max-Heap)
std::priority_queue pq;
// Insert elements
pq.push(30);
pq.push(10);
pq.push(50);
pq.push(20);
// Retrieve and print elements
std::cout << "Elements in Max-Heap (highest to lowest):" << std::endl;
while (!pq.empty()) {
std::cout << pq.top() << std::endl; // Access the top element
pq.pop(); // Remove the top element
}
return 0;
}
```
**Output:**
```text
Elements in Max-Heap (highest to lowest):
50
30
20
10
```
---
### Example 2: Custom Priority (Min-Heap)
If you need a min-heap (where the smallest value is always at the top), you can pass `std::greater` as the third template argument, or define a custom comparator struct.
```cpp
#include
#include
#include
// Custom comparator struct
struct Compare {
bool operator()(int a, int b) {
return a > b; // Defines a Min-Heap
}
};
int main() {
// Create a priority queue with a custom comparator for a Min-Heap
std::priority_queue, Compare> pq_min;
// Insert elements
pq_min.push(30);
pq_min.push(10);
pq_min.push(50);
pq_min.push(20);
// Retrieve and print elements
std::cout << "Elements in Min-Heap (lowest to highest):" << std::endl;
while (!pq_min.empty()) {
std::cout << pq_min.top() << std::endl; // Access the top element
pq_min.pop(); // Remove the top element
}
return 0;
}
```
**Output:**
```text
Elements in Min-Heap (lowest to highest):
10
20
30
50
```
---
## Advanced Usage: Priority Queue of Custom Objects
When working with custom classes or structs, you must define how they are compared. You can do this by overloading the `<` operator inside the struct or by passing a custom comparator class.
```cpp
#include
#include
#include
#include
struct Task {
int priority;
std::string description;
// Overload the '<' operator to define priority.
// Note: In std::priority_queue, the element that evaluates to "less" is placed lower in the heap.
// Therefore, to make higher priority numbers come first, we use '<'.
bool operator<(const Task& other) const {
return priority < other.priority;
}
};
int main() {
std::priority_queue task_queue;
task_queue.push({2, "Write documentation"});
task_queue.push({5, "Fix critical production bug"});
task_queue.push({1, "Clean up workspace"});
task_queue.push({3, "Refactor legacy code"});
std::cout << "Executing tasks based on priority:" << std::endl;
while (!task_queue.empty()) {
Task current = task_queue.top();
std::cout << "[" << current.priority << "] " << current.description << std::endl;
task_queue.pop();
}
return 0;
}
```
**Output:**
```text
Executing tasks based on priority:
Fix critical production bug
Refactor legacy code
Write documentation
Clean up workspace
```
---
## Considerations & Best Practices
1. **No Iteration Support:** You cannot iterate through a `std::priority_queue` using a `for` loop or iterators. If you need to inspect all elements without destroying the queue, consider using `std::vector` with `std::make_heap`, `std::push_heap`, and `std::pop_heap` algorithms instead.
2. **Performance:**
* `top()` is $O(1)$.
* `push()` and `pop()` are $O(\log n)$.
* Building a priority queue of size $n$ from an existing container using the constructor takes $O(n)$ time, which is more efficient than pushing elements one by one ($O(n \log n)$).
3. **Memory Overhead:** Since it is typically backed by `std::vector`, it inherits its dynamic resizing behavior. Ensure you use `emplace()` instead of `push()` when inserting temporary objects to avoid unnecessary copy or move operations.
YouTip