Auto merge of #74010 - pierwill:pierwill-o-notation, r=GuillaumeGomez

Use italics for O notation

In documentation, I think it makes sense to italicize O notation (*O(n)*) as opposed to using back-ticks (`O(n)`). Visually, back-ticks focus the reader on the literal characters being used, making them ideal for representing code. Using italics, as far I can tell, more closely follows typographic conventions in mathematics and computer science.

Just a suggestion, of course! 😇
This commit is contained in:
bors 2020-07-20 10:19:58 +00:00
commit 71384101ea
9 changed files with 51 additions and 51 deletions

View file

@ -1,9 +1,9 @@
//! A priority queue implemented with a binary heap. //! A priority queue implemented with a binary heap.
//! //!
//! Insertion and popping the largest element have `O(log(n))` time complexity. //! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
//! Checking the largest element is `O(1)`. Converting a vector to a binary heap //! Checking the largest 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 //! 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))` //! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*))
//! in-place heapsort. //! in-place heapsort.
//! //!
//! # Examples //! # Examples
@ -235,7 +235,7 @@ use super::SpecExtend;
/// ///
/// | [push] | [pop] | [peek]/[peek\_mut] | /// | [push] | [pop] | [peek]/[peek\_mut] |
/// |--------|-----------|--------------------| /// |--------|-----------|--------------------|
/// | O(1)~ | O(log(n)) | O(1) | /// | O(1)~ | *O*(log(*n*)) | *O*(1) |
/// ///
/// The value for `push` is an expected cost; the method documentation gives a /// The value for `push` is an expected cost; the method documentation gives a
/// more detailed analysis. /// more detailed analysis.
@ -398,7 +398,7 @@ impl<T: Ord> BinaryHeap<T> {
/// ///
/// # Time complexity /// # Time complexity
/// ///
/// Cost is `O(1)` in the worst case. /// Cost is *O*(1) in the worst case.
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> { pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) } if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) }
@ -422,7 +422,7 @@ impl<T: Ord> BinaryHeap<T> {
/// ///
/// # Time complexity /// # Time complexity
/// ///
/// The worst case cost of `pop` on a heap containing *n* elements is `O(log(n))`. /// The worst case cost of `pop` on a heap containing *n* elements is *O*(log(*n*)).
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn pop(&mut self) -> Option<T> { pub fn pop(&mut self) -> Option<T> {
self.data.pop().map(|mut item| { self.data.pop().map(|mut item| {
@ -455,15 +455,15 @@ impl<T: Ord> BinaryHeap<T> {
/// ///
/// The expected cost of `push`, averaged over every possible ordering of /// The expected cost of `push`, averaged over every possible ordering of
/// the elements being pushed, and over a sufficiently large number of /// the elements being pushed, and over a sufficiently large number of
/// pushes, is `O(1)`. This is the most meaningful cost metric when pushing /// pushes, is *O*(1). This is the most meaningful cost metric when pushing
/// elements that are *not* already in any sorted pattern. /// elements that are *not* already in any sorted pattern.
/// ///
/// The time complexity degrades if elements are pushed in predominantly /// The time complexity degrades if elements are pushed in predominantly
/// ascending order. In the worst case, elements are pushed in ascending /// ascending order. In the worst case, elements are pushed in ascending
/// sorted order and the amortized cost per push is `O(log(n))` against a heap /// sorted order and the amortized cost per push is *O*(log(*n*)) against a heap
/// containing *n* elements. /// containing *n* elements.
/// ///
/// The worst case cost of a *single* call to `push` is `O(n)`. The worst case /// The worst case cost of a *single* call to `push` is *O*(*n*). The worst case
/// occurs when capacity is exhausted and needs a resize. The resize cost /// occurs when capacity is exhausted and needs a resize. The resize cost
/// has been amortized in the previous figures. /// has been amortized in the previous figures.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -643,7 +643,7 @@ impl<T: Ord> BinaryHeap<T> {
/// The remaining elements will be removed on drop in heap order. /// The remaining elements will be removed on drop in heap order.
/// ///
/// Note: /// Note:
/// * `.drain_sorted()` is `O(n * log(n))`; much slower than `.drain()`. /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`.
/// You should use the latter for most cases. /// You should use the latter for most cases.
/// ///
/// # Examples /// # Examples
@ -756,7 +756,7 @@ impl<T> BinaryHeap<T> {
/// ///
/// # Time complexity /// # Time complexity
/// ///
/// Cost is `O(1)` in the worst case. /// Cost is *O*(1) in the worst case.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&self) -> Option<&T> { pub fn peek(&self) -> Option<&T> {
self.data.get(0) self.data.get(0)
@ -1312,7 +1312,7 @@ unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, T> {}
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> { impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
/// Converts a `Vec<T>` into a `BinaryHeap<T>`. /// Converts a `Vec<T>` into a `BinaryHeap<T>`.
/// ///
/// This conversion happens in-place, and has `O(n)` time complexity. /// This conversion happens in-place, and has *O*(*n*) time complexity.
fn from(vec: Vec<T>) -> BinaryHeap<T> { fn from(vec: Vec<T>) -> BinaryHeap<T> {
let mut heap = BinaryHeap { data: vec }; let mut heap = BinaryHeap { data: vec };
heap.rebuild(); heap.rebuild();

View file

@ -404,7 +404,7 @@ impl<T> LinkedList<T> {
/// This reuses all the nodes from `other` and moves them into `self`. After /// This reuses all the nodes from `other` and moves them into `self`. After
/// this operation, `other` becomes empty. /// this operation, `other` becomes empty.
/// ///
/// This operation should compute in `O(1)` time and `O(1)` memory. /// This operation should compute in *O*(1) time and *O*(1) memory.
/// ///
/// # Examples /// # Examples
/// ///
@ -561,7 +561,7 @@ impl<T> LinkedList<T> {
/// Returns `true` if the `LinkedList` is empty. /// Returns `true` if the `LinkedList` is empty.
/// ///
/// This operation should compute in `O(1)` time. /// This operation should compute in *O*(1) time.
/// ///
/// # Examples /// # Examples
/// ///
@ -582,7 +582,7 @@ impl<T> LinkedList<T> {
/// Returns the length of the `LinkedList`. /// Returns the length of the `LinkedList`.
/// ///
/// This operation should compute in `O(1)` time. /// This operation should compute in *O*(1) time.
/// ///
/// # Examples /// # Examples
/// ///
@ -608,7 +608,7 @@ impl<T> LinkedList<T> {
/// Removes all elements from the `LinkedList`. /// Removes all elements from the `LinkedList`.
/// ///
/// This operation should compute in `O(n)` time. /// This operation should compute in *O*(*n*) time.
/// ///
/// # Examples /// # Examples
/// ///
@ -751,7 +751,7 @@ impl<T> LinkedList<T> {
/// Adds an element first in the list. /// Adds an element first in the list.
/// ///
/// This operation should compute in `O(1)` time. /// This operation should compute in *O*(1) time.
/// ///
/// # Examples /// # Examples
/// ///
@ -774,7 +774,7 @@ impl<T> LinkedList<T> {
/// Removes the first element and returns it, or `None` if the list is /// Removes the first element and returns it, or `None` if the list is
/// empty. /// empty.
/// ///
/// This operation should compute in `O(1)` time. /// This operation should compute in *O*(1) time.
/// ///
/// # Examples /// # Examples
/// ///
@ -797,7 +797,7 @@ impl<T> LinkedList<T> {
/// Appends an element to the back of a list. /// Appends an element to the back of a list.
/// ///
/// This operation should compute in `O(1)` time. /// This operation should compute in *O*(1) time.
/// ///
/// # Examples /// # Examples
/// ///
@ -817,7 +817,7 @@ impl<T> LinkedList<T> {
/// Removes the last element from a list and returns it, or `None` if /// Removes the last element from a list and returns it, or `None` if
/// it is empty. /// it is empty.
/// ///
/// This operation should compute in `O(1)` time. /// This operation should compute in *O*(1) time.
/// ///
/// # Examples /// # Examples
/// ///
@ -838,7 +838,7 @@ impl<T> LinkedList<T> {
/// Splits the list into two at the given index. Returns everything after the given index, /// Splits the list into two at the given index. Returns everything after the given index,
/// including the index. /// including the index.
/// ///
/// This operation should compute in `O(n)` time. /// This operation should compute in *O*(*n*) time.
/// ///
/// # Panics /// # Panics
/// ///
@ -894,7 +894,7 @@ impl<T> LinkedList<T> {
/// Removes the element at the given index and returns it. /// Removes the element at the given index and returns it.
/// ///
/// This operation should compute in `O(n)` time. /// This operation should compute in *O*(*n*) time.
/// ///
/// # Panics /// # Panics
/// Panics if at >= len /// Panics if at >= len

View file

@ -1,7 +1,7 @@
//! A double-ended queue implemented with a growable ring buffer. //! A double-ended queue implemented with a growable ring buffer.
//! //!
//! This queue has `O(1)` amortized inserts and removals from both ends of the //! This queue has *O*(1) amortized inserts and removals from both ends of the
//! container. It also has `O(1)` indexing like a vector. The contained elements //! container. It also has *O*(1) indexing like a vector. The contained elements
//! are not required to be copyable, and the queue will be sendable if the //! are not required to be copyable, and the queue will be sendable if the
//! contained type is sendable. //! contained type is sendable.
@ -1512,7 +1512,7 @@ impl<T> VecDeque<T> {
/// Removes an element from anywhere in the `VecDeque` and returns it, /// Removes an element from anywhere in the `VecDeque` and returns it,
/// replacing it with the first element. /// replacing it with the first element.
/// ///
/// This does not preserve ordering, but is `O(1)`. /// This does not preserve ordering, but is *O*(1).
/// ///
/// Returns `None` if `index` is out of bounds. /// Returns `None` if `index` is out of bounds.
/// ///
@ -1547,7 +1547,7 @@ impl<T> VecDeque<T> {
/// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
/// last element. /// last element.
/// ///
/// This does not preserve ordering, but is `O(1)`. /// This does not preserve ordering, but is *O*(1).
/// ///
/// Returns `None` if `index` is out of bounds. /// Returns `None` if `index` is out of bounds.
/// ///
@ -2331,7 +2331,7 @@ impl<T> VecDeque<T> {
/// ///
/// # Complexity /// # Complexity
/// ///
/// Takes `O(min(mid, len() - mid))` time and no extra space. /// Takes `*O*(min(mid, len() - mid))` time and no extra space.
/// ///
/// # Examples /// # Examples
/// ///
@ -2374,7 +2374,7 @@ impl<T> VecDeque<T> {
/// ///
/// # Complexity /// # Complexity
/// ///
/// Takes `O(min(k, len() - k))` time and no extra space. /// Takes `*O*(min(k, len() - k))` time and no extra space.
/// ///
/// # Examples /// # Examples
/// ///
@ -3076,7 +3076,7 @@ impl<T> From<VecDeque<T>> for Vec<T> {
/// [`Vec<T>`]: crate::vec::Vec /// [`Vec<T>`]: crate::vec::Vec
/// [`VecDeque<T>`]: crate::collections::VecDeque /// [`VecDeque<T>`]: crate::collections::VecDeque
/// ///
/// This never needs to re-allocate, but does need to do `O(n)` data movement if /// This never needs to re-allocate, but does need to do *O*(*n*) data movement if
/// the circular buffer doesn't happen to be at the beginning of the allocation. /// the circular buffer doesn't happen to be at the beginning of the allocation.
/// ///
/// # Examples /// # Examples
@ -3084,7 +3084,7 @@ impl<T> From<VecDeque<T>> for Vec<T> {
/// ``` /// ```
/// use std::collections::VecDeque; /// use std::collections::VecDeque;
/// ///
/// // This one is O(1). /// // This one is *O*(1).
/// let deque: VecDeque<_> = (1..5).collect(); /// let deque: VecDeque<_> = (1..5).collect();
/// let ptr = deque.as_slices().0.as_ptr(); /// let ptr = deque.as_slices().0.as_ptr();
/// let vec = Vec::from(deque); /// let vec = Vec::from(deque);

View file

@ -1162,7 +1162,7 @@ impl String {
/// Removes a [`char`] from this `String` at a byte position and returns it. /// Removes a [`char`] from this `String` at a byte position and returns it.
/// ///
/// This is an `O(n)` operation, as it requires copying every element in the /// This is an *O*(*n*) operation, as it requires copying every element in the
/// buffer. /// buffer.
/// ///
/// # Panics /// # Panics
@ -1262,7 +1262,7 @@ impl String {
/// Inserts a character into this `String` at a byte position. /// Inserts a character into this `String` at a byte position.
/// ///
/// This is an `O(n)` operation as it requires copying every element in the /// This is an *O*(*n*) operation as it requires copying every element in the
/// buffer. /// buffer.
/// ///
/// # Panics /// # Panics
@ -1309,7 +1309,7 @@ impl String {
/// Inserts a string slice into this `String` at a byte position. /// Inserts a string slice into this `String` at a byte position.
/// ///
/// This is an `O(n)` operation as it requires copying every element in the /// This is an *O*(*n*) operation as it requires copying every element in the
/// buffer. /// buffer.
/// ///
/// # Panics /// # Panics
@ -1971,7 +1971,7 @@ impl hash::Hash for String {
/// ///
/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if /// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if
/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on /// necessary). This is done to avoid allocating a new `String` and copying the entire contents on
/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by /// every operation, which would lead to *O*(*n*^2) running time when building an *n*-byte string by
/// repeated concatenation. /// repeated concatenation.
/// ///
/// The string on the right-hand side is only borrowed; its contents are copied into the returned /// The string on the right-hand side is only borrowed; its contents are copied into the returned

View file

@ -1672,7 +1672,7 @@ impl<T> [T] {
/// Sorts the slice, but may not preserve the order of equal elements. /// Sorts the slice, but may not preserve the order of equal elements.
/// ///
/// This sort is unstable (i.e., may reorder equal elements), in-place /// This sort is unstable (i.e., may reorder equal elements), in-place
/// (i.e., does not allocate), and `O(n * log(n))` worst-case. /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case.
/// ///
/// # Current implementation /// # Current implementation
/// ///
@ -1708,7 +1708,7 @@ impl<T> [T] {
/// elements. /// elements.
/// ///
/// This sort is unstable (i.e., may reorder equal elements), in-place /// This sort is unstable (i.e., may reorder equal elements), in-place
/// (i.e., does not allocate), and `O(n * log(n))` worst-case. /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case.
/// ///
/// The comparator function must define a total ordering for the elements in the slice. If /// The comparator function must define a total ordering for the elements in the slice. If
/// the ordering is not total, the order of the elements is unspecified. An order is a /// the ordering is not total, the order of the elements is unspecified. An order is a
@ -1763,8 +1763,8 @@ impl<T> [T] {
/// elements. /// elements.
/// ///
/// This sort is unstable (i.e., may reorder equal elements), in-place /// This sort is unstable (i.e., may reorder equal elements), in-place
/// (i.e., does not allocate), and `O(m * n * log(n))` worst-case, where the key function is /// (i.e., does not allocate), and *O*(m \* *n* \* log(*n*)) worst-case, where the key function is
/// `O(m)`. /// *O*(*m*).
/// ///
/// # Current implementation /// # Current implementation
/// ///
@ -1803,7 +1803,7 @@ impl<T> [T] {
/// This reordering has the additional property that any value at position `i < index` will be /// This reordering has the additional property that any value at position `i < index` will be
/// less than or equal to any value at a position `j > index`. Additionally, this reordering is /// less than or equal to any value at a position `j > index`. Additionally, this reordering is
/// unstable (i.e. any number of equal elements may end up at position `index`), in-place /// unstable (i.e. any number of equal elements may end up at position `index`), in-place
/// (i.e. does not allocate), and `O(n)` worst-case. This function is also/ known as "kth /// (i.e. does not allocate), and *O*(*n*) worst-case. This function is also/ known as "kth
/// element" in other libraries. It returns a triplet of the following values: all elements less /// element" in other libraries. It returns a triplet of the following values: all elements less
/// than the one at the given index, the value at the given index, and all elements greater than /// than the one at the given index, the value at the given index, and all elements greater than
/// the one at the given index. /// the one at the given index.
@ -1852,7 +1852,7 @@ impl<T> [T] {
/// This reordering has the additional property that any value at position `i < index` will be /// This reordering has the additional property that any value at position `i < index` will be
/// less than or equal to any value at a position `j > index` using the comparator function. /// less than or equal to any value at a position `j > index` using the comparator function.
/// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
/// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
/// is also known as "kth element" in other libraries. It returns a triplet of the following /// is also known as "kth element" in other libraries. It returns a triplet of the following
/// values: all elements less than the one at the given index, the value at the given index, /// values: all elements less than the one at the given index, the value at the given index,
/// and all elements greater than the one at the given index, using the provided comparator /// and all elements greater than the one at the given index, using the provided comparator
@ -1906,7 +1906,7 @@ impl<T> [T] {
/// This reordering has the additional property that any value at position `i < index` will be /// This reordering has the additional property that any value at position `i < index` will be
/// less than or equal to any value at a position `j > index` using the key extraction function. /// less than or equal to any value at a position `j > index` using the key extraction function.
/// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
/// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
/// is also known as "kth element" in other libraries. It returns a triplet of the following /// is also known as "kth element" in other libraries. It returns a triplet of the following
/// values: all elements less than the one at the given index, the value at the given index, and /// values: all elements less than the one at the given index, the value at the given index, and
/// all elements greater than the one at the given index, using the provided key extraction /// all elements greater than the one at the given index, using the provided key extraction

View file

@ -121,7 +121,7 @@ where
/// Partially sorts a slice by shifting several out-of-order elements around. /// Partially sorts a slice by shifting several out-of-order elements around.
/// ///
/// Returns `true` if the slice is sorted at the end. This function is `O(n)` worst-case. /// Returns `true` if the slice is sorted at the end. This function is *O*(*n*) worst-case.
#[cold] #[cold]
fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &mut F) -> bool fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &mut F) -> bool
where where
@ -168,7 +168,7 @@ where
false false
} }
/// Sorts a slice using insertion sort, which is `O(n^2)` worst-case. /// Sorts a slice using insertion sort, which is *O*(*n*^2) worst-case.
fn insertion_sort<T, F>(v: &mut [T], is_less: &mut F) fn insertion_sort<T, F>(v: &mut [T], is_less: &mut F)
where where
F: FnMut(&T, &T) -> bool, F: FnMut(&T, &T) -> bool,
@ -178,7 +178,7 @@ where
} }
} }
/// Sorts `v` using heapsort, which guarantees `O(n * log(n))` worst-case. /// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case.
#[cold] #[cold]
pub fn heapsort<T, F>(v: &mut [T], is_less: &mut F) pub fn heapsort<T, F>(v: &mut [T], is_less: &mut F)
where where
@ -751,7 +751,7 @@ where
} }
} }
/// Sorts `v` using pattern-defeating quicksort, which is `O(n * log(n))` worst-case. /// Sorts `v` using pattern-defeating quicksort, which is *O*(*n* \* log(*n*)) worst-case.
pub fn quicksort<T, F>(v: &mut [T], mut is_less: F) pub fn quicksort<T, F>(v: &mut [T], mut is_less: F)
where where
F: FnMut(&T, &T) -> bool, F: FnMut(&T, &T) -> bool,

View file

@ -7,8 +7,8 @@ use std::iter::FromIterator;
use crate::stable_hasher::{HashStable, StableHasher}; use crate::stable_hasher::{HashStable, StableHasher};
use rustc_index::vec::{Idx, IndexVec}; use rustc_index::vec::{Idx, IndexVec};
/// An indexed multi-map that preserves insertion order while permitting both `O(log n)` lookup of /// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of
/// an item by key and `O(1)` lookup by index. /// an item by key and *O*(1) lookup by index.
/// ///
/// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`, /// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`,
/// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order. /// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order.
@ -20,7 +20,7 @@ use rustc_index::vec::{Idx, IndexVec};
/// items will be yielded in insertion order. /// items will be yielded in insertion order.
/// ///
/// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and /// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and
/// `SortedIndexMultiMap` require `O(n)` time to insert a single item. This is because we may need /// `SortedIndexMultiMap` require *O*(*n*) time to insert a single item. This is because we may need
/// to insert into the middle of the sorted array. Users should avoid mutating this data structure /// to insert into the middle of the sorted array. Users should avoid mutating this data structure
/// in-place. /// in-place.
/// ///

View file

@ -772,7 +772,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
} }
/// Returns those indices that are true in rows `a` and `b`. This /// Returns those indices that are true in rows `a` and `b`. This
/// is an O(n) operation where `n` is the number of elements /// is an *O*(*n*) operation where *n* is the number of elements
/// (somewhat independent from the actual size of the /// (somewhat independent from the actual size of the
/// intersection, in particular). /// intersection, in particular).
pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> { pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> {

View file

@ -86,7 +86,7 @@
//! cost are suffixed with a `~`. //! cost are suffixed with a `~`.
//! //!
//! All amortized costs are for the potential need to resize when capacity is //! All amortized costs are for the potential need to resize when capacity is
//! exhausted. If a resize occurs it will take O(n) time. Our collections never //! exhausted. If a resize occurs it will take *O*(*n*) time. Our collections never
//! automatically shrink, so removal operations aren't amortized. Over a //! automatically shrink, so removal operations aren't amortized. Over a
//! sufficiently large series of operations, the average cost per operation will //! sufficiently large series of operations, the average cost per operation will
//! deterministically equal the given cost. //! deterministically equal the given cost.