-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPriorityQueue.h
More file actions
204 lines (160 loc) · 7.7 KB
/
Copy pathPriorityQueue.h
File metadata and controls
204 lines (160 loc) · 7.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#ifndef DSPRIORITYQUEUE_H
#define DSPRIORITYQUEUE_H
// includes ////////////////////////////////////////
#include <cstddef>
#include "Allocators.h"
#ifdef DS_DEBUG_LOG
#include <vector>
#endif
// defines /////////////////////////////////////////
// forward declarations ////////////////////////////
// class declarations //////////////////////////////
namespace DS {
/// @brief Implements a priority queue based on a binary-heap
/// Characteristics:
/// Space Complexity: O(n)
/// Time Complexity:
/// - Access top: O(1)
/// - Insert: O(logn) through heapify
/// - Delete: O(logn) through heapify
///
/// @tparam T the data type of the elements
template <typename T, bool isMin = true>
class PriorityQueue {
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type & ;
using const_reference = const value_type&;
using pointer = value_type * ;
using const_pointer = const value_type*;
using allocator = AllocatorSimple<value_type>;
protected:
/// @brief Internal implementation of the container
struct PriorityQueueImpl {
/// @brief Data container
T *m_data = { nullptr };
/// @brief Size of the container
size_type m_size = { 0 };
/// @brief Capacity of the container
size_type m_capacity = { 0 };
};
// protected variable declarations
/// @brief Container implementation
PriorityQueueImpl m_impl;
/// @brief Allocator
allocator m_allocator;
// protected function declarations
private:
// private variable declarations
// private function declarations
/// @brief Increase the capacity of the container
/// @param capacity the capacity to increase
/// @param capacity the minimum increase in capacity
/// @return the new capacity
size_type increaseCapacity(size_type capacity, size_type min) { return capacity + 2 * capacity + min; }
/// @brief Reallocate the container with the requested capacity
/// @param capacity the new capacity
void reallocate(size_type capacity);
/// @brief Destroys the requested data
/// @param data a pointer to the data to destroy
/// @param size the number of elements to destroy
void destroy(value_type* data, size_type size);
/// @brief Clone the internal data
/// @param newdata the object to hold the cloned data
/// @param olddata the object to clone the data from
void clone(PriorityQueueImpl& newdata, const PriorityQueueImpl& olddata);
/// @brief Retrieve the parent of a child
/// @param index the array index of the child
/// @return the parent index
size_type parent(size_type index) const { return (index - 1) / 2; }
/// @brief Retrieve the left child of a parent
/// @param index the array index of the parent
/// @return the left index of the child
size_type left(size_type index) const { return (index * 2) + 1; }
/// @brief Retrieve the right child of a parent
/// @param index the array index of the parent
/// @return the right index of the child
size_type right(size_type index) const { return left(index) + 1; }
/// @brief Check if a parent has a left child
/// @param index the array index of the parent
/// @return a flag indicating whether the parent has a left child
bool has_left(size_type index) const { return left(index) < m_impl.m_size; }
/// @brief Check if a parent has a right child
/// @param index the array index of the parent
/// @return a flag indicating whether the parent has a right child
bool has_right(size_type index) const { return right(index) < m_impl.m_size; }
/// @brief Places a new element at the top of the tree
/// @param index the array index of the parent
void heapify_down(size_type index);
/// @brief Places a new element in its ordered position in the tree
/// @param index the array index of the element
void heapify_up(size_type index);
/// @brief Tests if the first element is ordered "before" the second, based on whether this is a max or min heap
/// In min heap, first element is smaller than the second. In max heap, before means larger.
/// @param obj1 the first element to compare
/// @param obj2 the second element to compare
/// @return false if a parent is not ordered "before" the child
bool isBefore(const value_type* obj1, const value_type* obj2) const { return isMin ? *obj1 < *obj2 : *obj1 > *obj2; }
public:
/// @brief Default Constructor
PriorityQueue(void) = default;
/// @brief Explicit Constructor
/// @param capacity the initial capacity of the queue
explicit PriorityQueue(size_type capacity);
/// @brief Destructor
~PriorityQueue(void);
/// @brief Copy Constructor
/// @param other the container to copy
PriorityQueue(const PriorityQueue& other);
/// @brief Copy assignment operator
/// @param other the container to copy assign
PriorityQueue& operator=(const PriorityQueue& other);
// public function declarations
/// @brief Return the height of the sub-tree
/// @return the height of the sub-tree
size_type height(size_type index);
/// @brief Access the top element O(1)
/// @return the element
value_type* top(void) { return m_impl.m_size > 0 ? &m_impl.m_data[0] : nullptr; }
/// @brief Access the top element O(1)
/// @return the element
const value_type* top(void) const { return m_impl.m_size > 0 ? &m_impl.m_data[0] : nullptr; }
/// @brief Checks if the container is empty
/// @return A flag indicating whether the container is empty
constexpr bool empty() const noexcept { return size() == 0; }
/// @brief Size of the container
/// @return Size of the container
constexpr size_type size() const noexcept { return m_impl.m_size; }
/// @brief Capacity of the container
/// @return Capacity of the container
constexpr size_type capacity() const noexcept { return m_impl.m_capacity; }
/// @brief Allocate new storage
/// @param new_cap the size of the new storage
void reserve(size_type new_cap);
/// @brief Shrinks the container to its size
void shrink_to_fit();
/// @brief Clears the container of its elements. Does not change reserved memory (capacity).
void clear() noexcept;
/// @brief Push a new element to the container
/// @param value the data to insert
void push(const value_type& value);
/// @brief Pops an element from the container
void pop(void);
#ifdef DS_DEBUG_LOG
/// @brief Validates the queue, i.e., that all elements are properly ordered
/// @param index the array index of the subtree to test
bool validateHeap(size_type index = 0) const;
/// @brief Print traversal of the tree in a pretty way
/// @param node the start node
/// @param str a string to store the result
/// @param start_level the level of the node (should not change)
void printPretty(size_type index, std::string& str, int level) const;
#endif// DS_DEBUG_LOG
/// @brief Logs the container
void print(void) const;
};
}
#include "PriorityQueue.inl"
#endif //DSPRIORITYQUEUE_H