66
77namespace aocutil
88{
9+
910template <typename T, typename PrioType = int >
1011class PrioQueue
1112{
@@ -45,16 +46,30 @@ class PrioQueue
4546 }
4647 }
4748
48- std::optional<T> extract_min ()
49+ T extract_min ()
50+ {
51+ auto min_elem = prio_to_elem.begin ();
52+ if (min_elem == prio_to_elem.end ()) { // Queue is empty.
53+ assert (empty ());
54+ throw std::out_of_range (" PrioQueue extract_min: Queue already empty" );
55+ }
56+ T elem = min_elem->second ;
57+ prio_to_elem.erase (min_elem);
58+ elem_to_prio.erase (elem);
59+ return elem;
60+ }
61+
62+ T extract_min (PrioType& prio)
4963 {
5064 auto min_elem = prio_to_elem.begin ();
5165 if (min_elem == prio_to_elem.end ()) { // Queue is empty.
5266 assert (empty ());
53- return {} ;
67+ throw std::out_of_range ( " PrioQueue extract_min: Queue already empty " ) ;
5468 }
5569 T elem = min_elem->second ;
5670 prio_to_elem.erase (min_elem);
5771 elem_to_prio.erase (elem);
72+ prio = min_elem->first ;
5873 return elem;
5974 }
6075
@@ -75,4 +90,269 @@ class PrioQueue
7590 return empt;
7691 }
7792};
93+
94+ // Is slower...
95+ // template<typename T, typename HashFun = void>
96+ // class BinaryHeap
97+ // {
98+ // enum class Child {Left, Right};
99+ // std::vector<T> nodes;
100+ // using MapType = typename std::conditional_t<std::is_same_v<HashFun, void>, phmap::flat_hash_map<T, std::size_t>, phmap::flat_hash_map<T, std::size_t, HashFun>>;
101+ // MapType elem_to_idx;
102+
103+ // std::size_t get_parent_idx(std::size_t idx) const {
104+ // return (idx - 1) / 2;
105+ // }
106+
107+ // std::optional<std::size_t> get_children_idx(std::size_t idx, Child ct) const
108+ // {
109+ // std::size_t child_idx = 0;
110+ // if (ct == Child::Left) {
111+ // child_idx = 2 * idx + 1;
112+ // } else if (ct == Child::Right) {
113+ // child_idx = 2 * idx + 2;
114+ // } else {
115+ // assert(false);
116+ // }
117+
118+ // if (child_idx < nodes.size()) {
119+ // return child_idx;
120+ // } else {
121+ // return {};
122+ // }
123+ // }
124+
125+ // bool is_ordered(const T& parent, const T& child) const
126+ // {
127+ // if (type == BinaryHeapType::Min) {
128+ // return parent <= child;
129+ // } else if (type == BinaryHeapType::Max) {
130+ // return parent >= child;
131+ // } else {
132+ // throw std::invalid_argument("Binary heap is_ordered: Invalid binary heap type");
133+ // }
134+ // }
135+
136+
137+ // void swap_nodes(std::size_t idx_a, std::size_t idx_b) {
138+ // assert(elem_to_idx.contains(nodes.at(idx_a)));
139+ // assert(elem_to_idx.contains(nodes.at(idx_b)));
140+
141+ // elem_to_idx.at(nodes.at(idx_a)) = idx_b;
142+ // elem_to_idx.at(nodes.at(idx_b)) = idx_a;
143+ // std::swap(nodes.at(idx_a), nodes.at(idx_b));
144+ // }
145+
146+ // void heapify_up(std::size_t idx)
147+ // {
148+ // if (nodes.size() <= 1) {
149+ // return;
150+ // }
151+
152+ // while (idx > 0 && !is_ordered(nodes.at(get_parent_idx(idx)), nodes.at(idx))) {
153+ // swap_nodes(get_parent_idx(idx), idx);
154+ // idx = get_parent_idx(idx);
155+ // }
156+ // }
157+
158+ // void heapify_down(std::size_t idx)
159+ // {
160+ // if (nodes.size() <= 1) {
161+ // return;
162+ // }
163+ // do {
164+ // auto idx_left_child = get_children_idx(idx, Child::Left);
165+ // auto idx_right_child = get_children_idx(idx, Child::Right);
166+ // if (!idx_left_child) {
167+ // assert(!idx_right_child);
168+ // return;
169+ // }
170+ // if (!idx_right_child) {
171+ // idx_right_child = idx_left_child;
172+ // }
173+
174+ // assert(idx_left_child && idx_right_child);
175+ // const T& left = nodes.at(idx_left_child.value());
176+ // const T& right = nodes.at(idx_right_child.value());
177+ // const T& min_max_child = (type == BinaryHeapType::Min) ? std::min(left, right) : std::max(left, right);
178+ // std::size_t min_max_child_idx = min_max_child == left ? idx_left_child.value() : idx_right_child.value();
179+
180+ // if (!is_ordered(nodes.at(idx), nodes.at(min_max_child_idx))) {
181+ // swap_nodes(idx, min_max_child_idx);
182+ // idx = min_max_child_idx;
183+ // } else {
184+ // break;
185+ // }
186+ // } while (idx < nodes.size() - 1);
187+ // }
188+
189+ // bool is_heap() const {
190+ // return (type == BinaryHeapType::Min) ? std::is_heap(nodes.cbegin(), nodes.cend(), std::greater<T>{}) : std::is_heap(nodes.begin(), nodes.end());
191+ // }
192+
193+ // public:
194+ // enum class BinaryHeapType {Max, Min};
195+ // const BinaryHeapType type = BinaryHeapType::Min;
196+
197+ // BinaryHeap(BinaryHeapType type = BinaryHeapType::Min) :type(type) {};
198+
199+ // void insert(const T& elem)
200+ // {
201+ // if (elem_to_idx.contains(elem)) {
202+ // throw "BinaryHeap insert: elem already inside";
203+ // }
204+
205+ // nodes.push_back(elem);
206+ // std::size_t idx = nodes.size() - 1;
207+ // elem_to_idx.insert({elem, idx});
208+
209+ // heapify_up(idx);
210+ // assert(is_heap());
211+ // }
212+
213+ // T extract_min()
214+ // {
215+ // if (size() == 0) {
216+ // throw std::out_of_range("BinaryHeap extract_min: Heap is empty");
217+ // }
218+ // T extracted_elem = nodes.at(0);
219+ // std::size_t last_idx = nodes.size() - 1;
220+ // if (nodes.size() > 1) {
221+ // swap_nodes(0, last_idx);
222+ // }
223+ // nodes.pop_back();
224+
225+
226+ // heapify_down(0);
227+
228+ // elem_to_idx.erase(extracted_elem);
229+
230+ // assert(is_heap());
231+ // return extracted_elem;
232+ // }
233+
234+ // void delete_elem(const T& elem)
235+ // {
236+
237+ // // cf. https://en.wikipedia.org/wiki/Binary_heap#Delete (last retrieved 2024-06-20)
238+ // if (!elem_to_idx.contains(elem)) {
239+ // throw std::out_of_range("BinaryHeap delete_elem: elem not in heap");
240+ // }
241+ // std::size_t deleted_idx = elem_to_idx.at(elem);
242+ // std::size_t last_idx = nodes.size() - 1;
243+
244+ // if (nodes.size() == 1) {
245+ // elem_to_idx.erase(elem);
246+ // nodes.pop_back();
247+ // assert(is_heap());
248+ // return;
249+ // }
250+
251+ // swap_nodes(deleted_idx, last_idx);
252+ // bool require_heapify_up = (type == BinaryHeapType::Min) ? nodes.at(deleted_idx) < nodes.at(last_idx) : nodes.at(deleted_idx) > nodes.at(last_idx) ;
253+
254+ // elem_to_idx.erase(nodes.at(last_idx));
255+ // nodes.pop_back();
256+ // if (nodes.size() == 0) {
257+ // assert(is_heap());
258+ // return;
259+ // }
260+
261+ // if (require_heapify_up) {
262+ // heapify_up(deleted_idx);
263+ // } else {
264+ // heapify_down(deleted_idx);
265+ // }
266+ // assert(is_heap());
267+ // }
268+
269+ // typename std::vector<T>::const_iterator cbegin() const {
270+ // return nodes.cbegin();
271+ // }
272+
273+ // typename std::vector<T>::const_iterator cend() const {
274+ // return nodes.cend();
275+ // }
276+
277+ // std::size_t size() const {
278+ // return nodes.size();
279+ // }
280+
281+ // bool contains(const T& elem) const {
282+ // return elem_to_idx.contains(elem);
283+ // }
284+ // };
285+
286+ // template<typename T, typename PrioType = int>
287+ // class PrioQueueHeap
288+ // {
289+ // private:
290+ // struct KeyVal {
291+ // PrioType key;
292+ // T val;
293+ // auto operator<=>(const KeyVal& other) const {return key - other.key;};
294+ // auto operator==(const KeyVal& other) const {return val == other.val;};
295+ // // KeyVal() = default;
296+ // KeyVal(PrioType key, const T& val) :key(key), val(val) {};
297+ // KeyVal(const T& val) : val(val) {};
298+
299+
300+ // struct KeyValHash {
301+ // std::size_t operator()(const KeyVal& kv) const noexcept {
302+ // return std::hash<T>{}(kv.val);
303+ // }
304+ // };
305+ // };
306+
307+ // BinaryHeap<KeyVal, typename KeyVal::KeyValHash> heap;
308+
309+ // public:
310+ // void insert(const T& elem, const PrioType& priority)
311+ // {
312+ // KeyVal kv(priority, elem);
313+ // if (heap.contains(kv)) {
314+ // throw std::invalid_argument("PrioQueueHeap insert: Element already in queue");
315+ // }
316+ // heap.insert(kv);
317+ // }
318+
319+ // void update_prio(const T& elem, const PrioType& new_priority)
320+ // {
321+ // KeyVal kv(new_priority, elem);
322+
323+ // if (!heap.contains(kv)) {
324+ // throw std::out_of_range("PrioQueueHeap update_prio: Element not in queue.");
325+ // }
326+ // heap.delete_elem(kv);
327+ // heap.insert(kv);
328+ // }
329+
330+ // void insert_or_update(const T& elem, const PrioType& prio)
331+ // {
332+ // if (heap.contains(KeyVal(prio, elem))) {
333+ // update_prio(elem, prio);
334+ // } else {
335+ // insert(elem, prio);
336+ // }
337+ // }
338+
339+ // T extract_min()
340+ // {
341+ // return heap.extract_min().val;
342+ // }
343+
344+ // bool contains(const T& elem) const {
345+ // return heap.contains(KeyVal(elem)); // The key stays undefined but that's okay.
346+ // }
347+
348+ // std::size_t size() const {
349+ // return heap.size();
350+ // }
351+
352+ // bool empty() const
353+ // {
354+ // return heap.size() == 0;
355+ // }
356+ // };
357+
78358}
0 commit comments