diff --git a/src/dary/daryheap.rs b/src/dary/daryheap.rs index 4b6afed..d48e0d5 100644 --- a/src/dary/daryheap.rs +++ b/src/dary/daryheap.rs @@ -1,5 +1,5 @@ use super::heap::Heap; -use crate::{positions::none::HeapPositionsNone, PriorityQueue}; +use crate::{PriorityQueue, positions::none::HeapPositionsNone}; /// Type alias for `DaryHeap`; see [`DaryHeap`] for details. pub type BinaryHeap = DaryHeap; @@ -75,6 +75,19 @@ where } } } + +impl FromIterator<(N, K)> for DaryHeap +where + N: Clone, + K: PartialOrd + Clone, +{ + fn from_iter>(iter: I) -> Self { + Self { + heap: Heap::from_iter(iter, HeapPositionsNone), + } + } +} + impl DaryHeap where N: Clone, diff --git a/src/dary/daryheap_index.rs b/src/dary/daryheap_index.rs index 8831a91..9ea62b6 100644 --- a/src/dary/daryheap_index.rs +++ b/src/dary/daryheap_index.rs @@ -1,8 +1,6 @@ use super::heap::Heap; -use crate::{ - positions::has_index::HeapPositionsHasIndex, HasIndex, PriorityQueue, PriorityQueueDecKey, - ResUpdateKey, -}; +use crate::positions::has_index::HeapPositionsHasIndex; +use crate::{HasIndex, PriorityQueue, PriorityQueueDecKey, ResUpdateKey}; /// Type alias for `DaryHeapOfIndices`; see [`DaryHeapOfIndices`] for details. pub type BinaryHeapOfIndices = DaryHeapOfIndices; @@ -147,6 +145,18 @@ where N: HasIndex, K: PartialOrd + Clone, { + /// Creates a d-ary heap from an iterator in linear time. + /// + /// The `index_bound` is the exclusive upper bound of node indices that may enter the heap. + pub fn from_iter_with_index_bound(index_bound: usize, iter: I) -> Self + where + I: IntoIterator, + { + Self { + heap: Heap::from_iter(iter, HeapPositionsHasIndex::with_index_bound(index_bound)), + } + } + /// As explained in [`DaryHeapOfIndices`], /// this heap is useful when the nodes come from a closed set with a known size. /// Therefore, the heap has a strict exclusive upper bound on the index of a node which can enter the heap, diff --git a/src/dary/daryheap_map.rs b/src/dary/daryheap_map.rs index 9363a81..f72ccd6 100644 --- a/src/dary/daryheap_map.rs +++ b/src/dary/daryheap_map.rs @@ -1,8 +1,6 @@ use super::heap::Heap; -use crate::{ - positions::map::{HeapPositionsMap, Index}, - PriorityQueue, PriorityQueueDecKey, ResUpdateKey, -}; +use crate::positions::map::{HeapPositionsMap, Index}; +use crate::{PriorityQueue, PriorityQueueDecKey, ResUpdateKey}; /// Type alias for `DaryHeapWithMap`; see [`DaryHeapWithMap`] for details. pub type BinaryHeapWithMap = DaryHeapWithMap; @@ -139,6 +137,23 @@ where } } } + +/// Creates a d-ary heap from an iterator in linear time. +/// +/// The iterator must not contain the same node more than once. +impl FromIterator<(N, K)> for DaryHeapWithMap +where + N: Index, + K: PartialOrd + Clone, +{ + fn from_iter>(iter: I) -> Self { + Self { + heap: Heap::from_iter(iter, HeapPositionsMap::default()), + } + } +} + +/// The iterator must not contain the same node more than once. impl DaryHeapWithMap where N: Index, @@ -207,8 +222,18 @@ where N: Index, K: PartialOrd + Clone, { - type NodeKey<'a> = &'a (N, K) where Self: 'a, N: 'a, K: 'a; - type Iter<'a> = core::slice::Iter<'a, (N, K)> where Self: 'a, N: 'a, K: 'a; + type NodeKey<'a> + = &'a (N, K) + where + Self: 'a, + N: 'a, + K: 'a; + type Iter<'a> + = core::slice::Iter<'a, (N, K)> + where + Self: 'a, + N: 'a, + K: 'a; #[inline(always)] fn len(&self) -> usize { diff --git a/src/dary/heap.rs b/src/dary/heap.rs index ff44828..1fa9d62 100644 --- a/src/dary/heap.rs +++ b/src/dary/heap.rs @@ -1,7 +1,7 @@ use super::daryheap_const_helpers::{left_child_of, offset, parent_of}; use crate::{ - positions::heap_positions::{HeapPositions, HeapPositionsDecKey}, PriorityQueue, PriorityQueueDecKey, ResUpdateKey, + positions::heap_positions::{HeapPositions, HeapPositionsDecKey}, }; use alloc::vec::Vec; @@ -30,6 +30,33 @@ where Self { tree, positions } } + pub fn from_iter(iter: I, mut positions: P) -> Self + where + I: IntoIterator, + { + let mut tree: Vec<_> = iter.into_iter().collect(); + + if let Some((node, key)) = tree.first().cloned() { + let heap_offset = offset::(); + let mut padded_tree = Vec::with_capacity(tree.len() + heap_offset); + padded_tree.extend((0..heap_offset).map(|_| (node.clone(), key.clone()))); + padded_tree.append(&mut tree); + tree = padded_tree; + + for (position, (node, _key)) in tree.iter().enumerate().skip(heap_offset) { + positions.insert(node, position); + } + + let mut heap = Self { tree, positions }; + for position in (heap_offset..heap.tree.len()).rev() { + heap.heapify_down(position); + } + heap + } else { + Self { tree, positions } + } + } + fn insert_offset(&mut self, node: &N, key: &K) { self.tree .extend((0..offset::()).map(|_| (node.clone(), key.clone()))); diff --git a/src/impl_queues/priority_queue.rs b/src/impl_queues/priority_queue.rs index 05019fb..909f6ee 100644 --- a/src/impl_queues/priority_queue.rs +++ b/src/impl_queues/priority_queue.rs @@ -1,5 +1,5 @@ use crate::{ - priority_queue::PriorityQueue, PriorityQueueDecKey, ResTryDecreaseKeyOrPush, ResUpdateKey, + PriorityQueueDecKey, ResTryDecreaseKeyOrPush, ResUpdateKey, priority_queue::PriorityQueue, }; use std::hash::Hash; @@ -8,8 +8,18 @@ where K: PartialOrd + Ord, N: Ord + Hash, { - type NodeKey<'a> = (&'a N, &'a K) where Self: 'a, N: 'a, K: 'a; - type Iter<'a> = priority_queue::core_iterators::Iter<'a, N, K> where Self: 'a, N: 'a, K: 'a; + type NodeKey<'a> + = (&'a N, &'a K) + where + Self: 'a, + N: 'a, + K: 'a; + type Iter<'a> + = priority_queue::core_iterators::Iter<'a, N, K> + where + Self: 'a, + N: 'a, + K: 'a; fn len(&self) -> usize { priority_queue::PriorityQueue::len(self) diff --git a/src/impl_queues/std_binary_heap.rs b/src/impl_queues/std_binary_heap.rs index e2c5800..895d3cd 100644 --- a/src/impl_queues/std_binary_heap.rs +++ b/src/impl_queues/std_binary_heap.rs @@ -5,8 +5,18 @@ where K: PartialOrd + Ord, N: Ord, { - type NodeKey<'a> = &'a (N, K) where Self: 'a, N: 'a, K: 'a; - type Iter<'a> = alloc::collections::binary_heap::Iter<'a, (N, K)> where Self: 'a, N: 'a, K: 'a; + type NodeKey<'a> + = &'a (N, K) + where + Self: 'a, + N: 'a, + K: 'a; + type Iter<'a> + = alloc::collections::binary_heap::Iter<'a, (N, K)> + where + Self: 'a, + N: 'a, + K: 'a; #[inline(always)] fn len(&self) -> usize { diff --git a/tests/daryheap.rs b/tests/daryheap.rs index f29104b..55018a5 100644 --- a/tests/daryheap.rs +++ b/tests/daryheap.rs @@ -31,3 +31,21 @@ fn test_dary_for() { test_push_then_pop(new_heap()); test_push_then_pop_randomized(new_heap()); } + +#[test] +fn from_iter_heapifies() { + use orx_priority_queue::PriorityQueue; + + let mut heap = [(0, 42), (1, 7), (2, 24), (3, 3), (4, 99), (5, 11)] + .into_iter() + .collect::>(); + + assert_eq!(heap.len(), 6); + assert_eq!(heap.pop(), Some((3, 3))); + assert_eq!(heap.pop(), Some((1, 7))); + assert_eq!(heap.pop(), Some((5, 11))); + assert_eq!(heap.pop(), Some((2, 24))); + assert_eq!(heap.pop(), Some((0, 42))); + assert_eq!(heap.pop(), Some((4, 99))); + assert_eq!(heap.pop(), None); +} diff --git a/tests/daryheap_of_indices.rs b/tests/daryheap_of_indices.rs index b0b9159..c4c210f 100644 --- a/tests/daryheap_of_indices.rs +++ b/tests/daryheap_of_indices.rs @@ -50,3 +50,22 @@ fn test_dary_for() { .iter() .for_each(|change_key_method| test_change_key_or_push(new_heap(), *change_key_method)); } + +#[test] +fn from_iter_with_index_bound_heapifies_and_tracks_positions() { + use orx_priority_queue::{DaryHeapOfIndices, PriorityQueue, PriorityQueueDecKey}; + + let mut heap = DaryHeapOfIndices::::from_iter_with_index_bound( + 4, + [(0, 42), (1, 7), (2, 24), (3, 3)], + ); + + assert_eq!(heap.key_of(&0), Some(42)); + assert_eq!(heap.key_of(&1), Some(7)); + assert_eq!(heap.key_of(&2), Some(24)); + assert_eq!(heap.key_of(&3), Some(3)); + assert_eq!(heap.pop(), Some((3, 3))); + assert_eq!(heap.pop(), Some((1, 7))); + assert_eq!(heap.pop(), Some((2, 24))); + assert_eq!(heap.pop(), Some((0, 42))); +} diff --git a/tests/daryheap_with_map.rs b/tests/daryheap_with_map.rs index 46a2a52..d08a6dd 100644 --- a/tests/daryheap_with_map.rs +++ b/tests/daryheap_with_map.rs @@ -50,3 +50,21 @@ fn test_dary_for() { .iter() .for_each(|change_key_method| test_change_key_or_push(new_heap(), *change_key_method)); } + +#[test] +fn from_iter_heapifies_and_tracks_positions() { + use orx_priority_queue::{PriorityQueue, PriorityQueueDecKey, QuaternaryHeapWithMap}; + + let mut heap = [(0, 42), (1, 7), (2, 24), (3, 3)] + .into_iter() + .collect::>(); + + assert_eq!(heap.key_of(&0), Some(42)); + assert_eq!(heap.key_of(&1), Some(7)); + assert_eq!(heap.key_of(&2), Some(24)); + assert_eq!(heap.key_of(&3), Some(3)); + assert_eq!(heap.pop(), Some((3, 3))); + assert_eq!(heap.pop(), Some((1, 7))); + assert_eq!(heap.pop(), Some((2, 24))); + assert_eq!(heap.pop(), Some((0, 42))); +} diff --git a/tests/priority_queue_deckey_tests/mod.rs b/tests/priority_queue_deckey_tests/mod.rs index 6799089..96910ff 100644 --- a/tests/priority_queue_deckey_tests/mod.rs +++ b/tests/priority_queue_deckey_tests/mod.rs @@ -5,7 +5,7 @@ mod key_of; mod mixed; mod remove; -pub use change_key::{test_change_key, ChangeKeyMethod}; +pub use change_key::{ChangeKeyMethod, test_change_key}; pub use change_key_or_push::test_change_key_or_push; pub use contains::test_contains; pub use key_of::test_key_of;