├── .gitignore ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── release.toml ├── Cargo.toml ├── benches └── bench.rs ├── tests ├── regression.rs ├── fake_heap.rs └── random.rs ├── LICENSE-MIT ├── README.md ├── CHANGELOG.md ├── src ├── index.rs ├── hole.rs └── lib.rs └── LICENSE-APACHE /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | target/ 3 | cmake-build-*/ 4 | .idea/ 5 | 6 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "11:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | pre-release-replacements = [ 2 | { file="README.md", search="min-max-heap = \"[0-9.]*\"", replace="min-max-heap = \"{{version}}\"" }, 3 | { file="src/lib.rs", search="min-max-heap = \"[0-9.]*\"", replace="min-max-heap = \"{{version}}\"" }, 4 | { file="src/lib.rs", search="https://docs[.]rs/min-max-heap/[0-9.]*", replace="https://docs.rs/min-max-heap/{{version}}" }, 5 | { file="CHANGELOG.md", search="\\[Unreleased\\]", replace="[{{version}}] - {{date}}" } 6 | ] 7 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "min-max-heap" 3 | version = "1.3.1-alpha.0" 4 | authors = ["Jesse A. Tov "] 5 | description = "An efficient, double-ended priority queue" 6 | repository = "https://github.com/tov/min-max-heap-rs" 7 | readme = "README.md" 8 | license = "MIT/Apache-2.0" 9 | keywords = ["heap", "priority-queue"] 10 | categories = ["data-structures"] 11 | edition = "2018" 12 | 13 | [dependencies] 14 | serde = { version = "1.0", optional = true, features = ["derive"] } 15 | 16 | [dev-dependencies] 17 | rand = "0.8" 18 | quickcheck = "1.0" 19 | 20 | [package.metadata.docs.rs] 21 | features = ["serde"] 22 | 23 | -------------------------------------------------------------------------------- /benches/bench.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | extern crate test; 4 | 5 | use min_max_heap::MinMaxHeap; 6 | use test::Bencher; 7 | 8 | #[bench] 9 | fn push_seq(b: &mut Bencher) { 10 | b.iter(|| { 11 | let n = 1000; 12 | let mut heap = MinMaxHeap::with_capacity(n); 13 | for i in 0..n { 14 | heap.push(i); 15 | } 16 | }); 17 | } 18 | 19 | #[bench] 20 | fn pop_max_seq(b: &mut Bencher) { 21 | b.iter(|| { 22 | let n = 1000; 23 | let mut heap: MinMaxHeap<_> = (0..n).collect(); 24 | for _ in 0..n { 25 | heap.pop_max(); 26 | } 27 | }); 28 | } 29 | 30 | #[bench] 31 | fn pop_min_seq(b: &mut Bencher) { 32 | b.iter(|| { 33 | let n = 1000; 34 | let mut heap: MinMaxHeap<_> = (0..n).collect(); 35 | for _ in 0..n { 36 | heap.pop_min(); 37 | } 38 | }); 39 | } 40 | 41 | -------------------------------------------------------------------------------- /tests/regression.rs: -------------------------------------------------------------------------------- 1 | use min_max_heap::MinMaxHeap; 2 | 3 | #[test] 4 | fn random_20211219() { 5 | let mut h = MinMaxHeap::::new(); 6 | 7 | // 0 8 | assert_eq!( h.replace_max(0), None ); 9 | assert_eq!( h.len(), 1 ); 10 | 11 | // 0 1 12 | h.push(1); 13 | assert_eq!( h.len(), 2 ); 14 | assert_eq!( h.peek_min(), Some(&0) ); 15 | assert_eq!( h.peek_max(), Some(&1) ); 16 | 17 | // 0 0 1 18 | h.push(0); 19 | assert_eq!( h.len(), 3 ); 20 | assert_eq!( h.peek_min(), Some(&0) ); 21 | assert_eq!( h.peek_max(), Some(&1) ); 22 | 23 | // 0 0 1 1 24 | h.push(1); 25 | assert_eq!( h.len(), 4 ); 26 | assert_eq!( h.peek_min(), Some(&0) ); 27 | assert_eq!( h.peek_max(), Some(&1) ); 28 | 29 | // 0 0 0 1 30 | assert_eq!( h.replace_max(0), Some(1) ); 31 | assert_eq!( h.len(), 4 ); 32 | assert_eq!( h.peek_min(), Some(&0) ); 33 | assert_eq!( h.peek_max(), Some(&1) ); 34 | 35 | assert_eq!( h.into_vec_asc(), vec![0, 0, 0, 1] ); 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Jesse A. Tov 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # min-max-heap: a double-ended priority queue 2 | 3 | [![Build Status]][CI] 4 | [![Crates.io]][crate] 5 | [![License: MIT]](LICENSE-MIT) 6 | [![License: Apache 2.0]](LICENSE-APACHE) 7 | 8 | [Build Status]: 9 | 10 | 11 | [CI]: 12 | 13 | 14 | [Crates.io]: 15 | 16 | 17 | [crate]: 18 | 19 | 20 | [License: MIT]: 21 | 22 | 23 | [License: Apache 2.0]: 24 | 25 | 26 | A min-max-heap is like a binary heap, but it allows extracting both the 27 | minimum and maximum value efficiently. In particular, finding either the 28 | minimum or maximum element is worst-case *O*(1) time. A removal of either 29 | extreme, or an insertion, is worst-case *O*(log *n*) time. 30 | 31 | ## Usage 32 | 33 | It’s [on crates.io][crate], so add this to your `Cargo.toml`: 34 | 35 | ```toml 36 | [dependencies] 37 | min-max-heap = "1.3.0" 38 | ``` 39 | 40 | This crate supports Rust version 1.46 and later. 41 | 42 | ## References 43 | 44 | - M. D. Atkinson, J.-R. Sack, N. Santoro, and T. Strothot. 45 | Ian Munro (ed.). “[Min-Max Heaps and Generalized Priority 46 | Queues][Atkinson86].” In *Communications of the ACM.* 29(10): 47 | 996–1000, June 1996. \[[pdf][Atkinson86]\] 48 | 49 | - The Rust Standard Library’s [`BinaryHeap`] API and 50 | implementation. \[[src][binary_heap.rs]\] 51 | 52 | [Atkinson86]: 53 | 54 | 55 | [`BinaryHeap`]: 56 | 57 | 58 | [binary_heap.rs]: 59 | 60 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: CI 4 | 5 | jobs: 6 | check: 7 | name: Check 8 | runs-on: ubuntu-latest 9 | continue-on-error: ${{ matrix.experimental }} 10 | strategy: 11 | matrix: 12 | rust: 13 | - stable 14 | - 1.46.0 15 | flags: 16 | - --lib --tests 17 | - --lib --tests --features=serde 18 | experimental: [false] 19 | include: 20 | - rust: nightly 21 | flags: --all-targets --features=serde 22 | experimental: true 23 | steps: 24 | - uses: actions/checkout@v2 25 | - uses: actions-rs/toolchain@v1 26 | with: 27 | profile: minimal 28 | toolchain: ${{ matrix.rust }} 29 | override: true 30 | - uses: actions-rs/cargo@v1 31 | with: 32 | command: check 33 | args: ${{ matrix.flags }} 34 | 35 | test: 36 | name: Test Suite 37 | runs-on: ubuntu-latest 38 | continue-on-error: ${{ matrix.experimental }} 39 | strategy: 40 | matrix: 41 | rust: 42 | - stable 43 | - 1.46.0 44 | flags: 45 | - "" 46 | - --features=serde 47 | experimental: [false] 48 | include: 49 | - rust: nightly 50 | flags: --features=serde 51 | experimental: true 52 | steps: 53 | - uses: actions/checkout@v2 54 | - uses: actions-rs/toolchain@v1 55 | with: 56 | profile: minimal 57 | toolchain: ${{ matrix.rust }} 58 | override: true 59 | - uses: actions-rs/cargo@v1 60 | with: 61 | command: test 62 | args: ${{ matrix.flags }} 63 | 64 | clippy: 65 | name: Clippy 66 | runs-on: ubuntu-latest 67 | continue-on-error: ${{ matrix.experimental }} 68 | strategy: 69 | matrix: 70 | rust: 71 | - stable 72 | - 1.46.0 73 | flags: 74 | - "" 75 | - --features=serde 76 | experimental: [false] 77 | include: 78 | - rust: nightly 79 | flags: --features=serde 80 | experimental: true 81 | steps: 82 | - uses: actions/checkout@v2 83 | - uses: actions-rs/toolchain@v1 84 | with: 85 | profile: minimal 86 | toolchain: ${{ matrix.rust }} 87 | override: true 88 | - run: rustup component add clippy 89 | - uses: actions-rs/cargo@v1 90 | with: 91 | command: clippy 92 | args: ${{ matrix.flags }} -- -D warnings 93 | -------------------------------------------------------------------------------- /tests/fake_heap.rs: -------------------------------------------------------------------------------- 1 | use std::collections::btree_map::BTreeMap; 2 | 3 | #[derive(Debug, Eq, PartialEq)] 4 | pub struct FakeHeap { 5 | tree: BTreeMap, 6 | len: usize, 7 | } 8 | 9 | impl FakeHeap { 10 | pub fn new() -> Self { 11 | Self { 12 | tree: BTreeMap::new(), 13 | len: 0, 14 | } 15 | } 16 | 17 | pub fn len(&self) -> usize { 18 | self.len 19 | } 20 | 21 | #[allow(dead_code)] 22 | pub fn is_empty(&self) -> bool { 23 | self.len == 0 24 | } 25 | 26 | pub fn push(&mut self, element: T) { 27 | if let Some(found) = self.tree.get_mut(&element) { 28 | *found += 1; 29 | } else { 30 | self.tree.insert(element, 0); 31 | } 32 | 33 | self.len += 1; 34 | } 35 | 36 | pub fn peek_min(&self) -> Option<&T> { 37 | self.tree.range(..).next().map(|p| p.0) 38 | } 39 | 40 | pub fn peek_max(&self) -> Option<&T> { 41 | self.tree.range(..).next_back().map(|p| p.0) 42 | } 43 | 44 | pub fn pop_min(&mut self) -> Option { 45 | if let Some((elem, count)) = self.tree.range_mut(..).next() { 46 | let elem = elem.clone(); 47 | if let Some(pred) = count.checked_sub(1) { 48 | *count = pred; 49 | } else { 50 | self.tree.remove(&elem); 51 | } 52 | 53 | self.len -= 1; 54 | Some(elem) 55 | } else { 56 | None 57 | } 58 | } 59 | 60 | pub fn pop_max(&mut self) -> Option { 61 | if let Some((elem, count)) = self.tree.range_mut(..).next_back() { 62 | let elem = elem.clone(); 63 | if let Some(pred) = count.checked_sub(1) { 64 | *count = pred; 65 | } else { 66 | self.tree.remove(&elem); 67 | } 68 | 69 | self.len -= 1; 70 | Some(elem) 71 | } else { 72 | None 73 | } 74 | } 75 | 76 | pub fn push_pop_min(&mut self, element: T) -> T { 77 | self.push(element); 78 | self.pop_min().unwrap() 79 | } 80 | 81 | pub fn push_pop_max(&mut self, element: T) -> T { 82 | self.push(element); 83 | self.pop_max().unwrap() 84 | } 85 | 86 | pub fn replace_min(&mut self, element: T) -> Option { 87 | let result = self.pop_min(); 88 | self.push(element); 89 | result 90 | } 91 | 92 | pub fn replace_max(&mut self, element: T) -> Option { 93 | let result = self.pop_max(); 94 | self.push(element); 95 | result 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog] and this project adheres to 6 | [Semantic Versioning]. 7 | 8 | [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ 9 | [Semantic Versioning]: http://semver.org/spec/v2.0.0.html 10 | 11 | ## [1.3.0] - 2019-12-29 12 | 13 | ### Added 14 | - Methods `MinMaxHeap::peek_min_mut` and `MinMaxHeap::peek_max_mut`*. 15 | 16 | ### Changed 17 | - Oldest supported rustc version is now 1.32.0. 18 | - Updated dev dependencies `rand` (0.5 to 0.7) and `quickcheck` (0.7.2 19 | to 0.9). 20 | 21 | ## [1.2.2] - 2018-12-17 22 | 23 | ### Fixed 24 | - Removed syntax not accepted by older rustc. 25 | 26 | ## [1.2.1] - 2018-12-17 27 | 28 | ### Fixed 29 | - Documented time complexity of `push` to be worst-case linear and amortized 30 | logarithmic. 31 | - Fixed bugs in `MinMaxHeap::replace_max` and `MinMaxHeap::push_pop_max` that 32 | were corrupting the heap order. 33 | 34 | ## [1.2.0] - 2018-06-02 35 | 36 | ### Added 37 | - Two new iterator types, `DrainAsc` and `DrainDesc`, and two new methods 38 | for creating them, `MinMaxHeap::drain_asc` and `MinMaxHeap::drain_desc`. 39 | These iterators drain the heap in ascending (min-first) or descending 40 | (max-first) order, respectively. 41 | - Implementations of `Iterator::size_hint` for `Drain`, `IntoIter`, and 42 | `Iter` iterator types. 43 | 44 | ## [1.1.1] - 2018-05-30 45 | 46 | ### Added 47 | - `#[doc(html_base_url = ...)]` annotation in crate root. 48 | 49 | ## [1.1.0] - 2018-05-12 50 | 51 | ### Added 52 | - Optional serde support. Enable `"serde"` Cargo feature to get impls 53 | of `Serializable` and `Deserializable` for `MinMaxHeap`. 54 | - Documented oldest supported rustc version: 1.20. 55 | 56 | ## [1.0.4] - 2018-05-04 57 | 58 | ### Changed 59 | - Uses `ManuallyDrop` instead of `Option` in internal `Hole` 60 | implementation. (Thanks to Nikita Popov.) 61 | 62 | ## [1.0.3] - 2018-05-03 63 | 64 | ### Added 65 | - Some simple benchmarks. 66 | 67 | ### Changed 68 | - Internal `is_min_level` function uses `leading_zeros` instead of an 69 | *O*(log *n*)–time loop. 70 | 71 | ## [1.0.2] - 2018-04-01 72 | 73 | ### Fixed 74 | - Documentation URL. 75 | 76 | ## [1.0.1] - 2018-03-31 77 | 78 | ### Removed 79 | - Dependency on Clippy. Use `cargo +nightly clippy` instead. 80 | 81 | ## [1.0.0] - 2018-03-31 82 | 83 | ### Added 84 | - Automatic code coverage checking on codecov.io. 85 | 86 | ## [0.2.1] - 2016-06-13 87 | 88 | ### Fixed 89 | - Bad crate metadata. 90 | 91 | ## [0.2.0] - 2016-06-13 92 | 93 | ### Added 94 | - `MinMaxHeap::into_vec_asc` and `MinMaxHeap::into_vec_desc` methods. 95 | - Impl of `From>` for `MinMaxHeap`. 96 | 97 | ## [0.1.2] - 2016-06-13 98 | 99 | ### Removed 100 | - Clippy warnings. 101 | 102 | ## [0.1.1] - 2016-06-12 103 | 104 | ### Added 105 | - Mentioned `crates.io` in docs. 106 | 107 | ## [0.1.0] - 2016-06-12 108 | 109 | Initial release 110 | 111 | 112 | -------------------------------------------------------------------------------- /tests/random.rs: -------------------------------------------------------------------------------- 1 | use quickcheck::{Arbitrary, Gen, quickcheck}; 2 | 3 | mod fake_heap; 4 | 5 | const SCRIPT_LENGTH: usize = 1000; 6 | 7 | quickcheck! { 8 | fn prop_usize(script: Script) -> bool { 9 | script.check() 10 | } 11 | } 12 | 13 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] 14 | enum Command { 15 | Push, 16 | PopMin, 17 | PopMax, 18 | PushPopMin, 19 | PushPopMax, 20 | ReplaceMin, 21 | ReplaceMax, 22 | } 23 | 24 | #[derive(Clone, Debug, PartialEq, Eq)] 25 | struct Script(Vec<(Command, T)>); 26 | 27 | impl Arbitrary for Command { 28 | fn arbitrary(g: &mut Gen) -> Self { 29 | g.choose(COMMAND_FREQS).copied().unwrap_or(Command::Push) 30 | } 31 | 32 | fn shrink(&self) -> Box> { 33 | use Command::*; 34 | 35 | let v = match self { 36 | PushPopMin | ReplaceMin => vec![Push, PopMin], 37 | PushPopMax | ReplaceMax => vec![Push, PopMax], 38 | _ => vec![], 39 | }; 40 | 41 | Box::new(v.into_iter()) 42 | } 43 | } 44 | 45 | const COMMAND_FREQS: &[Command] = { 46 | use Command::*; 47 | &[ 48 | Push, Push, Push, 49 | PopMin, 50 | PopMax, 51 | PushPopMin, 52 | PushPopMax, 53 | ReplaceMin, 54 | ReplaceMax, 55 | ] 56 | }; 57 | 58 | impl Arbitrary for Script { 59 | fn arbitrary(g: &mut Gen) -> Self { 60 | Script((0 .. SCRIPT_LENGTH) 61 | .map(|_| (Command::arbitrary(g), T::arbitrary(g))) 62 | .collect()) 63 | } 64 | 65 | fn shrink(&self) -> Box> { 66 | Box::new(self.0.shrink().map(Script)) 67 | } 68 | } 69 | 70 | impl Script { 71 | fn check(&self) -> bool { 72 | let mut tester = Tester::new(); 73 | tester.check_script(self) 74 | } 75 | } 76 | 77 | struct Tester { 78 | real: min_max_heap::MinMaxHeap, 79 | fake: fake_heap::FakeHeap, 80 | } 81 | 82 | impl Tester { 83 | fn new() -> Self { 84 | Tester { 85 | real: min_max_heap::MinMaxHeap::new(), 86 | fake: fake_heap::FakeHeap::new(), 87 | } 88 | } 89 | 90 | fn check_script(&mut self, script: &Script) -> bool { 91 | script.0 92 | .iter() 93 | .all(|&(cmd, ref elt)| self.do_checks(cmd, elt)) 94 | } 95 | 96 | fn do_checks(&mut self, cmd: Command, elt: &T) -> bool { 97 | self.check_command(cmd, elt) 98 | && self.real.len() == self.fake.len() 99 | && self.real.peek_min() == self.fake.peek_min() 100 | && self.real.peek_max() == self.fake.peek_max() 101 | } 102 | 103 | fn check_command(&mut self, cmd: Command, elt: &T) -> bool { 104 | use Command::*; 105 | 106 | let e1 = elt.clone(); 107 | let e2 = elt.clone(); 108 | let r = &mut self.real; 109 | let f = &mut self.fake; 110 | 111 | match cmd { 112 | Push => { 113 | r.push(e1); 114 | f.push(e2); 115 | true 116 | } 117 | PopMin => r.pop_min() == f.pop_min(), 118 | PopMax => r.pop_max() == f.pop_max(), 119 | PushPopMin => r.push_pop_min(e1) == f.push_pop_min(e2), 120 | PushPopMax => r.push_pop_max(e1) == f.push_pop_max(e2), 121 | ReplaceMin => r.replace_min(e1) == f.replace_min(e2), 122 | ReplaceMax => r.replace_max(e1) == f.replace_max(e2), 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/index.rs: -------------------------------------------------------------------------------- 1 | pub trait HeapIndex { 2 | fn parent(self) -> Self; 3 | fn grandparent(self) -> Self; 4 | 5 | fn child1(self) -> Self; 6 | fn child2(self) -> Self; 7 | 8 | fn grandchild1(self) -> Self; 9 | fn grandchild2(self) -> Self; 10 | fn grandchild3(self) -> Self; 11 | fn grandchild4(self) -> Self; 12 | 13 | fn has_parent(self) -> bool; 14 | fn has_grandparent(self) -> bool; 15 | 16 | #[allow(clippy::wrong_self_convention)] 17 | fn is_min_level(self) -> bool; 18 | } 19 | 20 | impl HeapIndex for usize { 21 | fn parent(self) -> Self { (self - 1) / 2 } 22 | fn grandparent(self) -> Self { self.parent().parent() } 23 | 24 | fn child1(self) -> Self { 2 * self + 1 } 25 | fn child2(self) -> Self { 2 * self + 2 } 26 | 27 | fn grandchild1(self) -> Self { self.child1().child1() } 28 | fn grandchild2(self) -> Self { self.child1().child2() } 29 | fn grandchild3(self) -> Self { self.child2().child1() } 30 | fn grandchild4(self) -> Self { self.child2().child2() } 31 | 32 | fn has_parent(self) -> bool { 33 | self > 0 34 | } 35 | 36 | fn has_grandparent(self) -> bool { 37 | self > 2 38 | } 39 | 40 | fn is_min_level(self) -> bool { 41 | (self + 1).leading_zeros() & 1 == 1 42 | } 43 | } 44 | 45 | // 0 46 | // 1 2 47 | // 3 4 5 6 48 | // 7 8 9 10 11 12 13 14 49 | 50 | #[cfg(test)] 51 | mod test { 52 | use super::*; 53 | 54 | #[test] 55 | fn t_parent() { 56 | assert_eq!(0, 1.parent()); 57 | assert_eq!(0, 2.parent()); 58 | assert_eq!(1, 3.parent()); 59 | assert_eq!(1, 4.parent()); 60 | assert_eq!(2, 5.parent()); 61 | assert_eq!(2, 6.parent()); 62 | assert_eq!(5, 11.parent()); 63 | } 64 | 65 | #[test] 66 | fn t_child1() { 67 | assert_eq!(1, 0.child1()); 68 | assert_eq!(3, 1.child1()); 69 | assert_eq!(7, 3.child1()); 70 | assert_eq!(13, 6.child1()); 71 | } 72 | 73 | #[test] 74 | fn t_child2() { 75 | assert_eq!(2, 0.child2()); 76 | assert_eq!(4, 1.child2()); 77 | assert_eq!(8, 3.child2()); 78 | assert_eq!(14, 6.child2()); 79 | } 80 | 81 | #[test] 82 | fn t_grandchild1() { 83 | assert_eq!(3, 0.grandchild1()); 84 | assert_eq!(7, 1.grandchild1()); 85 | assert_eq!(11, 2.grandchild1()); 86 | } 87 | 88 | #[test] 89 | fn t_grandchild2() { 90 | assert_eq!(4, 0.grandchild2()); 91 | assert_eq!(8, 1.grandchild2()); 92 | assert_eq!(12, 2.grandchild2()); 93 | } 94 | 95 | #[test] 96 | fn t_grandchild3() { 97 | assert_eq!(5, 0.grandchild3()); 98 | assert_eq!(9, 1.grandchild3()); 99 | assert_eq!(13, 2.grandchild3()); 100 | } 101 | 102 | #[test] 103 | fn t_grandchild4() { 104 | assert_eq!(6, 0.grandchild4()); 105 | assert_eq!(10, 1.grandchild4()); 106 | assert_eq!(14, 2.grandchild4()); 107 | } 108 | 109 | #[test] 110 | fn t_has_parent() { 111 | assert!(! 0.has_parent()); 112 | assert!(1.has_parent()); 113 | assert!(2.has_parent()); 114 | assert!(3.has_parent()); 115 | } 116 | 117 | #[test] 118 | fn t_has_grandparent() { 119 | assert!(! 0.has_grandparent()); 120 | assert!(! 1.has_grandparent()); 121 | assert!(! 2.has_grandparent()); 122 | assert!(3.has_grandparent()); 123 | assert!(4.has_grandparent()); 124 | assert!(5.has_grandparent()); 125 | assert!(6.has_grandparent()); 126 | } 127 | 128 | #[test] 129 | fn t_is_min_level() { 130 | assert!(0.is_min_level()); 131 | assert!(!1.is_min_level()); 132 | assert!(!2.is_min_level()); 133 | assert!(3.is_min_level()); 134 | assert!(4.is_min_level()); 135 | assert!(5.is_min_level()); 136 | assert!(6.is_min_level()); 137 | assert!(!7.is_min_level()); 138 | assert!(!8.is_min_level()); 139 | assert!(!9.is_min_level()); 140 | assert!(!10.is_min_level()); 141 | assert!(!11.is_min_level()); 142 | assert!(!12.is_min_level()); 143 | assert!(!13.is_min_level()); 144 | assert!(!14.is_min_level()); 145 | assert!(15.is_min_level()); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/hole.rs: -------------------------------------------------------------------------------- 1 | use std::{mem, ptr}; 2 | use std::mem::ManuallyDrop; 3 | 4 | use super::index::*; 5 | 6 | // From std::collections::BinaryHeap: 7 | pub struct Hole<'a, T: 'a> { 8 | data: &'a mut [T], 9 | elt: ManuallyDrop, 10 | pos: usize, 11 | } 12 | 13 | enum Generation { 14 | Child, 15 | Grandchild, 16 | } 17 | 18 | impl<'a, T> Hole<'a, T> { 19 | /// Create a new Hole at index `pos`. 20 | /// 21 | /// Caller must ensure that `pos` is a valid index in `data`. 22 | pub unsafe fn new(data: &'a mut [T], pos: usize) -> Self { 23 | debug_assert!(pos < data.len()); 24 | let elt = ptr::read(data.get_unchecked(pos)); 25 | Hole { data, elt: ManuallyDrop::new(elt), pos } 26 | } 27 | 28 | #[inline] 29 | fn pos(&self) -> usize { 30 | self.pos 31 | } 32 | 33 | /// Return a reference to the element removed 34 | #[inline] 35 | pub fn element(&self) -> &T { 36 | &self.elt 37 | } 38 | 39 | #[inline] 40 | pub fn get_parent(&mut self) -> Option> { 41 | if self.pos().has_parent() { 42 | // SAFETY: parent is a valid index and not equal to `pos` 43 | Some(unsafe { HoleSwap::new(self, self.pos().parent()) }) 44 | } else { 45 | None 46 | } 47 | } 48 | 49 | #[inline] 50 | fn get_grandparent(&mut self) -> Option> { 51 | if self.pos().has_grandparent() { 52 | // SAFETY: grandparent is a valid index and not equal to `pos` 53 | Some(unsafe { HoleSwap::new(self, self.pos().grandparent()) }) 54 | } else { 55 | None 56 | } 57 | } 58 | 59 | #[inline] 60 | fn on_min_level(&self) -> bool { 61 | self.pos().is_min_level() 62 | } 63 | 64 | #[inline] 65 | fn best_child_or_grandchild(&mut self, f: F) 66 | -> Option<(HoleSwap<'a, '_, T>, Generation)> 67 | where 68 | F: Fn(&T, &T) -> bool, 69 | { 70 | let data = &*self.data; 71 | let here = self.pos(); 72 | 73 | let mut best = None; 74 | let mut element = self.element(); 75 | 76 | { 77 | let mut check = |index, generation| { 78 | data.get(index).map(|candidate| { 79 | if f(candidate, element) { 80 | best = Some((index, generation)); 81 | element = candidate; 82 | } 83 | }) 84 | }; 85 | 86 | (|| { 87 | check(here.child1(), Generation::Child)?; 88 | check(here.child2(), Generation::Child)?; 89 | check(here.grandchild1(), Generation::Grandchild)?; 90 | check(here.grandchild2(), Generation::Grandchild)?; 91 | check(here.grandchild3(), Generation::Grandchild)?; 92 | check(here.grandchild4(), Generation::Grandchild)?; 93 | Some(()) 94 | })(); 95 | } 96 | 97 | best.map(move |(index, generation)| { 98 | // SAFETY: `index` is a valid index and not equal to `here` 99 | let best = unsafe { HoleSwap::new(self, index) }; 100 | (best, generation) 101 | }) 102 | } 103 | 104 | fn trickle_down_best(&mut self, f: F) where F: Fn(&T, &T) -> bool { 105 | while let Some((best, generation)) = self.best_child_or_grandchild(&f) { 106 | best.move_to(); 107 | match generation { 108 | Generation::Grandchild => { 109 | // SAFETY: `pos` has a parent since it has a grandparent 110 | let mut parent = unsafe { HoleSwap::new(self, self.pos().parent()) }; 111 | if f(parent.other_element(), parent.hole_element()) { 112 | parent.swap_with(); 113 | } 114 | } 115 | Generation::Child => return, 116 | } 117 | } 118 | } 119 | } 120 | 121 | impl<'a, T: Ord> Hole<'a, T> { 122 | pub fn bubble_up(&mut self) { 123 | if self.on_min_level() { 124 | match self.get_parent() { 125 | Some(parent) if parent.hole_element() > parent.other_element() => { 126 | parent.move_to(); 127 | self.bubble_up_max(); 128 | } 129 | _ => self.bubble_up_min(), 130 | } 131 | } else { 132 | match self.get_parent() { 133 | Some(parent) if parent.hole_element() < parent.other_element() => { 134 | parent.move_to(); 135 | self.bubble_up_min(); 136 | } 137 | _ => self.bubble_up_max(), 138 | } 139 | } 140 | } 141 | 142 | fn bubble_up_grandparent(&mut self, f: F) where F: Fn(&T, &T) -> bool { 143 | while let Some(grandparent) = self.get_grandparent() { 144 | if f(grandparent.hole_element(), grandparent.other_element()) { 145 | grandparent.move_to(); 146 | } else { 147 | return; 148 | } 149 | } 150 | } 151 | 152 | fn bubble_up_min(&mut self) { 153 | self.bubble_up_grandparent(PartialOrd::lt); 154 | } 155 | 156 | fn bubble_up_max(&mut self) { 157 | self.bubble_up_grandparent(PartialOrd::gt); 158 | } 159 | 160 | pub fn trickle_down(&mut self) { 161 | if self.on_min_level() { 162 | self.trickle_down_min(); 163 | } else { 164 | self.trickle_down_max(); 165 | } 166 | } 167 | 168 | pub fn trickle_down_min(&mut self) { 169 | self.trickle_down_best(PartialOrd::lt); 170 | } 171 | 172 | pub fn trickle_down_max(&mut self) { 173 | self.trickle_down_best(PartialOrd::gt); 174 | } 175 | } 176 | 177 | impl<'a, T> Drop for Hole<'a, T> { 178 | fn drop(&mut self) { 179 | unsafe { 180 | // SAFETY: `elt` is being moved into the hole 181 | let elt = ptr::read(&*self.elt); 182 | // SAFETY: `pos` is a valid index in `data` and is a hole 183 | ptr::write(self.data.get_unchecked_mut(self.pos()), elt); 184 | } 185 | } 186 | } 187 | 188 | /// A hole, along with a potential new position to move it to. 189 | /// This replaces some unsafe blocks with safety requirements on the constructor. 190 | pub struct HoleSwap<'a, 'b, T> { 191 | hole: &'b mut Hole<'a, T>, 192 | index: usize, 193 | } 194 | 195 | impl<'a, 'b, T> HoleSwap<'a, 'b, T> { 196 | /// Caller must ensure that `index` is a valid index in `data` 197 | /// and not equal to `pos`. 198 | unsafe fn new(hole: &'b mut Hole<'a, T>, index: usize) -> Self { 199 | debug_assert!(index != hole.pos()); 200 | debug_assert!(index < hole.data.len()); 201 | HoleSwap { hole, index } 202 | } 203 | 204 | /// The element currently pulled out of the hole. 205 | pub fn hole_element(&self) -> &T { 206 | self.hole.element() 207 | } 208 | 209 | /// The element at the index to potentially move to. 210 | pub fn other_element(&self) -> &T { 211 | // SAFETY: `index` is a valid index in `data` and not a hole 212 | unsafe { self.hole.data.get_unchecked(self.index) } 213 | } 214 | 215 | /// Move `other_element()` into the current hole 216 | /// and move the hole to where `other_element()` was. 217 | /// This invalidates the `HoleSwap`. 218 | pub fn move_to(self) { 219 | unsafe { 220 | // SAFETY: `index` is a valid index in `data` and not a hole 221 | let elt = ptr::read(self.other_element()); 222 | // SAFETY: `pos` is a valid index in `data` and a hole 223 | ptr::write(self.hole.data.get_unchecked_mut(self.hole.pos()), elt); 224 | } 225 | self.hole.pos = self.index; 226 | } 227 | 228 | /// Swaps `hole_element()` with `other_element()`, without moving the hole 229 | pub fn swap_with(&mut self) { 230 | // SAFETY: `index` is a valid index in `data` and not a hole 231 | let other_element = unsafe { self.hole.data.get_unchecked_mut(self.index) }; 232 | mem::swap(other_element, &mut self.hole.elt); 233 | } 234 | } 235 | 236 | #[cfg(test)] 237 | mod test { 238 | use super::*; 239 | 240 | #[test] 241 | fn hole() { 242 | let mut v = vec![0, 1, 2, 3, 4, 5]; 243 | unsafe { 244 | let mut h = Hole::new(&mut v, 1); 245 | 246 | assert_eq!(1, h.pos()); 247 | assert_eq!(1, *h.element()); 248 | assert_eq!(2, h.data[2]); 249 | 250 | HoleSwap::new(&mut h, 4).move_to(); 251 | 252 | assert_eq!(4, h.pos()); 253 | assert_eq!(1, *h.element()); 254 | assert_eq!(4, h.data[1]); 255 | assert_eq!(2, h.data[2]); 256 | } 257 | 258 | assert_eq!(vec![0, 4, 2, 3, 1, 5], v); 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc(html_root_url = "https://docs.rs/min-max-heap/1.3.0")] 2 | //! A double-ended priority queue. 3 | //! 4 | //! A min-max-heap is like a binary heap, but it allows extracting both 5 | //! the minimum and maximum value efficiently. In particular, finding 6 | //! either the minimum or maximum element is worst-case *O*(1) time. A 7 | //! removal of either extreme, or an insertion, is worst-case 8 | //! *O*(log *n*) time. 9 | //! 10 | //! ## Usage 11 | //! 12 | //! It’s [on crates.io](https://crates.io/crates/min-max-heap), so add 13 | //! this to your `Cargo.toml`: 14 | //! 15 | //! ```toml 16 | //! [dependencies] 17 | //! min-max-heap = "1.3.0" 18 | //! ``` 19 | //! 20 | //! This crate supports Rust version 1.46 and later. 21 | //! 22 | //! ## References 23 | //! 24 | //! - M. D. Atkinson, J.-R. Sack, N. Santoro, and T. Strothot. 25 | //! Ian Munro (ed.). “[Min-Max Heaps and Generalized Priority 26 | //! Queues][Atkinson86].” In *Communications of the ACM.* 29(10): 27 | //! 996–1000, June 1996. \[[pdf][Atkinson86]\] 28 | //! 29 | //! - The Rust Standard Library’s [`BinaryHeap`] API and 30 | //! implementation. \[[src][binary_heap.rs]\] 31 | //! 32 | //! [Atkinson86]: 33 | //! 34 | //! 35 | //! [`BinaryHeap`]: 36 | //! std::collections::binary_heap::BinaryHeap 37 | //! 38 | //! [binary_heap.rs]: 39 | //! 40 | 41 | #![warn(missing_docs)] 42 | 43 | #[cfg(feature = "serde")] 44 | use serde::{Serialize, Deserialize}; 45 | 46 | use std::iter::FromIterator; 47 | use std::{fmt, mem, slice, vec}; 48 | use std::ops::{Deref, DerefMut}; 49 | 50 | mod hole; 51 | mod index; 52 | 53 | use self::hole::*; 54 | 55 | /// A double-ended priority queue. 56 | /// 57 | /// Most operations are *O*(log *n*). 58 | #[derive(Clone, Debug)] 59 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 60 | pub struct MinMaxHeap(Vec); 61 | 62 | impl Default for MinMaxHeap { 63 | fn default() -> Self { 64 | MinMaxHeap::new() 65 | } 66 | } 67 | 68 | impl MinMaxHeap { 69 | /// Creates a new, empty `MinMaxHeap`. 70 | /// 71 | /// *O*(1). 72 | pub fn new() -> Self { 73 | MinMaxHeap(Vec::new()) 74 | } 75 | 76 | /// Creates a new, empty `MinMaxHeap` with space allocated to hold 77 | /// `len` elements. 78 | /// 79 | /// *O*(n). 80 | pub fn with_capacity(len: usize) -> Self { 81 | MinMaxHeap(Vec::with_capacity(len)) 82 | } 83 | 84 | /// The number of elements in the heap. 85 | /// 86 | /// *O*(1). 87 | pub fn len(&self) -> usize { 88 | self.0.len() 89 | } 90 | 91 | /// Is the heap empty? 92 | /// 93 | /// *O*(1). 94 | pub fn is_empty(&self) -> bool { 95 | self.0.is_empty() 96 | } 97 | } 98 | 99 | impl MinMaxHeap { 100 | /// Adds an element to the heap. 101 | /// 102 | /// Amortized *O*(log *n*); worst-case *O*(*n*) when the backing vector needs to 103 | /// grow. 104 | pub fn push(&mut self, element: T) { 105 | let pos = self.len(); 106 | self.0.push(element); 107 | // SAFETY: `pos` is the index of the new element 108 | unsafe { 109 | self.bubble_up(pos); 110 | } 111 | } 112 | 113 | /// Gets a reference to the minimum element, if any. 114 | /// 115 | /// *O*(1). 116 | pub fn peek_min(&self) -> Option<&T> { 117 | self.0.first() 118 | } 119 | 120 | /// Returns a mutable reference to the minimum element, if any. Once this reference is dropped, 121 | /// the heap is adjusted if necessary. 122 | /// 123 | /// Note: If the `PeekMinMut` value is leaked, the heap may be in an 124 | /// inconsistent state. 125 | /// 126 | /// *O*(1) for the peek; *O*(log *n*) when the reference is dropped. 127 | pub fn peek_min_mut(&mut self) -> Option> { 128 | if self.is_empty() { 129 | None 130 | } else { 131 | Some(PeekMinMut { 132 | heap: self, 133 | sift: false, 134 | }) 135 | } 136 | } 137 | 138 | /// Gets a reference to the maximum element, if any. 139 | /// 140 | /// *O*(1). 141 | pub fn peek_max(&self) -> Option<&T> { 142 | // SAFETY: `i` is a valid index in `self.0` 143 | self.find_max().map(|i| unsafe { self.0.get_unchecked(i) }) 144 | } 145 | 146 | /// Returns a mutable reference to the maximum element, if any. Once this reference is dropped, 147 | /// the heap is adjusted if necessary. 148 | /// 149 | /// Note: If the `PeekMaxMut` value is leaked, the heap may be in an 150 | /// inconsistent state. 151 | /// 152 | /// *O*(1) for the peek; *O*(log *n*) when the reference is dropped. 153 | pub fn peek_max_mut(&mut self) -> Option> { 154 | self.find_max().map(move |i| PeekMaxMut { 155 | heap: self, 156 | max_index: i, 157 | sift: false, 158 | }) 159 | } 160 | 161 | fn find_max_slice(slice: &[T]) -> Option { 162 | match slice.len() { 163 | 0 => None, 164 | 1 => Some(0), 165 | 2 => Some(1), 166 | _ => if slice[1] > slice[2] { Some(1) } else { Some(2) }, 167 | } 168 | } 169 | 170 | fn find_max(&self) -> Option { 171 | Self::find_max_slice(&self.0) 172 | } 173 | 174 | /// Removes the minimum element, if any. 175 | /// 176 | /// *O*(log *n*). 177 | pub fn pop_min(&mut self) -> Option { 178 | self.0.pop().map(|mut item| { 179 | if let Some(min) = self.0.first_mut() { 180 | mem::swap(&mut item, min); 181 | // SAFETY: `self.0` is not empty 182 | unsafe { 183 | self.trickle_down_min(0); 184 | } 185 | } 186 | 187 | item 188 | }) 189 | } 190 | 191 | /// Removes the maximum element, if any. 192 | /// 193 | /// *O*(log *n*). 194 | pub fn pop_max(&mut self) -> Option { 195 | self.find_max().map(|max| { 196 | let mut item = self.0.pop().unwrap(); 197 | 198 | if let Some(max_element) = self.0.get_mut(max) { 199 | mem::swap(&mut item, max_element); 200 | // SAFETY: `max` is a valid index in `self.0` 201 | unsafe { 202 | self.trickle_down_max(max); 203 | } 204 | } 205 | 206 | item 207 | }) 208 | } 209 | 210 | /// Pushes an element, then pops the minimum element. 211 | /// 212 | /// Calling `push_pop_min` is equivalent to calling [`push`] 213 | /// followed by [`pop_min`], except that it avoids allocation. 214 | /// 215 | /// This means that if the element you give it is smaller than 216 | /// anything already in the heap then `push_pop_min` gives you back 217 | /// that same element. If the heap is empty then `push_pop_min` 218 | /// returns its argument and leaves the heap empty. In order to 219 | /// always insert the element, even if it would be the new minimum, 220 | /// see [`replace_min`], which equivalent to [`pop_min`] followed by 221 | /// [`push`]. 222 | /// 223 | /// [`push`]: 224 | /// 225 | /// 226 | /// [`pop_min`]: 227 | /// 228 | /// 229 | /// [`replace_min`]: 230 | /// 231 | /// 232 | /// *O*(log *n*). 233 | pub fn push_pop_min(&mut self, mut element: T) -> T { 234 | if let Some(mut min) = self.peek_min_mut() { 235 | if element > *min { 236 | mem::swap(&mut element, &mut min); 237 | } 238 | } 239 | element 240 | } 241 | 242 | /// Pushes an element, then pops the maximum element. 243 | /// 244 | /// Calling `push_pop_max` is equivalent to calling [`push`] 245 | /// followed by [`pop_max`], except that it avoids allocation. 246 | /// 247 | /// This means that if the element you give it is greater than 248 | /// anything already in the heap then `push_pop_max` gives you back 249 | /// that same element. If the heap is empty then `push_pop_max` 250 | /// returns its argument and leaves the heap empty. In order to 251 | /// always insert the element, even if it would be the new maximum, 252 | /// see [`replace_max`], which equivalent to [`pop_max`] followed by 253 | /// [`push`]. 254 | /// 255 | /// [`push`]: 256 | /// 257 | /// 258 | /// [`pop_max`]: 259 | /// 260 | /// 261 | /// [`replace_max`]: 262 | /// 263 | /// 264 | /// *O*(log *n*). 265 | pub fn push_pop_max(&mut self, mut element: T) -> T { 266 | if let Some(mut max) = self.peek_max_mut() { 267 | if element < *max { 268 | mem::swap(&mut element, &mut max); 269 | } 270 | } 271 | element 272 | } 273 | 274 | /// Pops the minimum element and pushes a new element, in an 275 | /// optimized fashion. 276 | /// 277 | /// Except for avoiding allocation, calling `replace_min` is 278 | /// equivalent to calling [`pop_min`] followed by [`push`]. 279 | /// 280 | /// This means that `replace_min` will always leaves the element you 281 | /// give it in the heap and gives you back the *old* minimum 282 | /// element; it never returns the element you just gave it. If the 283 | /// heap is empty there is no old minimum, so `replace_min` pushes 284 | /// the element and returns `None`. If you want to get back the 285 | /// smallest element *including* the one you are about to push, see 286 | /// [`push_pop_min`]. 287 | /// 288 | /// [`push`]: 289 | /// 290 | /// 291 | /// [`pop_min`]: 292 | /// 293 | /// 294 | /// [`push_pop_min`]: 295 | /// 296 | /// 297 | /// *O*(log *n*). 298 | pub fn replace_min(&mut self, mut element: T) -> Option { 299 | if let Some(mut min) = self.peek_min_mut() { 300 | mem::swap(&mut element, &mut min); 301 | return Some(element); 302 | } 303 | 304 | // Heap was empty, so no reordering is necessary 305 | self.0.push(element); 306 | None 307 | } 308 | 309 | /// Pops the maximum element and pushes a new element, in an 310 | /// optimized fashion. 311 | /// 312 | /// Except for avoiding allocation, calling `replace_max` is 313 | /// equivalent to calling [`pop_max`] followed by [`push`]. 314 | /// 315 | /// This means that `replace_max` will always leaves the element you 316 | /// give it in the heap and gives you back the *old* maximum 317 | /// element; it never returns the element you just gave it. If the 318 | /// heap is empty there is no old maximum, so `replace_max` pushes 319 | /// the element and returns `None`. If you want to get back the 320 | /// largest element *including* the one you are about to push, see 321 | /// [`push_pop_max`]. 322 | /// 323 | /// [`push`]: 324 | /// 325 | /// 326 | /// [`pop_max`]: 327 | /// 328 | /// 329 | /// [`push_pop_max`]: 330 | /// 331 | /// 332 | /// *O*(log *n*). 333 | pub fn replace_max(&mut self, mut element: T) -> Option { 334 | if let Some(mut max) = self.peek_max_mut() { 335 | // If `element` is the new min, swap it with the current min 336 | // (unless the min is the same as the max) 337 | if max.heap.len() > 1 { 338 | let min = &mut max.heap.0[0]; 339 | if element < *min { 340 | mem::swap(&mut element, min); 341 | } 342 | } 343 | mem::swap(&mut element, &mut max); 344 | return Some(element); 345 | } 346 | 347 | // Heap was empty, so no reordering is necessary 348 | self.0.push(element); 349 | None 350 | } 351 | 352 | /// Returns an ascending (sorted) vector, reusing the heap’s 353 | /// storage. 354 | /// 355 | /// *O*(*n* log *n*). 356 | pub fn into_vec_asc(mut self) -> Vec { 357 | let mut elements = &mut *self.0; 358 | while elements.len() > 1 { 359 | let max = Self::find_max_slice(elements).unwrap(); 360 | let (last, elements_rest) = elements.split_last_mut().unwrap(); 361 | elements = elements_rest; 362 | if let Some(max_element) = elements.get_mut(max) { 363 | mem::swap(max_element, last); 364 | // SAFETY: `max < elements.len()` 365 | unsafe { 366 | Self::trickle_down_slice(elements, max); 367 | } 368 | } 369 | } 370 | self.into_vec() 371 | } 372 | 373 | /// Returns an descending (sorted) vector, reusing the heap’s 374 | /// storage. 375 | /// 376 | /// *O*(*n* log *n*). 377 | pub fn into_vec_desc(mut self) -> Vec { 378 | let mut elements = &mut *self.0; 379 | while elements.len() > 1 { 380 | let (last, elements_rest) = elements.split_last_mut().unwrap(); 381 | elements = elements_rest; 382 | mem::swap(&mut elements[0], last); 383 | // SAFETY: `elements` is not empty 384 | unsafe { 385 | Self::trickle_down_min_slice(elements, 0); 386 | } 387 | } 388 | self.into_vec() 389 | } 390 | 391 | /// Retains only the elements specified by the predicate. 392 | /// 393 | /// In other words, remove all elements `e` such that `f(&e)` returns 394 | /// `false`. The elements are visited in unsorted (and unspecified) order. 395 | /// 396 | /// # Examples 397 | /// 398 | /// Basic usage: 399 | /// 400 | /// ``` 401 | /// use min_max_heap::MinMaxHeap; 402 | /// 403 | /// let mut heap = MinMaxHeap::from(vec![-10, -5, 1, 2, 4, 13]); 404 | /// 405 | /// heap.retain(|x| x % 2 == 0); // only keep even numbers 406 | /// 407 | /// let mut vec = heap.into_vec(); 408 | /// vec.sort(); 409 | /// assert_eq!(vec, [-10, 2, 4]) 410 | /// ``` 411 | pub fn retain(&mut self, f: F) 412 | where 413 | F: FnMut(&T) -> bool, 414 | { 415 | self.0.retain(f); 416 | self.rebuild(); 417 | } 418 | 419 | /// Caller must ensure that `pos` is a valid index in `self.0`. 420 | #[inline] 421 | unsafe fn trickle_down_min(&mut self, pos: usize) { 422 | Self::trickle_down_min_slice(&mut self.0, pos); 423 | } 424 | 425 | /// Caller must ensure that `pos` is a valid index in `self.0`. 426 | #[inline] 427 | unsafe fn trickle_down_max(&mut self, pos: usize) { 428 | debug_assert!(pos < self.len()); 429 | Hole::new(&mut self.0, pos).trickle_down_max(); 430 | } 431 | 432 | /// Caller must ensure that `pos` is a valid index in `self.0`. 433 | #[inline] 434 | unsafe fn trickle_down(&mut self, pos: usize) { 435 | Self::trickle_down_slice(&mut self.0, pos); 436 | } 437 | 438 | /// Caller must ensure that `pos` is a valid index in `slice`. 439 | #[inline] 440 | unsafe fn trickle_down_min_slice(slice: &mut [T], pos: usize) { 441 | debug_assert!(pos < slice.len()); 442 | Hole::new(slice, pos).trickle_down_min(); 443 | } 444 | 445 | /// Caller must ensure that `pos` is a valid index in `slice`. 446 | #[inline] 447 | unsafe fn trickle_down_slice(slice: &mut [T], pos: usize) { 448 | debug_assert!(pos < slice.len()); 449 | Hole::new(slice, pos).trickle_down(); 450 | } 451 | 452 | /// Caller must ensure that `pos` is a valid index in `self.0`. 453 | #[inline] 454 | unsafe fn bubble_up(&mut self, pos: usize) { 455 | debug_assert!(pos < self.len()); 456 | Hole::new(&mut self.0, pos).bubble_up(); 457 | } 458 | 459 | fn rebuild(&mut self) { 460 | for n in (0..(self.len() / 2)).rev() { 461 | // SAFETY: `n < self.len()` 462 | unsafe { 463 | self.trickle_down(n); 464 | } 465 | } 466 | } 467 | } 468 | 469 | impl MinMaxHeap { 470 | /// Drops all items from the heap. 471 | /// 472 | /// *O*(*n*) 473 | pub fn clear(&mut self) { 474 | self.0.clear(); 475 | } 476 | 477 | /// The number of elements the heap can hold without reallocating. 478 | /// 479 | /// *O*(1) 480 | pub fn capacity(&self) -> usize { 481 | self.0.capacity() 482 | } 483 | 484 | /// Reserves the minimum capacity for exactly `additional` more 485 | /// elements to be inserted in the given `MinMaxHeap`. 486 | /// 487 | /// *O*(*n*) 488 | /// 489 | /// # Panics 490 | /// 491 | /// Panics if the new capacity overflows `usize`. 492 | pub fn reserve_exact(&mut self, additional: usize) { 493 | self.0.reserve_exact(additional) 494 | } 495 | 496 | /// Reserves the minimum capacity for at least `additional` more 497 | /// elements to be inserted in the given `MinMaxHeap`. 498 | /// 499 | /// *O*(*n*) 500 | /// 501 | /// # Panics 502 | /// 503 | /// Panics if the new capacity overflows `usize`. 504 | pub fn reserve(&mut self, additional: usize) { 505 | self.0.reserve(additional) 506 | } 507 | 508 | /// Discards extra capacity. 509 | /// 510 | /// *O*(*n*) 511 | pub fn shrink_to_fit(&mut self) { 512 | self.0.shrink_to_fit() 513 | } 514 | 515 | /// Consumes the `MinMaxHeap` and returns its elements in a vector 516 | /// in arbitrary order. 517 | /// 518 | /// *O*(*n*) 519 | pub fn into_vec(self) -> Vec { 520 | self.0 521 | } 522 | 523 | /// Returns a borrowing iterator over the min-max-heap’s elements in 524 | /// arbitrary order. 525 | /// 526 | /// *O*(1) on creation, and *O*(1) for each `next()` operation. 527 | pub fn iter(&self) -> Iter { 528 | Iter(self.0.iter()) 529 | } 530 | 531 | /// Returns a draining iterator over the min-max-heap’s elements in 532 | /// arbitrary order. 533 | /// 534 | /// *O*(1) on creation, and *O*(1) for each `next()` operation. 535 | pub fn drain(&mut self) -> Drain { 536 | Drain(self.0.drain(..)) 537 | } 538 | 539 | /// Returns a draining iterator over the min-max-heap’s elements in 540 | /// ascending (min-first) order. 541 | /// 542 | /// *O*(1) on creation, and *O*(log *n*) for each `next()` operation. 543 | pub fn drain_asc(&mut self) -> DrainAsc { 544 | DrainAsc(self) 545 | } 546 | 547 | /// Returns a draining iterator over the min-max-heap’s elements in 548 | /// descending (max-first) order. 549 | /// 550 | /// *O*(1) on creation, and *O*(log *n*) for each `next()` operation. 551 | pub fn drain_desc(&mut self) -> DrainDesc { 552 | DrainDesc(self) 553 | } 554 | } 555 | 556 | // 557 | // Iterators 558 | // 559 | 560 | /// A borrowed iterator over the elements of the min-max-heap in 561 | /// arbitrary order. 562 | /// 563 | /// This type is created with 564 | /// [`MinMaxHeap::iter`](struct.MinMaxHeap.html#method.iter). 565 | pub struct Iter<'a, T: 'a>(slice::Iter<'a, T>); 566 | 567 | impl<'a, T> Iterator for Iter<'a, T> { 568 | type Item = &'a T; 569 | fn next(&mut self) -> Option { self.0.next() } 570 | 571 | fn size_hint(&self) -> (usize, Option) { 572 | self.0.size_hint() 573 | } 574 | } 575 | 576 | impl<'a, T> ExactSizeIterator for Iter<'a, T> { } 577 | 578 | impl<'a, T> IntoIterator for &'a MinMaxHeap { 579 | type Item = &'a T; 580 | type IntoIter = Iter<'a, T>; 581 | fn into_iter(self) -> Self::IntoIter { self.iter() } 582 | } 583 | 584 | /// An owning iterator over the elements of the min-max-heap in 585 | /// arbitrary order. 586 | pub struct IntoIter(vec::IntoIter); 587 | 588 | impl Iterator for IntoIter { 589 | type Item = T; 590 | fn next(&mut self) -> Option { self.0.next() } 591 | 592 | fn size_hint(&self) -> (usize, Option) { 593 | self.0.size_hint() 594 | } 595 | } 596 | 597 | impl ExactSizeIterator for IntoIter { } 598 | 599 | impl<'a, T> IntoIterator for MinMaxHeap { 600 | type Item = T; 601 | type IntoIter = IntoIter; 602 | fn into_iter(self) -> Self::IntoIter { 603 | IntoIter(self.0.into_iter()) 604 | } 605 | } 606 | 607 | /// A draining iterator over the elements of the min-max-heap in 608 | /// arbitrary order. 609 | /// 610 | /// This type is created with 611 | /// [`MinMaxHeap::drain`](struct.MinMaxHeap.html#method.drain). 612 | pub struct Drain<'a, T: 'a>(vec::Drain<'a, T>); 613 | 614 | impl<'a, T> Iterator for Drain<'a, T> { 615 | type Item = T; 616 | fn next(&mut self) -> Option { self.0.next() } 617 | 618 | fn size_hint(&self) -> (usize, Option) { 619 | self.0.size_hint() 620 | } 621 | } 622 | 623 | impl<'a, T> ExactSizeIterator for Drain<'a, T> { } 624 | 625 | impl FromIterator for MinMaxHeap { 626 | fn from_iter(iter: I) -> Self 627 | where I: IntoIterator { 628 | MinMaxHeap::from(iter.into_iter().collect::>()) 629 | } 630 | } 631 | 632 | /// A draining iterator over the elements of the min-max-heap in 633 | /// ascending (min-first) order. 634 | /// 635 | /// Note that each `next()` and `next_back()` operation is 636 | /// *O*(log *n*) time, so this currently provides no performance 637 | /// advantage over `pop_min()` and `pop_max()`. 638 | /// 639 | /// This type is created with 640 | /// [`MinMaxHeap::drain_asc`](struct.MinMaxHeap.html#method.drain_asc). 641 | #[derive(Debug)] 642 | pub struct DrainAsc<'a, T: 'a>(&'a mut MinMaxHeap); 643 | 644 | /// A draining iterator over the elements of the min-max-heap in 645 | /// descending (max-first) order. 646 | /// 647 | /// Note that each `next()` and `next_back()` operation is 648 | /// *O*(log *n*) time, so this currently provides no performance 649 | /// advantage over `pop_max()` and `pop_min()`. 650 | /// 651 | /// This type is created with 652 | /// [`MinMaxHeap::drain_desc`](struct.MinMaxHeap.html#method.drain_desc). 653 | #[derive(Debug)] 654 | pub struct DrainDesc<'a, T: 'a>(&'a mut MinMaxHeap); 655 | 656 | impl<'a, T> Drop for DrainAsc<'a, T> { 657 | fn drop(&mut self) { 658 | let _ = (self.0).0.drain(..); 659 | } 660 | } 661 | 662 | impl<'a, T> Drop for DrainDesc<'a, T> { 663 | fn drop(&mut self) { 664 | let _ = (self.0).0.drain(..); 665 | } 666 | } 667 | 668 | impl<'a, T: Ord> Iterator for DrainAsc<'a, T> { 669 | type Item = T; 670 | 671 | fn next(&mut self) -> Option { 672 | self.0.pop_min() 673 | } 674 | 675 | fn size_hint(&self) -> (usize, Option) { 676 | (self.len(), Some(self.len())) 677 | } 678 | } 679 | 680 | impl<'a, T: Ord> Iterator for DrainDesc<'a, T> { 681 | type Item = T; 682 | 683 | fn next(&mut self) -> Option { 684 | self.0.pop_max() 685 | } 686 | 687 | fn size_hint(&self) -> (usize, Option) { 688 | (self.len(), Some(self.len())) 689 | } 690 | } 691 | 692 | impl<'a, T: Ord> DoubleEndedIterator for DrainAsc<'a, T> { 693 | fn next_back(&mut self) -> Option { 694 | self.0.pop_max() 695 | } 696 | } 697 | 698 | impl<'a, T: Ord> DoubleEndedIterator for DrainDesc<'a, T> { 699 | fn next_back(&mut self) -> Option { 700 | self.0.pop_min() 701 | } 702 | } 703 | 704 | impl<'a, T: Ord> ExactSizeIterator for DrainAsc<'a, T> { 705 | fn len(&self) -> usize { 706 | self.0.len() 707 | } 708 | } 709 | 710 | impl<'a, T: Ord> ExactSizeIterator for DrainDesc<'a, T> { 711 | fn len(&self) -> usize { 712 | self.0.len() 713 | } 714 | } 715 | 716 | // 717 | // From> 718 | // 719 | 720 | impl From> for MinMaxHeap { 721 | fn from(vec: Vec) -> Self { 722 | let mut heap = MinMaxHeap(vec); 723 | heap.rebuild(); 724 | heap 725 | } 726 | } 727 | 728 | // 729 | // Extend 730 | // 731 | 732 | impl Extend for MinMaxHeap { 733 | fn extend>(&mut self, iter: I) { 734 | for elem in iter { 735 | self.push(elem) 736 | } 737 | } 738 | } 739 | 740 | impl<'a, T: Ord + Clone + 'a> Extend<&'a T> for MinMaxHeap { 741 | fn extend>(&mut self, iter: I) { 742 | for elem in iter { 743 | self.push(elem.clone()) 744 | } 745 | } 746 | } 747 | 748 | /// Structure wrapping a mutable reference to the minimum item on a 749 | /// `MinMaxHeap`. 750 | /// 751 | /// This `struct` is created by the [`peek_min_mut`] method on [`MinMaxHeap`]. See 752 | /// its documentation for more. 753 | /// 754 | /// [`peek_min_mut`]: struct.MinMaxHeap.html#method.peek_min_mut 755 | /// [`MinMaxHeap`]: struct.MinMaxHeap.html 756 | pub struct PeekMinMut<'a, T: Ord> { 757 | heap: &'a mut MinMaxHeap, 758 | sift: bool, 759 | } 760 | 761 | impl fmt::Debug for PeekMinMut<'_, T> { 762 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 763 | f.debug_tuple("PeekMinMut") 764 | .field(&**self) 765 | .finish() 766 | } 767 | } 768 | 769 | impl<'a, T: Ord> Drop for PeekMinMut<'a, T> { 770 | fn drop(&mut self) { 771 | if self.sift { 772 | // SAFETY: `heap` is not empty 773 | unsafe { 774 | self.heap.trickle_down_min(0); 775 | } 776 | } 777 | } 778 | } 779 | 780 | impl<'a, T: Ord> Deref for PeekMinMut<'a, T> { 781 | type Target = T; 782 | fn deref(&self) -> &T { 783 | debug_assert!(!self.heap.is_empty()); 784 | // SAFE: PeekMinMut is only instantiated for non-empty heaps 785 | unsafe { self.heap.0.get_unchecked(0) } 786 | } 787 | } 788 | 789 | impl<'a, T: Ord> DerefMut for PeekMinMut<'a, T> { 790 | fn deref_mut(&mut self) -> &mut T { 791 | debug_assert!(!self.heap.is_empty()); 792 | self.sift = true; 793 | // SAFE: PeekMinMut is only instantiated for non-empty heaps 794 | unsafe { self.heap.0.get_unchecked_mut(0) } 795 | } 796 | } 797 | 798 | impl<'a, T: Ord> PeekMinMut<'a, T> { 799 | /// Removes the peeked value from the heap and returns it. 800 | pub fn pop(mut self) -> T { 801 | // Sift is unnecessary since pop_min() already reorders heap 802 | self.sift = false; 803 | self.heap.pop_min().unwrap() 804 | } 805 | } 806 | 807 | /// Structure wrapping a mutable reference to the maximum item on a 808 | /// `MinMaxHeap`. 809 | /// 810 | /// This `struct` is created by the [`peek_max_mut`] method on [`MinMaxHeap`]. See 811 | /// its documentation for more. 812 | /// 813 | /// [`peek_max_mut`]: struct.MinMaxHeap.html#method.peek_max_mut 814 | /// [`MinMaxHeap`]: struct.MinMaxHeap.html 815 | pub struct PeekMaxMut<'a, T: Ord> { 816 | heap: &'a mut MinMaxHeap, 817 | max_index: usize, 818 | sift: bool, 819 | } 820 | 821 | impl fmt::Debug for PeekMaxMut<'_, T> { 822 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 823 | f.debug_tuple("PeekMaxMut") 824 | .field(&**self) 825 | .finish() 826 | } 827 | } 828 | 829 | impl<'a, T: Ord> Drop for PeekMaxMut<'a, T> { 830 | fn drop(&mut self) { 831 | if self.sift { 832 | // SAFETY: `max_index` is a valid index in `heap` 833 | let mut hole = unsafe { Hole::new(&mut self.heap.0, self.max_index) }; 834 | 835 | if let Some(mut parent) = hole.get_parent() { 836 | if parent.hole_element() < parent.other_element() { 837 | parent.swap_with(); 838 | } 839 | } 840 | 841 | hole.trickle_down_max(); 842 | } 843 | } 844 | } 845 | 846 | impl<'a, T: Ord> Deref for PeekMaxMut<'a, T> { 847 | type Target = T; 848 | fn deref(&self) -> &T { 849 | debug_assert!(self.max_index < self.heap.len()); 850 | // SAFE: PeekMaxMut is only instantiated for non-empty heaps 851 | unsafe { self.heap.0.get_unchecked(self.max_index) } 852 | } 853 | } 854 | 855 | impl<'a, T: Ord> DerefMut for PeekMaxMut<'a, T> { 856 | fn deref_mut(&mut self) -> &mut T { 857 | debug_assert!(self.max_index < self.heap.len()); 858 | self.sift = true; 859 | // SAFE: PeekMaxMut is only instantiated for non-empty heaps 860 | unsafe { self.heap.0.get_unchecked_mut(self.max_index) } 861 | } 862 | } 863 | 864 | impl<'a, T: Ord> PeekMaxMut<'a, T> { 865 | /// Removes the peeked value from the heap and returns it. 866 | pub fn pop(mut self) -> T { 867 | // Sift is unnecessary since pop_max() already reorders heap 868 | self.sift = false; 869 | self.heap.pop_max().unwrap() 870 | } 871 | } 872 | 873 | #[cfg(test)] 874 | mod tests { 875 | extern crate rand; 876 | 877 | use super::*; 878 | use self::rand::seq::SliceRandom; 879 | 880 | #[test] 881 | fn example() { 882 | let mut h = MinMaxHeap::new(); 883 | assert!(h.is_empty()); 884 | 885 | h.push(5); 886 | assert!(!h.is_empty()); 887 | assert_eq!(Some(&5), h.peek_min()); 888 | assert_eq!(Some(&5), h.peek_max()); 889 | 890 | h.push(7); 891 | assert_eq!(Some(&5), h.peek_min()); 892 | assert_eq!(Some(&7), h.peek_max()); 893 | 894 | h.push(6); 895 | assert_eq!(Some(&5), h.peek_min()); 896 | assert_eq!(Some(&7), h.peek_max()); 897 | 898 | assert_eq!(Some(5), h.pop_min()); 899 | assert_eq!(Some(7), h.pop_max()); 900 | assert_eq!(Some(6), h.pop_max()); 901 | assert_eq!(None, h.pop_min()); 902 | } 903 | 904 | #[test] 905 | fn drain_asc() { 906 | let mut h = MinMaxHeap::from(vec![3, 2, 4, 1]); 907 | let mut i = h.drain_asc(); 908 | assert_eq!( i.next(), Some(1) ); 909 | assert_eq!( i.next(), Some(2) ); 910 | assert_eq!( i.next(), Some(3) ); 911 | assert_eq!( i.next(), Some(4) ); 912 | assert_eq!( i.next(), None ); 913 | } 914 | 915 | // This test catches a lot: 916 | #[test] 917 | fn random_vectors() { 918 | for i in 0 .. 300 { 919 | check_heap(&random_heap(i)); 920 | } 921 | } 922 | 923 | #[test] 924 | fn from_vector() { 925 | for i in 0 .. 300 { 926 | check_heap(&MinMaxHeap::from(random_vec(i))) 927 | } 928 | } 929 | 930 | fn check_heap(heap: &MinMaxHeap) { 931 | let asc = iota_asc(heap.len()); 932 | let desc = iota_desc(heap.len()); 933 | 934 | assert_eq!(asc, into_vec_asc(heap.clone())); 935 | assert_eq!(desc, into_vec_desc(heap.clone())); 936 | assert_eq!(asc, heap.clone().into_vec_asc()); 937 | assert_eq!(desc, heap.clone().into_vec_desc()); 938 | } 939 | 940 | fn random_vec(len: usize) -> Vec { 941 | let mut result = (0 .. len).collect::>(); 942 | result.shuffle(&mut rand::thread_rng()); 943 | result 944 | } 945 | 946 | fn random_heap(len: usize) -> MinMaxHeap { 947 | MinMaxHeap::from_iter(random_vec(len)) 948 | } 949 | 950 | fn into_vec_asc(mut heap: MinMaxHeap) -> Vec { 951 | let mut result = Vec::with_capacity(heap.len()); 952 | while let Some(elem) = heap.pop_min() { 953 | result.push(elem) 954 | } 955 | result 956 | } 957 | 958 | fn into_vec_desc(mut heap: MinMaxHeap) -> Vec { 959 | let mut result = Vec::with_capacity(heap.len()); 960 | while let Some(elem) = heap.pop_max() { 961 | result.push(elem) 962 | } 963 | result 964 | } 965 | 966 | fn iota_asc(len: usize) -> Vec { 967 | (0 .. len).collect() 968 | } 969 | 970 | fn iota_desc(len: usize) -> Vec { 971 | let mut result = (0 .. len).collect::>(); 972 | result.reverse(); 973 | result 974 | } 975 | 976 | #[test] 977 | fn replace_min() { 978 | let mut h = MinMaxHeap::from(vec![1, 2]); 979 | assert_eq!(Some(1), h.replace_min(0)); 980 | assert_eq!(Some(&0), h.peek_min()); 981 | assert_eq!(Some(&2), h.peek_max()); 982 | 983 | assert_eq!(Some(0), h.replace_min(3)); 984 | assert_eq!(Some(&2), h.peek_min()); 985 | assert_eq!(Some(&3), h.peek_max()); 986 | } 987 | 988 | #[test] 989 | fn replace_min_edge_cases() { 990 | let mut empty_heap = MinMaxHeap::new(); 991 | assert_eq!(None, empty_heap.replace_min(1)); 992 | assert_eq!(Some(1), empty_heap.pop_min()); 993 | assert_eq!(None, empty_heap.pop_min()); 994 | 995 | let mut one_element_heap = MinMaxHeap::from(vec![2]); 996 | assert_eq!(Some(2), one_element_heap.replace_min(1)); 997 | assert_eq!(Some(1), one_element_heap.pop_min()); 998 | assert_eq!(None, one_element_heap.pop_min()); 999 | } 1000 | 1001 | #[test] 1002 | fn replace_max() { 1003 | let mut h = MinMaxHeap::from(vec![1, 2]); 1004 | assert_eq!(Some(2), h.replace_max(3)); 1005 | assert_eq!(Some(&1), h.peek_min()); 1006 | assert_eq!(Some(&3), h.peek_max()); 1007 | 1008 | assert_eq!(Some(3), h.replace_max(0)); 1009 | assert_eq!(Some(&0), h.peek_min()); 1010 | assert_eq!(Some(&1), h.peek_max()); 1011 | } 1012 | 1013 | #[test] 1014 | fn replace_max_edge_cases() { 1015 | let mut empty_heap = MinMaxHeap::new(); 1016 | assert_eq!(None, empty_heap.replace_max(1)); 1017 | assert_eq!(Some(1), empty_heap.pop_max()); 1018 | assert_eq!(None, empty_heap.pop_max()); 1019 | 1020 | let mut one_element_heap = MinMaxHeap::from(vec![1]); 1021 | assert_eq!(Some(1), one_element_heap.replace_max(2)); 1022 | assert_eq!(Some(2), one_element_heap.pop_max()); 1023 | assert_eq!(None, one_element_heap.pop_max()); 1024 | } 1025 | 1026 | #[test] 1027 | fn peek_min_mut() { 1028 | let mut h = MinMaxHeap::from(vec![2, 3, 4]); 1029 | *h.peek_min_mut().unwrap() = 1; 1030 | assert_eq!(Some(&1), h.peek_min()); 1031 | assert_eq!(Some(&4), h.peek_max()); 1032 | 1033 | *h.peek_min_mut().unwrap() = 8; 1034 | assert_eq!(Some(&3), h.peek_min()); 1035 | assert_eq!(Some(&8), h.peek_max()); 1036 | 1037 | assert_eq!(3, h.peek_min_mut().unwrap().pop()); 1038 | assert_eq!(Some(&4), h.peek_min()); 1039 | assert_eq!(Some(&8), h.peek_max()); 1040 | } 1041 | 1042 | #[test] 1043 | fn peek_max_mut() { 1044 | let mut h = MinMaxHeap::from(vec![1, 2]); 1045 | *h.peek_max_mut().unwrap() = 3; 1046 | assert_eq!(Some(&1), h.peek_min()); 1047 | assert_eq!(Some(&3), h.peek_max()); 1048 | 1049 | *h.peek_max_mut().unwrap() = 0; 1050 | assert_eq!(Some(&0), h.peek_min()); 1051 | assert_eq!(Some(&1), h.peek_max()); 1052 | 1053 | assert_eq!(1, h.peek_max_mut().unwrap().pop()); 1054 | assert_eq!(Some(&0), h.peek_min()); 1055 | assert_eq!(Some(&0), h.peek_max()); 1056 | 1057 | *h.peek_max_mut().unwrap() = 1; 1058 | assert_eq!(Some(&1), h.peek_min()); 1059 | assert_eq!(Some(&1), h.peek_max()); 1060 | } 1061 | 1062 | #[test] 1063 | fn peek_max_mut_one() { 1064 | let mut h = MinMaxHeap::from(vec![1]); 1065 | { 1066 | let mut max = h.peek_max_mut().unwrap(); 1067 | assert_eq!(*max, 1); 1068 | *max = 2; 1069 | } 1070 | assert_eq!(h.peek_max(), Some(&2)); 1071 | } 1072 | 1073 | #[test] 1074 | fn push_pop_max() { 1075 | let mut h = MinMaxHeap::from(vec![1, 2]); 1076 | assert_eq!(3, h.push_pop_max(3)); 1077 | assert_eq!(2, h.push_pop_max(0)); 1078 | assert_eq!(Some(&0), h.peek_min()); 1079 | assert_eq!(Some(&1), h.peek_max()); 1080 | } 1081 | 1082 | #[test] 1083 | fn peek_mut_format() { 1084 | let mut h = MinMaxHeap::from(vec![1, 2, 3]); 1085 | assert_eq!("PeekMinMut(1)", format!("{:?}", h.peek_min_mut().unwrap())); 1086 | assert_eq!("PeekMaxMut(3)", format!("{:?}", h.peek_max_mut().unwrap())); 1087 | } 1088 | } 1089 | --------------------------------------------------------------------------------