3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
10 // <OWNER>[....]</OWNER>
12 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
14 using System.Collections.Generic;
15 using System.Diagnostics.Contracts;
17 using System.Core; // for System.Core.SR
20 namespace System.Linq.Parallel
23 /// Very simple heap data structure, of fixed size.
25 /// <typeparam name="TElement"></typeparam>
26 internal class FixedMaxHeap<TElement>
29 private TElement[] m_elements; // Element array.
30 private int m_count; // Current count.
31 private IComparer<TElement> m_comparer; // Element comparison routine.
33 //-----------------------------------------------------------------------------------
34 // Create a new heap with the specified maximum size.
37 internal FixedMaxHeap(int maximumSize)
38 : this(maximumSize, Util.GetDefaultComparer<TElement>())
42 internal FixedMaxHeap(int maximumSize, IComparer<TElement> comparer)
44 Contract.Assert(comparer != null);
46 m_elements = new TElement[maximumSize];
47 m_comparer = comparer;
50 //-----------------------------------------------------------------------------------
51 // Retrieve the count (i.e. how many elements are in the heap).
56 get { return m_count; }
59 //-----------------------------------------------------------------------------------
60 // Retrieve the size (i.e. the maximum size of the heap).
65 get { return m_elements.Length; }
68 //-----------------------------------------------------------------------------------
69 // Get the current maximum value in the max-heap.
71 // Note: The heap stores the maximumSize smallest elements that were inserted.
72 // So, if the heap is full, the value returned is the maximumSize-th smallest
73 // element that was inserted into the heap.
76 internal TElement MaxValue
82 throw new InvalidOperationException(SR.GetString(SR.NoElements));
85 // The maximum element is in the 0th position.
91 //-----------------------------------------------------------------------------------
92 // Removes all elements from the heap.
100 //-----------------------------------------------------------------------------------
101 // Inserts the new element, maintaining the heap property.
104 // If the element is greater than the current max element, this function returns
105 // false without modifying the heap. Otherwise, it returns true.
108 internal bool Insert(TElement e)
110 if (m_count < m_elements.Length)
112 // There is room. We can add it and then max-heapify.
113 m_elements[m_count] = e;
120 // No more room. The element might not even fit in the heap. The check
121 // is simple: if it's greater than the maximum element, then it can't be
122 // inserted. Otherwise, we replace the head with it and reheapify.
123 if (m_comparer.Compare(e, m_elements[0]) < 0)
134 //-----------------------------------------------------------------------------------
135 // Replaces the maximum value in the heap with the user-provided value, and restores
136 // the heap property.
139 internal void ReplaceMax(TElement newValue)
141 Contract.Assert(m_count > 0);
142 m_elements[0] = newValue;
146 //-----------------------------------------------------------------------------------
147 // Removes the maximum value from the heap, and restores the heap property.
150 internal void RemoveMax()
152 Contract.Assert(m_count > 0);
157 m_elements[0] = m_elements[m_count];
162 //-----------------------------------------------------------------------------------
163 // Private helpers to swap elements, and to reheapify starting from the root or
164 // from a leaf element, depending on what is needed.
167 private void Swap(int i, int j)
169 TElement tmpElement = m_elements[i];
170 m_elements[i] = m_elements[j];
171 m_elements[j] = tmpElement;
174 private void HeapifyRoot()
176 // We are heapifying from the head of the list.
182 // Calculate the current child node indexes.
183 int n0 = ((i + 1) * 2) - 1;
186 if (n0 < n && m_comparer.Compare(m_elements[i], m_elements[n0]) < 0)
188 // We have to select the bigger of the two subtrees, and float
189 // the current element down. This maintains the max-heap property.
190 if (n1 < n && m_comparer.Compare(m_elements[n0], m_elements[n1]) < 0)
201 else if (n1 < n && m_comparer.Compare(m_elements[i], m_elements[n1]) < 0)
203 // Float down the "right" subtree. We needn't compare this subtree
204 // to the "left", because if the element was smaller than that, the
205 // first if statement's predicate would have evaluated to true.
211 // Else, the current key is in its final position. Break out
212 // of the current loop and return.
218 private void HeapifyLastLeaf()
223 int j = ((i + 1) / 2) - 1;
225 if (m_comparer.Compare(m_elements[i], m_elements[j]) > 0)