From aa680f79fcef30c4cf4fd71a318726f3f824daa0 Mon Sep 17 00:00:00 2001 From: Xu Shaohua Date: Thu, 23 May 2024 10:36:59 +0800 Subject: [PATCH] sorts: Add binary heap --- sort/src/binary_heap.rs | 123 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 sort/src/binary_heap.rs diff --git a/sort/src/binary_heap.rs b/sort/src/binary_heap.rs new file mode 100644 index 00000000..a23349ca --- /dev/null +++ b/sort/src/binary_heap.rs @@ -0,0 +1,123 @@ +// Copyright (c) 2024 Xu Shaohua . All rights reserved. +// Use of this source is governed by General Public License that can be found +// in the LICENSE file. + +// Binary heap + +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub struct BinaryHeap { + heap: Vec, +} + +impl Default for BinaryHeap { + fn default() -> Self { + Self::new() + } +} + +impl BinaryHeap { + #[must_use] + #[inline] + pub const fn new() -> Self { + Self { heap: Vec::new() } + } + + pub fn from_slice(slice: &[i32]) -> Self { + Self { + heap: slice.to_vec(), + } + } + + #[must_use] + #[inline] + pub fn len(&self) -> usize { + self.heap.len() + } + + #[must_use] + #[inline] + pub fn is_empty(&self) -> bool { + self.heap.is_empty() + } + + #[must_use] + #[inline] + pub fn peak(&self) -> Option { + self.heap.first().copied() + } + + pub fn push(&mut self, val: i32) { + // 先将新的元素插入到数组尾部. + self.heap.push(val); + + // 然后将该元素进行上移 (shift up). + self.shift_up(self.heap.len() - 1); + } + + #[must_use] + pub fn pop(&mut self) -> Option { + if self.is_empty() { + return None; + } + + // 将堆顶的元素交换到数组的尾部, 并弹出它. + let len = self.len(); + self.heap.swap(0, len - 1); + let last = self.heap.pop(); + + // 然后调整堆顶的位置, 让它保持大顶堆的特性. + self.shift_down(0, len); + + last + } + + // 将该节点与父节点进行比较, 如果比父节点大, 就让它跟父节点交换, + // 一直重复这个过程, 直到找到合适的位置. + // + // 时间复杂度是 O(log(n)), 是树的高度. + fn shift_up(&mut self, mut pos: usize) { + if pos == 0 { + return; + } + + let mut parent_pos = (pos - 1) / 2; + while self.heap[parent_pos] < self.heap[pos] { + if parent_pos == 0 { + break; + } + pos = parent_pos; + parent_pos = (pos - 1) / 2; + } + } + + // 将该节点与子节点进行比较, 如果比子节点大, 就让它跟较大的那个子节点交换, + // 一直重复这个过 程, 直到找到合适的位置. + // + // 时间复杂度是 O(log(n)), 是树的高度. + fn shift_down(&mut self, mut pos: usize, len: usize) { + while pos * 2 + 1 < len { + let left = pos * 2 + 1; + let right = pos * 2 + 2; + + let larger = if right >= len { + // 右子树不存在, 它超出了数组的范围. + left + } else if self.heap[left] >= self.heap[right] { + // 左侧子树较大 + left + } else { + // 右侧子树较大 + right + }; + + // 当前节点与较大的子节点进行比较, 如果比它小就进行交换. + if self.heap[pos] < self.heap[larger] { + self.heap.swap(pos, larger); + pos = larger; + } else { + // 当前节点比最大的子节点还大 + break; + } + } + } +}