clean up BinaryHeap
code
This commit is contained in:
parent
e64a8193b0
commit
fe9f1beae2
@ -11,15 +11,15 @@
|
||||
//! A priority queue implemented with a binary heap.
|
||||
//!
|
||||
//! Insertion and popping the largest element have `O(log n)` time complexity. Checking the largest
|
||||
//! element is `O(1)`. Converting a vector to a priority queue can be done in-place, and has `O(n)`
|
||||
//! complexity. A priority queue can also be converted to a sorted vector in-place, allowing it to
|
||||
//! element is `O(1)`. Converting a vector to a binary heap can be done in-place, and has `O(n)`
|
||||
//! complexity. A binary heap can also be converted to a sorted vector in-place, allowing it to
|
||||
//! be used for an `O(n log n)` in-place heapsort.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! This is a larger example which implements [Dijkstra's algorithm][dijkstra]
|
||||
//! This is a larger example that implements [Dijkstra's algorithm][dijkstra]
|
||||
//! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph].
|
||||
//! It showcases how to use the `BinaryHeap` with custom types.
|
||||
//! It shows how to use `BinaryHeap` with custom types.
|
||||
//!
|
||||
//! [dijkstra]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
|
||||
//! [sssp]: http://en.wikipedia.org/wiki/Shortest_path_problem
|
||||
@ -32,7 +32,7 @@
|
||||
//! #[deriving(Copy, Eq, PartialEq)]
|
||||
//! struct State {
|
||||
//! cost: uint,
|
||||
//! position: uint
|
||||
//! position: uint,
|
||||
//! }
|
||||
//!
|
||||
//! // The priority queue depends on `Ord`.
|
||||
@ -55,13 +55,13 @@
|
||||
//! // Each node is represented as an `uint`, for a shorter implementation.
|
||||
//! struct Edge {
|
||||
//! node: uint,
|
||||
//! cost: uint
|
||||
//! cost: uint,
|
||||
//! }
|
||||
//!
|
||||
//! // Dijkstra's shortest path algorithm.
|
||||
//!
|
||||
//! // Start at `start` and use `dist` to track the current shortest distance
|
||||
//! // to each node. This implementation isn't memory efficient as it may leave duplicate
|
||||
//! // to each node. This implementation isn't memory-efficient as it may leave duplicate
|
||||
//! // nodes in the queue. It also uses `uint::MAX` as a sentinel value,
|
||||
//! // for a simpler implementation.
|
||||
//! fn shortest_path(adj_list: &Vec<Vec<Edge>>, start: uint, goal: uint) -> uint {
|
||||
@ -71,21 +71,16 @@
|
||||
//! let mut heap = BinaryHeap::new();
|
||||
//!
|
||||
//! // We're at `start`, with a zero cost
|
||||
//! dist[start] = 0u;
|
||||
//! heap.push(State { cost: 0u, position: start });
|
||||
//! dist[start] = 0;
|
||||
//! heap.push(State { cost: 0, position: start });
|
||||
//!
|
||||
//! // Examine the frontier with lower cost nodes first (min-heap)
|
||||
//! loop {
|
||||
//! let State { cost, position } = match heap.pop() {
|
||||
//! None => break, // empty
|
||||
//! Some(s) => s
|
||||
//! };
|
||||
//!
|
||||
//! while let Some(State { cost, position }) = heap.pop() {
|
||||
//! // Alternatively we could have continued to find all shortest paths
|
||||
//! if position == goal { return cost }
|
||||
//! if position == goal { return cost; }
|
||||
//!
|
||||
//! // Important as we may have already found a better way
|
||||
//! if cost > dist[position] { continue }
|
||||
//! if cost > dist[position] { continue; }
|
||||
//!
|
||||
//! // For each node we can reach, see if we can find a way with
|
||||
//! // a lower cost going through this node
|
||||
@ -108,7 +103,7 @@
|
||||
//! fn main() {
|
||||
//! // This is the directed graph we're going to use.
|
||||
//! // The node numbers correspond to the different states,
|
||||
//! // and the edge weights symbolises the cost of moving
|
||||
//! // and the edge weights symbolize the cost of moving
|
||||
//! // from one node to another.
|
||||
//! // Note that the edges are one-way.
|
||||
//! //
|
||||
@ -126,7 +121,7 @@
|
||||
//! //
|
||||
//! // The graph is represented as an adjacency list where each index,
|
||||
//! // corresponding to a node value, has a list of outgoing edges.
|
||||
//! // Chosen for it's efficiency.
|
||||
//! // Chosen for its efficiency.
|
||||
//! let graph = vec![
|
||||
//! // Node 0
|
||||
//! vec![Edge { node: 2, cost: 10 },
|
||||
@ -184,10 +179,11 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let heap: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// heap.push(4u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn new() -> BinaryHeap<T> { BinaryHeap{data: vec!(),} }
|
||||
pub fn new() -> BinaryHeap<T> { BinaryHeap { data: vec![] } }
|
||||
|
||||
/// Creates an empty `BinaryHeap` with a specific capacity.
|
||||
/// This preallocates enough memory for `capacity` elements,
|
||||
@ -198,7 +194,8 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let heap: BinaryHeap<uint> = BinaryHeap::with_capacity(10u);
|
||||
/// let mut heap = BinaryHeap::with_capacity(10);
|
||||
/// heap.push(4u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn with_capacity(capacity: uint) -> BinaryHeap<T> {
|
||||
@ -214,17 +211,17 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let heap = BinaryHeap::from_vec(vec![9i, 1, 2, 7, 3, 2]);
|
||||
/// ```
|
||||
pub fn from_vec(xs: Vec<T>) -> BinaryHeap<T> {
|
||||
let mut q = BinaryHeap{data: xs,};
|
||||
let mut n = q.len() / 2;
|
||||
pub fn from_vec(vec: Vec<T>) -> BinaryHeap<T> {
|
||||
let mut heap = BinaryHeap { data: vec };
|
||||
let mut n = heap.len() / 2;
|
||||
while n > 0 {
|
||||
n -= 1;
|
||||
q.siftdown(n)
|
||||
heap.sift_down(n);
|
||||
}
|
||||
q
|
||||
heap
|
||||
}
|
||||
|
||||
/// An iterator visiting all values in underlying vector, in
|
||||
/// Returns an iterator visiting all values in the underlying vector, in
|
||||
/// arbitrary order.
|
||||
///
|
||||
/// # Examples
|
||||
@ -244,17 +241,17 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
}
|
||||
|
||||
/// Creates a consuming iterator, that is, one that moves each value out of
|
||||
/// the binary heap in arbitrary order. The binary heap cannot be used
|
||||
/// the binary heap in arbitrary order. The binary heap cannot be used
|
||||
/// after calling this.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
/// let pq = BinaryHeap::from_vec(vec![1i, 2, 3, 4]);
|
||||
/// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4]);
|
||||
///
|
||||
/// // Print 1, 2, 3, 4 in arbitrary order
|
||||
/// for x in pq.into_iter() {
|
||||
/// for x in heap.into_iter() {
|
||||
/// // x has type int, not &int
|
||||
/// println!("{}", x);
|
||||
/// }
|
||||
@ -264,20 +261,19 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
IntoIter { iter: self.data.into_iter() }
|
||||
}
|
||||
|
||||
/// Returns the greatest item in a queue, or `None` if it is empty.
|
||||
/// Returns the greatest item in the binary heap, or `None` if it is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// assert_eq!(heap.peek(), None);
|
||||
///
|
||||
/// heap.push(1i);
|
||||
/// heap.push(5i);
|
||||
/// heap.push(2i);
|
||||
/// assert_eq!(heap.peek(), Some(&5i));
|
||||
/// heap.push(5);
|
||||
/// heap.push(2);
|
||||
/// assert_eq!(heap.peek(), Some(&5));
|
||||
///
|
||||
/// ```
|
||||
#[stable]
|
||||
@ -285,15 +281,15 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
self.data.get(0)
|
||||
}
|
||||
|
||||
/// Returns the number of elements the queue can hold without reallocating.
|
||||
/// Returns the number of elements the binary heap can hold without reallocating.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let heap: BinaryHeap<uint> = BinaryHeap::with_capacity(100u);
|
||||
/// assert!(heap.capacity() >= 100u);
|
||||
/// let mut heap = BinaryHeap::with_capacity(100);
|
||||
/// assert!(heap.capacity() >= 100);
|
||||
/// heap.push(4u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn capacity(&self) -> uint { self.data.capacity() }
|
||||
@ -313,13 +309,15 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut heap: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// heap.reserve_exact(100u);
|
||||
/// assert!(heap.capacity() >= 100u);
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// heap.reserve_exact(100);
|
||||
/// assert!(heap.capacity() >= 100);
|
||||
/// heap.push(4u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn reserve_exact(&mut self, additional: uint) { self.data.reserve_exact(additional) }
|
||||
pub fn reserve_exact(&mut self, additional: uint) {
|
||||
self.data.reserve_exact(additional);
|
||||
}
|
||||
|
||||
/// Reserves capacity for at least `additional` more elements to be inserted in the
|
||||
/// `BinaryHeap`. The collection may reserve more space to avoid frequent reallocations.
|
||||
@ -332,88 +330,82 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut heap: BinaryHeap<uint> = BinaryHeap::new();
|
||||
/// heap.reserve(100u);
|
||||
/// assert!(heap.capacity() >= 100u);
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// heap.reserve(100);
|
||||
/// assert!(heap.capacity() >= 100);
|
||||
/// heap.push(4u);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn reserve(&mut self, additional: uint) {
|
||||
self.data.reserve(additional)
|
||||
self.data.reserve(additional);
|
||||
}
|
||||
|
||||
/// Discards as much additional capacity as possible.
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
self.data.shrink_to_fit()
|
||||
self.data.shrink_to_fit();
|
||||
}
|
||||
|
||||
/// Removes the greatest item from a queue and returns it, or `None` if it
|
||||
/// Removes the greatest item from the binary heap and returns it, or `None` if it
|
||||
/// is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut heap = BinaryHeap::from_vec(vec![1i, 3]);
|
||||
///
|
||||
/// assert_eq!(heap.pop(), Some(3i));
|
||||
/// assert_eq!(heap.pop(), Some(1i));
|
||||
/// assert_eq!(heap.pop(), Some(3));
|
||||
/// assert_eq!(heap.pop(), Some(1));
|
||||
/// assert_eq!(heap.pop(), None);
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
match self.data.pop() {
|
||||
None => { None }
|
||||
Some(mut item) => {
|
||||
if !self.is_empty() {
|
||||
swap(&mut item, &mut self.data[0]);
|
||||
self.siftdown(0);
|
||||
}
|
||||
Some(item)
|
||||
self.data.pop().map(|mut item| {
|
||||
if !self.is_empty() {
|
||||
swap(&mut item, &mut self.data[0]);
|
||||
self.sift_down(0);
|
||||
}
|
||||
}
|
||||
item
|
||||
})
|
||||
}
|
||||
|
||||
/// Pushes an item onto the queue.
|
||||
/// Pushes an item onto the binary heap.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// heap.push(3i);
|
||||
/// heap.push(5i);
|
||||
/// heap.push(1i);
|
||||
/// heap.push(5);
|
||||
/// heap.push(1);
|
||||
///
|
||||
/// assert_eq!(heap.len(), 3);
|
||||
/// assert_eq!(heap.peek(), Some(&5i));
|
||||
/// assert_eq!(heap.peek(), Some(&5));
|
||||
/// ```
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn push(&mut self, item: T) {
|
||||
let old_len = self.len();
|
||||
self.data.push(item);
|
||||
self.siftup(0, old_len);
|
||||
self.sift_up(0, old_len);
|
||||
}
|
||||
|
||||
/// Pushes an item onto a queue then pops the greatest item off the queue in
|
||||
/// Pushes an item onto the binary heap, then pops the greatest item off the queue in
|
||||
/// an optimized fashion.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
/// heap.push(1i);
|
||||
/// heap.push(5i);
|
||||
/// heap.push(5);
|
||||
///
|
||||
/// assert_eq!(heap.push_pop(3i), 5);
|
||||
/// assert_eq!(heap.push_pop(9i), 9);
|
||||
/// assert_eq!(heap.push_pop(3), 5);
|
||||
/// assert_eq!(heap.push_pop(9), 9);
|
||||
/// assert_eq!(heap.len(), 2);
|
||||
/// assert_eq!(heap.peek(), Some(&3i));
|
||||
/// assert_eq!(heap.peek(), Some(&3));
|
||||
/// ```
|
||||
pub fn push_pop(&mut self, mut item: T) -> T {
|
||||
match self.data.get_mut(0) {
|
||||
@ -425,30 +417,29 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
},
|
||||
}
|
||||
|
||||
self.siftdown(0);
|
||||
self.sift_down(0);
|
||||
item
|
||||
}
|
||||
|
||||
/// Pops the greatest item off a queue then pushes an item onto the queue in
|
||||
/// an optimized fashion. The push is done regardless of whether the queue
|
||||
/// Pops the greatest item off the binary heap, then pushes an item onto the queue in
|
||||
/// an optimized fashion. The push is done regardless of whether the binary heap
|
||||
/// was empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let mut heap = BinaryHeap::new();
|
||||
///
|
||||
/// assert_eq!(heap.replace(1i), None);
|
||||
/// assert_eq!(heap.replace(3i), Some(1i));
|
||||
/// assert_eq!(heap.replace(3), Some(1));
|
||||
/// assert_eq!(heap.len(), 1);
|
||||
/// assert_eq!(heap.peek(), Some(&3i));
|
||||
/// assert_eq!(heap.peek(), Some(&3));
|
||||
/// ```
|
||||
pub fn replace(&mut self, mut item: T) -> Option<T> {
|
||||
if !self.is_empty() {
|
||||
swap(&mut item, &mut self.data[0]);
|
||||
self.siftdown(0);
|
||||
self.sift_down(0);
|
||||
Some(item)
|
||||
} else {
|
||||
self.push(item);
|
||||
@ -463,7 +454,6 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::BinaryHeap;
|
||||
///
|
||||
/// let heap = BinaryHeap::from_vec(vec![1i, 2, 3, 4, 5, 6, 7]);
|
||||
/// let vec = heap.into_vec();
|
||||
///
|
||||
@ -494,35 +484,34 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
while end > 1 {
|
||||
end -= 1;
|
||||
self.data.swap(0, end);
|
||||
self.siftdown_range(0, end)
|
||||
self.sift_down_range(0, end);
|
||||
}
|
||||
self.into_vec()
|
||||
}
|
||||
|
||||
// The implementations of siftup and siftdown use unsafe blocks in
|
||||
// The implementations of sift_up and sift_down use unsafe blocks in
|
||||
// order to move an element out of the vector (leaving behind a
|
||||
// zeroed element), shift along the others and move it back into the
|
||||
// vector over the junk element. This reduces the constant factor
|
||||
// vector over the junk element. This reduces the constant factor
|
||||
// compared to using swaps, which involves twice as many moves.
|
||||
fn siftup(&mut self, start: uint, mut pos: uint) {
|
||||
fn sift_up(&mut self, start: uint, mut pos: uint) {
|
||||
unsafe {
|
||||
let new = replace(&mut self.data[pos], zeroed());
|
||||
|
||||
while pos > start {
|
||||
let parent = (pos - 1) >> 1;
|
||||
if new > self.data[parent] {
|
||||
let x = replace(&mut self.data[parent], zeroed());
|
||||
ptr::write(&mut self.data[pos], x);
|
||||
pos = parent;
|
||||
continue
|
||||
}
|
||||
break
|
||||
|
||||
if new <= self.data[parent] { break; }
|
||||
|
||||
let x = replace(&mut self.data[parent], zeroed());
|
||||
ptr::write(&mut self.data[pos], x);
|
||||
pos = parent;
|
||||
}
|
||||
ptr::write(&mut self.data[pos], new);
|
||||
}
|
||||
}
|
||||
|
||||
fn siftdown_range(&mut self, mut pos: uint, end: uint) {
|
||||
fn sift_down_range(&mut self, mut pos: uint, end: uint) {
|
||||
unsafe {
|
||||
let start = pos;
|
||||
let new = replace(&mut self.data[pos], zeroed());
|
||||
@ -540,33 +529,31 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
}
|
||||
|
||||
ptr::write(&mut self.data[pos], new);
|
||||
self.siftup(start, pos);
|
||||
self.sift_up(start, pos);
|
||||
}
|
||||
}
|
||||
|
||||
fn siftdown(&mut self, pos: uint) {
|
||||
fn sift_down(&mut self, pos: uint) {
|
||||
let len = self.len();
|
||||
self.siftdown_range(pos, len);
|
||||
self.sift_down_range(pos, len);
|
||||
}
|
||||
|
||||
/// Returns the length of the queue.
|
||||
/// Returns the length of the binary heap.
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn len(&self) -> uint { self.data.len() }
|
||||
|
||||
/// Returns true if the queue contains no elements
|
||||
/// Checks if the binary heap is empty.
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||
|
||||
/// Clears the queue, returning an iterator over the removed elements.
|
||||
/// Clears the binary heap, returning an iterator over the removed elements.
|
||||
#[inline]
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
|
||||
Drain {
|
||||
iter: self.data.drain(),
|
||||
}
|
||||
pub fn drain(&mut self) -> Drain<T> {
|
||||
Drain { iter: self.data.drain() }
|
||||
}
|
||||
|
||||
/// Drops all items from the queue.
|
||||
/// Drops all items from the binary heap.
|
||||
#[unstable = "matches collection reform specification, waiting for dust to settle"]
|
||||
pub fn clear(&mut self) { self.drain(); }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user