| File: System\Linq\Parallel\Utils\FixedMaxHeap.cs | Web Access |
| Project: src\runtime\src\libraries\System.Linq.Parallel\src\System.Linq.Parallel.csproj (System.Linq.Parallel) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // FixedMaxHeap.cs // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Collections.Generic; using System.Diagnostics; namespace System.Linq.Parallel { /// <summary> /// Very simple heap data structure, of fixed size. /// </summary> /// <typeparam name="TElement"></typeparam> internal sealed class FixedMaxHeap<TElement> { private readonly TElement[] _elements; // Element array. private int _count; // Current count. private readonly IComparer<TElement> _comparer; // Element comparison routine. //----------------------------------------------------------------------------------- // Create a new heap with the specified maximum size. // internal FixedMaxHeap(int maximumSize) : this(maximumSize, Util.GetDefaultComparer<TElement>()) { } internal FixedMaxHeap(int maximumSize, IComparer<TElement> comparer) { Debug.Assert(comparer != null); _elements = new TElement[maximumSize]; _comparer = comparer; } //----------------------------------------------------------------------------------- // Retrieve the count (i.e. how many elements are in the heap). // internal int Count { get { return _count; } } //----------------------------------------------------------------------------------- // Retrieve the size (i.e. the maximum size of the heap). // internal int Size { get { return _elements.Length; } } //----------------------------------------------------------------------------------- // Get the current maximum value in the max-heap. // // Note: The heap stores the maximumSize smallest elements that were inserted. // So, if the heap is full, the value returned is the maximumSize-th smallest // element that was inserted into the heap. // internal TElement MaxValue { get { if (_count == 0) { throw new InvalidOperationException(SR.NoElements); } // The maximum element is in the 0th position. return _elements[0]; } } //----------------------------------------------------------------------------------- // Removes all elements from the heap. // internal void Clear() { _count = 0; } //----------------------------------------------------------------------------------- // Inserts the new element, maintaining the heap property. // // Return Value: // If the element is greater than the current max element, this function returns // false without modifying the heap. Otherwise, it returns true. // internal bool Insert(TElement e) { if (_count < _elements.Length) { // There is room. We can add it and then max-heapify. _elements[_count] = e; _count++; HeapifyLastLeaf(); return true; } else { // No more room. The element might not even fit in the heap. The check // is simple: if it's greater than the maximum element, then it can't be // inserted. Otherwise, we replace the head with it and reheapify. if (_comparer.Compare(e, _elements[0]) < 0) { _elements[0] = e; HeapifyRoot(); return true; } return false; } } //----------------------------------------------------------------------------------- // Replaces the maximum value in the heap with the user-provided value, and restores // the heap property. // internal void ReplaceMax(TElement newValue) { Debug.Assert(_count > 0); _elements[0] = newValue; HeapifyRoot(); } //----------------------------------------------------------------------------------- // Removes the maximum value from the heap, and restores the heap property. // internal void RemoveMax() { Debug.Assert(_count > 0); _count--; if (_count > 0) { _elements[0] = _elements[_count]; HeapifyRoot(); } } //----------------------------------------------------------------------------------- // Private helpers to swap elements, and to reheapify starting from the root or // from a leaf element, depending on what is needed. // private void Swap(int i, int j) { TElement tmpElement = _elements[i]; _elements[i] = _elements[j]; _elements[j] = tmpElement; } private void HeapifyRoot() { // We are heapifying from the head of the list. int i = 0; int n = _count; while (i < n) { // Calculate the current child node indexes. int n0 = ((i + 1) * 2) - 1; int n1 = n0 + 1; if (n0 < n && _comparer.Compare(_elements[i], _elements[n0]) < 0) { // We have to select the bigger of the two subtrees, and float // the current element down. This maintains the max-heap property. if (n1 < n && _comparer.Compare(_elements[n0], _elements[n1]) < 0) { Swap(i, n1); i = n1; } else { Swap(i, n0); i = n0; } } else if (n1 < n && _comparer.Compare(_elements[i], _elements[n1]) < 0) { // Float down the "right" subtree. We needn't compare this subtree // to the "left", because if the element was smaller than that, the // first if statement's predicate would have evaluated to true. Swap(i, n1); i = n1; } else { // Else, the current key is in its final position. Break out // of the current loop and return. break; } } } private void HeapifyLastLeaf() { int i = _count - 1; while (i > 0) { int j = ((i + 1) / 2) - 1; if (_comparer.Compare(_elements[i], _elements[j]) > 0) { Swap(i, j); i = j; } else { break; } } } } }