orx_priority_queue/dary/daryheap_map.rs
1use super::heap::Heap;
2use crate::positions::map::{HeapPositionsMap, Index};
3use crate::{PriorityQueue, PriorityQueueDecKey, ResUpdateKey};
4
5/// Type alias for `DaryHeapWithMap<N, K, 2>`; see [`DaryHeapWithMap`] for details.
6pub type BinaryHeapWithMap<N, K> = DaryHeapWithMap<N, K, 2>;
7/// Type alias for `DaryHeapWithMap<N, K, 4>`; see [`DaryHeapWithMap`] for details.
8pub type QuaternaryHeapWithMap<N, K> = DaryHeapWithMap<N, K, 4>;
9
10/// A d-ary heap which implements both `PriorityQueue` and `PriorityQueueDecKey`.
11///
12/// See [`PriorityQueueDecKey`] for additional functionalities.
13///
14/// `DaryHeapWithMap` achieves the additional features by making use of a map of nodes to positions on the heap.
15///
16/// # Flexibility (`DaryHeapWithMap`) vs Performance (`DaryHeapOfIndices`)
17///
18/// [`DaryHeapWithMap`] (hence its variants such as [`BinaryHeapWithMap`]) does not require to know
19/// the absolute size of the closed set.
20/// Furthermore, the node type needs to implement `Hash + Eq` rather than `HasIndex` trait defined in this crate.
21/// Due to these, `DaryHeapWithMap` might be considered as the more flexible [`PriorityQueueDecKey`] variant.
22///
23/// On the other hand, `DaryHeapOfIndices` (hence its variants such as `BinaryHeapOfIndices`),
24/// provides significantly faster accesses to positions of nodes on the heap.
25/// This is important for [`PriorityQueueDecKey`] operations such as `decrease_key` or `contains`.
26/// Furthermore, in many algorithms such as certain network algorithms where nodes enter and exit the queue,
27/// `index_bound` can often trivially be set to number of nodes.
28///
29/// # Examples
30///
31/// ## Heap as a `PriorityQueue`
32///
33/// Usage of d-ary heap as a basic priority queue.
34///
35/// ```
36/// use orx_priority_queue::*;
37///
38/// fn test_priority_queue<P>(mut pq: P)
39/// where
40/// P: PriorityQueue<usize, f64>
41/// {
42/// pq.clear();
43///
44/// pq.push(0, 42.0);
45/// assert_eq!(Some(&0), pq.peek().map(|x| x.node()));
46/// assert_eq!(Some(&42.0), pq.peek().map(|x| x.key()));
47///
48/// pq.push(1, 7.0);
49/// assert_eq!(Some(&1), pq.peek().map(|x| x.node()));
50/// assert_eq!(Some(&7.0), pq.peek().map(|x| x.key()));
51///
52/// let popped = pq.pop();
53/// assert_eq!(Some((1, 7.0)), popped);
54///
55/// let popped = pq.pop();
56/// assert_eq!(Some((0, 42.0)), popped);
57///
58/// assert!(pq.is_empty());
59/// }
60///
61/// // d-ary heap using a hash map to locate existing nodes (although decrease-key is not used here)
62/// test_priority_queue(DaryHeapWithMap::<_, _, 3>::default());
63/// test_priority_queue(DaryHeapWithMap::<_, _, 4>::with_capacity(16));
64/// // using type aliases to simplify signatures
65/// test_priority_queue(BinaryHeapWithMap::default());
66/// test_priority_queue(BinaryHeapWithMap::with_capacity(16));
67/// test_priority_queue(QuaternaryHeapWithMap::default());
68/// test_priority_queue(QuaternaryHeapWithMap::with_capacity(16));
69/// test_priority_queue(QuaternaryHeapWithMap::default());
70/// test_priority_queue(QuaternaryHeapWithMap::with_capacity(16));
71/// ```
72///
73/// ## Heap as a `PriorityQueueDecKey`
74///
75/// Usage of a d-ary heap as a priority queue with decrease key operation and its variants.
76///
77/// ```
78/// use orx_priority_queue::*;
79///
80/// fn test_priority_queue_deckey<P>(mut pq: P)
81/// where
82/// P: PriorityQueueDecKey<usize, f64>
83/// {
84/// pq.clear();
85///
86/// pq.push(0, 42.0);
87/// assert_eq!(Some(&0), pq.peek().map(|x| x.node()));
88/// assert_eq!(Some(&42.0), pq.peek().map(|x| x.key()));
89///
90/// pq.push(1, 17.0);
91/// assert_eq!(Some(&1), pq.peek().map(|x| x.node()));
92/// assert_eq!(Some(&17.0), pq.peek().map(|x| x.key()));
93///
94/// pq.decrease_key(&0, 7.0);
95/// assert_eq!(Some(&0), pq.peek().map(|x| x.node()));
96/// assert_eq!(Some(&7.0), pq.peek().map(|x| x.key()));
97///
98/// let res_try_deckey = pq.try_decrease_key(&1, 20.0);
99/// assert_eq!(res_try_deckey, ResTryDecreaseKey::Unchanged);
100///
101/// let popped = pq.pop();
102/// assert_eq!(Some((0, 7.0)), popped);
103///
104/// let popped = pq.pop();
105/// assert_eq!(Some((1, 17.0)), popped);
106///
107/// assert!(pq.is_empty());
108/// }
109/// // d-ary heap using a hash map to locate existing nodes
110/// test_priority_queue_deckey(DaryHeapWithMap::<_, _, 3>::default());
111/// test_priority_queue_deckey(DaryHeapWithMap::<_, _, 4>::with_capacity(16));
112/// // using type aliases to simplify signatures
113/// test_priority_queue_deckey(BinaryHeapWithMap::default());
114/// test_priority_queue_deckey(BinaryHeapWithMap::with_capacity(16));
115/// test_priority_queue_deckey(QuaternaryHeapWithMap::default());
116/// test_priority_queue_deckey(QuaternaryHeapWithMap::with_capacity(16));
117/// test_priority_queue_deckey(QuaternaryHeapWithMap::default());
118/// test_priority_queue_deckey(QuaternaryHeapWithMap::with_capacity(16));
119/// ```
120#[derive(Debug, Clone)]
121pub struct DaryHeapWithMap<N, K, const D: usize = 2>
122where
123 N: Index,
124 K: PartialOrd + Clone,
125{
126 heap: Heap<N, K, HeapPositionsMap<N>, D>,
127}
128
129impl<N, K, const D: usize> Default for DaryHeapWithMap<N, K, D>
130where
131 N: Index,
132 K: PartialOrd + Clone,
133{
134 fn default() -> Self {
135 Self {
136 heap: Heap::new(None, HeapPositionsMap::default()),
137 }
138 }
139}
140
141/// Creates a d-ary heap from an iterator in linear time.
142///
143/// The iterator must not contain the same node more than once.
144impl<N, K, const D: usize> FromIterator<(N, K)> for DaryHeapWithMap<N, K, D>
145where
146 N: Index,
147 K: PartialOrd + Clone,
148{
149 fn from_iter<I: IntoIterator<Item = (N, K)>>(iter: I) -> Self {
150 Self {
151 heap: Heap::from_iter(iter, HeapPositionsMap::default()),
152 }
153 }
154}
155
156/// The iterator must not contain the same node more than once.
157impl<N, K, const D: usize> DaryHeapWithMap<N, K, D>
158where
159 N: Index,
160 K: PartialOrd + Clone,
161{
162 /// Creates a new empty d-ary heap.
163 ///
164 /// # Examples
165 ///
166 /// ```
167 /// use orx_priority_queue::*;
168 ///
169 /// let mut heap = BinaryHeapWithMap::new();
170 ///
171 /// heap.push('a', 4);
172 /// heap.push('b', 42);
173 ///
174 /// assert_eq!(Some('a'), heap.pop_node());
175 /// assert_eq!(Some('b'), heap.pop_node());
176 /// assert!(heap.is_empty());
177 /// ```
178 pub fn new() -> Self {
179 Self::default()
180 }
181
182 /// Creates a new d-ary heap with the given initial `capacity` on the number of nodes to simultaneously exist on the heap.
183 pub fn with_capacity(capacity: usize) -> Self {
184 Self {
185 heap: Heap::new(Some(capacity), HeapPositionsMap::with_capacity(capacity)),
186 }
187 }
188 /// Returns the 'd' of the d-ary heap.
189 /// In other words, it represents the maximum number of children that each node on the heap can have.
190 pub const fn d() -> usize {
191 D
192 }
193
194 // additional functionalities
195 /// Returns the nodes and keys currently in the queue as a slice;
196 /// not necessarily sorted.
197 ///
198 /// # Examples
199 ///
200 /// ```
201 /// use orx_priority_queue::*;
202 ///
203 /// let mut queue = QuaternaryHeapWithMap::default();
204 /// queue.push("x", 42);
205 /// queue.push("y", 7);
206 /// queue.push("z", 99);
207 ///
208 /// let slice = queue.as_slice();
209 ///
210 /// assert_eq!(3, slice.len());
211 /// assert!(slice.contains(&("x", 42)));
212 /// assert!(slice.contains(&("y", 7)));
213 /// assert!(slice.contains(&("z", 99)));
214 /// ```
215 pub fn as_slice(&self) -> &[(N, K)] {
216 self.heap.as_slice()
217 }
218}
219
220impl<N, K, const D: usize> PriorityQueue<N, K> for DaryHeapWithMap<N, K, D>
221where
222 N: Index,
223 K: PartialOrd + Clone,
224{
225 type NodeKey<'a>
226 = &'a (N, K)
227 where
228 Self: 'a,
229 N: 'a,
230 K: 'a;
231 type Iter<'a>
232 = core::slice::Iter<'a, (N, K)>
233 where
234 Self: 'a,
235 N: 'a,
236 K: 'a;
237
238 #[inline(always)]
239 fn len(&self) -> usize {
240 self.heap.len()
241 }
242
243 #[inline(always)]
244 fn capacity(&self) -> usize {
245 self.heap.capacity()
246 }
247
248 fn peek(&self) -> Option<&(N, K)> {
249 self.heap.peek()
250 }
251
252 fn clear(&mut self) {
253 self.heap.clear()
254 }
255
256 #[inline(always)]
257 fn pop(&mut self) -> Option<(N, K)> {
258 self.heap.pop()
259 }
260
261 #[inline(always)]
262 fn pop_node(&mut self) -> Option<N> {
263 self.heap.pop_node()
264 }
265
266 #[inline(always)]
267 fn pop_key(&mut self) -> Option<K> {
268 self.heap.pop_key()
269 }
270
271 #[inline(always)]
272 fn push(&mut self, node: N, key: K) {
273 self.heap.push(node, key)
274 }
275
276 #[inline(always)]
277 fn push_then_pop(&mut self, node: N, key: K) -> (N, K) {
278 self.heap.push_then_pop(node, key)
279 }
280
281 fn iter(&self) -> Self::Iter<'_> {
282 self.as_slice().iter()
283 }
284}
285impl<N, K, const D: usize> PriorityQueueDecKey<N, K> for DaryHeapWithMap<N, K, D>
286where
287 N: Index,
288 K: PartialOrd + Clone,
289{
290 #[inline(always)]
291 fn contains(&self, node: &N) -> bool {
292 self.heap.contains(node)
293 }
294
295 #[inline(always)]
296 fn key_of(&self, node: &N) -> Option<K> {
297 self.heap.key_of(node)
298 }
299
300 #[inline(always)]
301 fn decrease_key(&mut self, node: &N, decreased_key: K) {
302 self.heap.decrease_key(node, decreased_key)
303 }
304
305 #[inline(always)]
306 fn update_key(&mut self, node: &N, new_key: K) -> ResUpdateKey {
307 self.heap.update_key(node, new_key)
308 }
309
310 #[inline(always)]
311 fn remove(&mut self, node: &N) -> K {
312 self.heap.remove(node)
313 }
314}