forked from abdonkov/DSA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BinaryMaxHeap.cs
268 lines (232 loc) · 10.1 KB
/
BinaryMaxHeap.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
using DSA.DataStructures.Interfaces;
using DSA.DataStructures.Lists;
using System;
using System.Collections.Generic;
namespace DSA.DataStructures.Heaps
{
/// <summary>
/// Represents a binary max heap backed by an <see cref="ArrayList{T}"/>.
/// </summary>
/// <typeparam name="T">The stored value type. T implements <see cref="IComparable{T}"/>.</typeparam>
public class BinaryMaxHeap<T> : IMaxHeap<T>
where T : IComparable<T>
{
/// <summary>
/// The backing <see cref="ArrayList{T}"/> containing the elements of the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
internal ArrayList<T> array;
/// <summary>
/// The comparer of the elements in the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
internal Comparer<T> comparer;
/// <summary>
/// Gets the number of elements in the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
public int Count { get; internal set; }
/// <summary>
/// Determines whether the <see cref="BinaryMaxHeap{T}"/> is empty.
/// </summary>
public bool IsEmpty { get { return Count == 0; } }
/// <summary>
/// Creates a new instance of the <see cref="BinaryMaxHeap{T}"/> class.
/// </summary>
public BinaryMaxHeap() : this(0, null) { }
/// <summary>
/// Creates a new instance of the <see cref="BinaryMaxHeap{T}"/> class with the given capacity for the backing <see cref="ArrayList{T}"/>.
/// </summary>
/// <param name="capacity">The capacity for the underlying <see cref="ArrayList{T}"/>.</param>
public BinaryMaxHeap(int capacity) : this(capacity, null) { }
/// <summary>
/// Creates a new instance of the <see cref="BinaryMaxHeap{T}"/> class with the specified comparer.
/// </summary>
/// <param name="comparer">The comparer of the elements in the <see cref="BinaryMaxHeap{T}"/>.</param>
public BinaryMaxHeap(Comparer<T> comparer) : this(0, comparer) { }
/// <summary>
/// Creates a new instance of the <see cref="BinaryMaxHeap{T}"/> class with the specified comparer and the given capacity for the backing <see cref="ArrayList{T}"/>.
/// </summary>
/// <param name="capacity">The capacity for the underlying <see cref="ArrayList{T}"/>.</param>
/// <param name="comparer">The comparer of the elements in the <see cref="BinaryMaxHeap{T}"/>.</param>
public BinaryMaxHeap(int capacity, Comparer<T> comparer)
{
array = new ArrayList<T>(capacity);
this.comparer = comparer ?? Comparer<T>.Default;
}
/// <summary>
/// Performing heapify-up operation on the given node. Used to rebalance the heap after adding a new item.
/// </summary>
/// <param name="nodeIndex">The index of the node to heapify-up.</param>
private void NodeHeapifyUp(int nodeIndex)
{
while (nodeIndex > 0)
{
// Getting the parent node
int parentIndex = (nodeIndex - 1) / 2;
if (comparer.Compare(array[parentIndex], array[nodeIndex]) < 0)
{// if the parent is smaller that the current node
// we have to swap them
var temp = array[parentIndex];
array[parentIndex] = array[nodeIndex];
array[nodeIndex] = temp;
// then we continue comparing the node with it's new parent
nodeIndex = parentIndex;
}
else// if the parent is bigger than or equal to the current node
break;// no more adjustments are needed
}
}
/// <summary>
/// Performing heapify-down operation on the given node. Used to rebalance the heap after removing or replacing the root.
/// </summary>
/// <param name="nodeIndex"></param>
private void NodeHeapifyDown(int nodeIndex)
{
var leftChildIndex = 2 * nodeIndex + 1;
var rigthChildIndex = 2 * nodeIndex + 2;
// while the current node has children
while (leftChildIndex < array.Count)
{
// saving the index of the biggest node of the three(current node and its children)
var biggestNodeIndex = nodeIndex;
// compare right child with the biggest node(current node for now)
if (rigthChildIndex < array.Count)// needed checking if there is a right node also
if (comparer.Compare(array[rigthChildIndex], array[biggestNodeIndex]) > 0)
biggestNodeIndex = rigthChildIndex;
// compare left child with the biggest node(current node or right child)
if (comparer.Compare(array[leftChildIndex], array[biggestNodeIndex]) > 0)
biggestNodeIndex = leftChildIndex;
// if the current node is the biggest
if (biggestNodeIndex == nodeIndex)
break;// no more adjustments are needed
// else if one of the children is bigger that the current node we swap them
var temp = array[nodeIndex];
array[nodeIndex] = array[biggestNodeIndex];
array[biggestNodeIndex] = temp;
// continue downwards with the comparison
nodeIndex = biggestNodeIndex;
leftChildIndex = 2 * nodeIndex + 1;
rigthChildIndex = 2 * nodeIndex + 2;
}
}
/// <summary>
/// Heapifies the given <see cref="IEnumerable{T}"/> collection. Overrides the current <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
/// <param name="collection">The collection of elements to heapify.</param>
public void Heapify(IEnumerable<T> collection)
{
if (collection == null) throw new ArgumentNullException();
var newArrayList = new ArrayList<T>(collection);
if (newArrayList.Count > 0)
{
array = newArrayList;
// Building the binary heap
int lastNodeWithChildrenIndex = (array.Count - 2) / 2;
for (int i = lastNodeWithChildrenIndex; i >= 0; i--)
{
NodeHeapifyDown(i);
}
Count = array.Count;
}
}
/// <summary>
/// Merges the elements of the <see cref="BinaryMaxHeap{T}"/> with the other given <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
/// <param name="otherMaxHeap">The other <see cref="BinaryMaxHeap{T}"/> used for merging.</param>
public void Merge(BinaryMaxHeap<T> otherMaxHeap)
{
for (int i = 0; i < otherMaxHeap.Count; i++)
{
Add(otherMaxHeap.array[i]);
}
}
/// <summary>
/// Adds an element to the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
/// <param name="value">The value to add.</param>
public void Add(T value)
{
if (IsEmpty)
array.Add(value);
else
{
array.Add(value);
NodeHeapifyUp(array.Count - 1);
}
Count++;
}
/// <summary>
/// Gets the max element of the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
/// <returns>Returns the max element of the <see cref="BinaryMaxHeap{T}"/>.</returns>
public T PeekMax()
{
if (IsEmpty) throw new InvalidOperationException("Heap is empty!");
return array[0];
}
/// <summary>
/// Removes and returns the max element of the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
/// <returns>Returns the max element which was removed from the <see cref="BinaryMaxHeap{T}"/>.</returns>
public T PopMax()
{
var max = PeekMax();
RemoveMax();
return max;
}
/// <summary>
/// Replaces the max element with the given value and rebalancing the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
/// <param name="value">The value to replace the max element of the <see cref="BinaryMaxHeap{T}"/>.</param>
public void ReplaceMax(T value)
{
if (IsEmpty) if (IsEmpty) throw new InvalidOperationException("Heap is empty!");
array[0] = value;
NodeHeapifyDown(0);
}
/// <summary>
/// Removes the max element from the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
public void RemoveMax()
{
if (IsEmpty) throw new InvalidOperationException("Heap is empty!");
array[0] = array[Count - 1];
array.RemoveAt(Count - 1);
Count--;
NodeHeapifyDown(0);
}
/// <summary>
/// Removes all elements from the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
public void Clear()
{
array = new ArrayList<T>();
Count = 0;
}
/// <summary>
/// Copies the elements of the <see cref="BinaryMaxHeap{T}"/> to a new array.
/// </summary>
/// <returns>An array containing copies of the elements of the <see cref="BinaryMaxHeap{T}"/>.</returns>
public T[] ToArray()
{
var newArray = new T[Count];
for (int i = 0; i < Count; i++)
{
newArray[i] = array[i];
}
return newArray;
}
/// <summary>
/// Returns a new <see cref="BinaryMinHeap{T}"/> containing the elements of the <see cref="BinaryMaxHeap{T}"/>.
/// </summary>
/// <returns>Returns a new <see cref="BinaryMinHeap{T}"/> containing the elements of the <see cref="BinaryMaxHeap{T}"/>.</returns>
public BinaryMinHeap<T> ToMinHeap()
{
var minHeap = new BinaryMinHeap<T>(Count, comparer);
minHeap.Heapify(ToArray());
return minHeap;
}
IMinHeap<T> IMaxHeap<T>.ToMinHeap()
{
return ToMinHeap();
}
}
}