18 Star 133 Fork 63

编程语言算法集 / C-Sharp

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
BinaryHeap.cs 7.54 KB
一键复制 编辑 原始数据 按行查看 历史
Gerson Jr 提交于 2024-01-08 14:18 . Switch to file-scoped namespaces (#434)
using System;
using System.Collections.Generic;
namespace DataStructures.Heap;
/// <summary>
/// A generic implementation of a binary heap.
/// </summary>
/// <remarks>
/// A binary heap is a complete binary tree that satisfies the heap property;
/// that is every node in the tree compares greater/less than or equal to its left and right
/// child nodes. Note that this is different from a binary search tree, where every node
/// must be the largest/smallest node of all of its children.
/// Although binary heaps are not very efficient, they are (probably) the simpliest heaps
/// to understand and implement.
/// More information: https://en.wikipedia.org/wiki/Binary_heap .
/// </remarks>
/// <typeparam name="T">Type of elements in binary heap.</typeparam>
public class BinaryHeap<T>
{
/// <summary>
/// Comparer to use when comparing elements.
/// </summary>
private readonly Comparer<T> comparer;
/// <summary>
/// List to hold the elements of the heap.
/// </summary>
private readonly List<T> data;
/// <summary>
/// Initializes a new instance of the <see cref="BinaryHeap{T}" /> class.
/// </summary>
public BinaryHeap()
{
data = new List<T>();
comparer = Comparer<T>.Default;
}
/// <summary>
/// Initializes a new instance of the <see cref="BinaryHeap{T}" /> class with a custom comparision function.
/// </summary>
/// <param name="customComparer">The custom comparing function to use to compare elements.</param>
public BinaryHeap(Comparer<T> customComparer)
{
data = new List<T>();
comparer = customComparer;
}
/// <summary>
/// Gets the number of elements in the heap.
/// </summary>
public int Count => data.Count;
/// <summary>
/// Add an element to the binary heap.
/// </summary>
/// <remarks>
/// Adding to the heap is done by append the element to the end of the backing list,
/// and pushing the added element up until the heap property is restored.
/// </remarks>
/// <param name="element">The element to add to the heap.</param>
/// <exception cref="ArgumentException">Thrown if element is already in heap.</exception>
public void Push(T element)
{
data.Add(element);
HeapifyUp(data.Count - 1);
}
/// <summary>
/// Remove the top/root of the binary heap (ie: the largest/smallest element).
/// </summary>
/// <remarks>
/// Removing from the heap is done by swapping the top/root with the last element in
/// the backing list, removing the last element, and pushing the new root down
/// until the heap property is restored.
/// </remarks>
/// <returns>The top/root of the heap.</returns>
/// <exception cref="InvalidOperationException">Thrown if heap is empty.</exception>
public T Pop()
{
if (Count == 0)
{
throw new InvalidOperationException("Heap is empty!");
}
var elem = data[0];
data[0] = data[^1];
data.RemoveAt(data.Count - 1);
HeapifyDown(0);
return elem;
}
/// <summary>
/// Return the top/root of the heap without removing it.
/// </summary>
/// <returns>The top/root of the heap.</returns>
/// <exception cref="InvalidOperationException">Thrown if heap is empty.</exception>
public T Peek()
{
if (Count == 0)
{
throw new InvalidOperationException("Heap is empty!");
}
return data[0];
}
/// <summary>
/// Returns element if it compares larger to the top/root of the heap, else
/// inserts element into the heap and returns the top/root of the heap.
/// </summary>
/// <param name="element">The element to check/insert.</param>
/// <returns>element if element compares larger than top/root of heap, top/root of heap otherwise.</returns>
public T PushPop(T element)
{
if (Count == 0)
{
return element;
}
if (comparer.Compare(element, data[0]) < 0)
{
var tmp = data[0];
data[0] = element;
HeapifyDown(0);
return tmp;
}
return element;
}
/// <summary>
/// Check if element is in the heap.
/// </summary>
/// <param name="element">The element to check for.</param>
/// <returns>true if element is in the heap, false otherwise.</returns>
public bool Contains(T element) => data.Contains(element);
/// <summary>
/// Remove an element from the heap.
/// </summary>
/// <remarks>
/// In removing an element from anywhere in the heap, we only need to push down or up
/// the replacement value depending on how the removed value compares to its
/// replacement value.
/// </remarks>
/// <param name="element">The element to remove from the heap.</param>
/// <exception cref="ArgumentException">Thrown if element is not in heap.</exception>
public void Remove(T element)
{
var idx = data.IndexOf(element);
if (idx == -1)
{
throw new ArgumentException($"{element} not in heap!");
}
Swap(idx, data.Count - 1);
var tmp = data[^1];
data.RemoveAt(data.Count - 1);
if (idx < data.Count)
{
if (comparer.Compare(tmp, data[idx]) > 0)
{
HeapifyDown(idx);
}
else
{
HeapifyUp(idx);
}
}
}
/// <summary>
/// Swap the elements in the heap array at the given indices.
/// </summary>
/// <param name="idx1">First index.</param>
/// <param name="idx2">Second index.</param>
private void Swap(int idx1, int idx2)
{
var tmp = data[idx1];
data[idx1] = data[idx2];
data[idx2] = tmp;
}
/// <summary>
/// Recursive function to restore heap properties.
/// </summary>
/// <remarks>
/// Restores heap property by swapping the element at <paramref name="elemIdx" />
/// with its parent if the element compares greater than its parent.
/// </remarks>
/// <param name="elemIdx">The element to check with its parent.</param>
private void HeapifyUp(int elemIdx)
{
var parent = (elemIdx - 1) / 2;
if (parent >= 0 && comparer.Compare(data[elemIdx], data[parent]) > 0)
{
Swap(elemIdx, parent);
HeapifyUp(parent);
}
}
/// <summary>
/// Recursive function to restore heap properties.
/// </summary>
/// <remarks>
/// Restores heap property by swapping the element at <paramref name="elemIdx" />
/// with the larger of its children.
/// </remarks>
/// <param name="elemIdx">The element to check with its children.</param>
private void HeapifyDown(int elemIdx)
{
var left = 2 * elemIdx + 1;
var right = 2 * elemIdx + 2;
var leftLargerThanElem = left < Count && comparer.Compare(data[elemIdx], data[left]) < 0;
var rightLargerThanElem = right < Count && comparer.Compare(data[elemIdx], data[right]) < 0;
var leftLargerThanRight = left < Count && right < Count && comparer.Compare(data[left], data[right]) > 0;
if (leftLargerThanElem && leftLargerThanRight)
{
Swap(elemIdx, left);
HeapifyDown(left);
}
else if (rightLargerThanElem && !leftLargerThanRight)
{
Swap(elemIdx, right);
HeapifyDown(right);
}
}
}
C#
1
https://gitee.com/TheAlgorithms/C-Sharp.git
git@gitee.com:TheAlgorithms/C-Sharp.git
TheAlgorithms
C-Sharp
C-Sharp
master

搜索帮助