Rust 常见内置 Traits 详解(一):https://ipotato.me/article/59
BinaryHrap 源码解析:https://zhuanlan.zhihu.com/p/305107063
#[stable(feature = "rust1", since = "1.0.0")]#[cfg_attr(not(test), rustc_diagnostic_item = "BinaryHeap")]pub struct BinaryHeap<T> {data: Vec<T>, // T -> Ord}impl<T: Ord> BinaryHeap<T> {/// Creates an empty `BinaryHeap` as a max-heap.////// # Examples////// Basic usage://////
/// use std::collections::BinaryHeap;/// let mut heap = BinaryHeap::new();/// heap.push(4);/// ```#[stable(feature = "rust1", since = "1.0.0")]#[must_use]pub fn new() -> BinaryHeap<T> {BinaryHeap { data: vec![] }}/// Returns the length of the binary heap.////// # Examples////// Basic usage:////// ```/// use std::collections::BinaryHeap;/// let heap = BinaryHeap::from([1, 3]);////// assert_eq!(heap.len(), 2);/// ```#[must_use]#[stable(feature = "rust1", since = "1.0.0")]pub fn len(&self) -> usize {self.data.len()}/// Pushes an item onto the binary heap.////// # Examples////// Basic usage:////// ```/// use std::collections::BinaryHeap;/// let mut heap = BinaryHeap::new();/// heap.push(3);/// heap.push(5);/// heap.push(1);////// assert_eq!(heap.len(), 3);/// assert_eq!(heap.peek(), Some(&5));/// ```////// # Time complexity////// The expected cost of `push`, averaged over every possible ordering 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/// elements that are *not* already in any sorted pattern.////// The time complexity degrades if elements are pushed in predominantly/// 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/// containing *n* elements.////// 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/// has been amortized in the previous figures.#[stable(feature = "rust1", since = "1.0.0")]pub fn push(&mut self, item: T) {let old_len = self.len();self.data.push(item);// SAFETY: Since we pushed a new item it means that// old_len = self.len() - 1 < self.len()unsafe { self.sift_up(0, old_len) };}// The implementations of sift_up and sift_down use unsafe blocks in// order to move an element out of the vector (leaving behind a// hole), shift along the others and move the removed element back into the// vector at the final location of the hole.// The `Hole` type is used to represent this, and make sure// the hole is filled back at the end of its scope, even on panic.// Using a hole reduces the constant factor compared to using swaps,// which involves twice as many moves./// # Safety////// The caller must guarantee that `pos < self.len()`.unsafe fn sift_up(&mut self, start: usize, pos: usize) -> usize {// Take out the value at `pos` and create a hole.// SAFETY: The caller guarantees that pos < self.len()let mut hole = unsafe { Hole::new(&mut self.data, pos) };while hole.pos() > start {let parent = (hole.pos() - 1) / 2;// SAFETY: hole.pos() > start >= 0, which means hole.pos() > 0// and so hole.pos() - 1 can't underflow.// This guarantees that parent < hole.pos() so// it's a valid index and also != hole.pos().// valid 正当的;有效的,有根据的// underflow 下溢// guarantee 保证if hole.element() <= unsafe { hole.get(parent) } {break;}// SAFETY: Same as aboveunsafe { hole.move_to(parent) };}hole.pos()}
}
javascript 最小堆 (leetcode 丑数)链接:[https://leetcode.cn/problems/ugly-number-ii/solution/chou-shu-ii-by-leetcode-solution-uoqd/](https://leetcode.cn/problems/ugly-number-ii/solution/chou-shu-ii-by-leetcode-solution-uoqd/)```javascriptvar nthUglyNumber = function(n) {const factors = [2, 3, 5];const seen = new Set();const heap = new MinHeap();seen.add(1);heap.insert(1);let ugly = 0;for (let i = 0; i < n; i++) {ugly = heap.pop();for (const factor of factors) {const next = ugly * factor;if (!seen.has(next)) {seen.add(next);heap.insert(next);}}}return ugly;};// 最小堆class MinHeap {constructor() {this.heap = [];}getParentIndex(i) {return (i - 1) >> 1;}getLeftIndex(i) {return i * 2 + 1;}getRightIndex(i) {return i * 2 + 2;}shiftUp(index) {if(index === 0) { return; }const parentIndex = this.getParentIndex(index);if(this.heap[parentIndex] > this.heap[index]){this.swap(parentIndex, index);this.shiftUp(parentIndex);}}swap(i1, i2) {const temp = this.heap[i1];this.heap[i1]= this.heap[i2];this.heap[i2] = temp;}insert(value) {this.heap.push(value);this.shiftUp(this.heap.length - 1);}pop() {this.heap[0] = this.heap.pop();this.shiftDown(0);return this.heap[0];}shiftDown(index) {const leftIndex = this.getLeftIndex(index);const rightIndex = this.getRightIndex(index);if (this.heap[leftIndex] < this.heap[index]) {this.swap(leftIndex, index);this.shiftDown(leftIndex);}if (this.heap[rightIndex] < this.heap[index]){this.swap(rightIndex, index);this.shiftDown(rightIndex);}}peek() {return this.heap[0];}size() {return this.heap.length;}}
