1
+ /**
2
+ * Copyright 2022 jingedawang
3
+ */
4
+ package container ;
5
+
6
+ /**
7
+ * BinaryHeap is basically a binary tree, whose each sub-tree keeps the max or min value in the root node.
8
+ *
9
+ * The underlying data is stored in an array, which is good for quick access.
10
+ * After the heap is built, the values are stored layer by layer in the array. For example, an array
11
+ * [4, 8, 1, 2, 0, 6, 5, 1, 9, 3]
12
+ * represents a heap like
13
+ * <pre>
14
+ * +--------------0---------------+
15
+ * +------1-------+ +------1-------+
16
+ * +--2---+ +--3---+ +--6---+ +--5---+
17
+ * 4 9 8
18
+ * </pre>
19
+ * To save time, we won't maintain a tree structure all the time. If you need to access the data by traversing
20
+ * its nodes, please call {@code toBinaryTree} method, which will return as a structured binary tree.
21
+ */
22
+ public class BinaryHeap extends AbstractTree implements BinaryTree , Heap {
23
+
24
+ /**
25
+ * Construct an empty max heap.
26
+ */
27
+ public BinaryHeap () {
28
+ this (new int [0 ], false );
29
+ }
30
+
31
+ /**
32
+ * Construct a heap with given array.
33
+ *
34
+ * @param arr The data used for constructing the heap.
35
+ * @param isMinHeap A flag indicating whether to create a min heap or a max heap.
36
+ */
37
+ public BinaryHeap (int [] arr , boolean isMinHeap ) {
38
+ this .isMinHeap = isMinHeap ;
39
+ data = arr .clone ();
40
+ capacity = data .length ;
41
+ size = data .length ;
42
+ for (int i = size / 2 - 1 ; i >= 0 ; i --) {
43
+ if (isMinHeap ) {
44
+ minHeapify (i );
45
+ } else {
46
+ maxHeapify (i );
47
+ }
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Check if the heap has no elements.
53
+ *
54
+ * @return {@code true} if the heap has no elements, {@code false} otherwise.
55
+ */
56
+ @ Override
57
+ public boolean empty () {
58
+ return size == 0 ;
59
+ }
60
+
61
+ /**
62
+ * Get the size of the heap.
63
+ *
64
+ * @return The element count of the heap.
65
+ */
66
+ @ Override
67
+ public int size () {
68
+ return size ;
69
+ }
70
+
71
+ /**
72
+ * Get the top value of the heap.
73
+ *
74
+ * If this is a max heap, the return value is the maximum.
75
+ * If this is a min heap, the return value is the minimum.
76
+ *
77
+ * @return The top value of the heap.
78
+ */
79
+ @ Override
80
+ public int top () {
81
+ return data [0 ];
82
+ }
83
+
84
+ /**
85
+ * Insert a node into the heap.
86
+ *
87
+ * The node will be inserted to a proper location in the heap.
88
+ * @param newNode The node to be inserted.
89
+ */
90
+ @ Override
91
+ public void insert (Node newNode ) {
92
+ if (size >= capacity ) {
93
+ int [] newArr ;
94
+ if (capacity > 0 ) {
95
+ newArr = new int [capacity * 2 ];
96
+ System .arraycopy (data , 0 , newArr , 0 , size );
97
+ } else {
98
+ newArr = new int [8 ];
99
+ }
100
+ data = newArr ;
101
+ capacity = newArr .length ;
102
+ }
103
+ size ++;
104
+ if (isMinHeap ) {
105
+ data [size - 1 ] = Integer .MAX_VALUE ;
106
+ decreaseValue (size - 1 , newNode .value );
107
+ }
108
+ else {
109
+ data [size - 1 ] = Integer .MIN_VALUE ;
110
+ increaseValue (size - 1 , newNode .value );
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Delete a node from the heap.
116
+ *
117
+ * Since the heap doesn't maintain the tree structure, so deleting a node from a heap is meaningless. Also, it's not
118
+ * useful to delete a node from a heap.
119
+ *
120
+ * @param node The node to be deleted.
121
+ */
122
+ @ Override
123
+ public void delete (Node node ) {
124
+ throw new UnsupportedOperationException ("'delete' method not supported in BinaryHeap class" );
125
+ }
126
+
127
+ /**
128
+ * Get and remove the top value of the heap.
129
+ *
130
+ * If this is a max heap, the return value is the maximum.
131
+ * If this is a min heap, the return value is the minimum.
132
+ * The top node will be removed and the heap will be maintained.
133
+ *
134
+ * @return The top value of the heap.
135
+ */
136
+ @ Override
137
+ public int pop () {
138
+ if (size <= 0 ) {
139
+ throw new ArrayIndexOutOfBoundsException ("Can not pop a value from an empty heap." );
140
+ }
141
+ int top = data [0 ];
142
+ data [0 ] = data [size - 1 ];
143
+ size --;
144
+ if (isMinHeap ) {
145
+ minHeapify (0 );
146
+ }
147
+ else {
148
+ maxHeapify (0 );
149
+ }
150
+ return top ;
151
+ }
152
+
153
+ /**
154
+ * Construct the tree structure and return as a binary tree.
155
+ *
156
+ * @return A binary tree converted from the heap.
157
+ */
158
+ public BinaryTree toBinaryTree () {
159
+ root = constructSubtree (0 );
160
+ return this ;
161
+ }
162
+
163
+ /**
164
+ * Adjust the maximum sub-heap to maintain its properties.
165
+ *
166
+ * @param index The root index of the sub-heap.
167
+ */
168
+ private void maxHeapify (int index ) {
169
+ int l = left (index );
170
+ int r = right (index );
171
+ int largest ;
172
+ if (l < size && data [l ] > data [index ]) {
173
+ largest = l ;
174
+ } else {
175
+ largest = index ;
176
+ }
177
+ if (r < size && data [r ] > data [largest ]) {
178
+ largest = r ;
179
+ }
180
+ if (largest != index ) {
181
+ int temp = data [index ];
182
+ data [index ] = data [largest ];
183
+ data [largest ] = temp ;
184
+ maxHeapify (largest );
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Adjust the minimum sub-heap to maintain its properties.
190
+ *
191
+ * @param index The root index of the sub-heap.
192
+ */
193
+ private void minHeapify (int index ) {
194
+ int l = left (index );
195
+ int r = right (index );
196
+ int smallest ;
197
+ if (l < size && data [l ] < data [index ]) {
198
+ smallest = l ;
199
+ } else {
200
+ smallest = index ;
201
+ }
202
+ if (r < size && data [r ] < data [smallest ]) {
203
+ smallest = r ;
204
+ }
205
+ if (smallest != index ) {
206
+ int temp = data [index ];
207
+ data [index ] = data [smallest ];
208
+ data [smallest ] = temp ;
209
+ minHeapify (smallest );
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Increase the value of the specified item and adjust the heap to keep its properties.
215
+ * <p>
216
+ * The new value must be greater than the original value, or this method would raise an error.
217
+ * This method should be called from a max heap.
218
+ *
219
+ * @param index The index of the specified item.
220
+ * @param newValue The new value of the specified item.
221
+ */
222
+ private void increaseValue (int index , int newValue ) {
223
+ if (newValue < data [index ]) {
224
+ throw new IllegalArgumentException ("Only increasing value is allowed." );
225
+ }
226
+ data [index ] = newValue ;
227
+ while (index > 0 && data [index ] > data [parent (index )]) {
228
+ int temp = data [index ];
229
+ data [index ] = data [parent (index )];
230
+ data [parent (index )] = temp ;
231
+ index = parent (index );
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Decrease the value of the specified item and adjust the heap to keep its properties.
237
+ * <p>
238
+ * The new value must be smaller than the original value, or this method would raise an error.
239
+ * This method should be called from a min heap.
240
+ *
241
+ * @param index The index of the specified item.
242
+ * @param newValue The new value of the specified item.
243
+ */
244
+ private void decreaseValue (int index , int newValue ) {
245
+ if (newValue > data [index ]) {
246
+ throw new IllegalArgumentException ("Only decreasing value is allowed." );
247
+ }
248
+ data [index ] = newValue ;
249
+ while (index > 0 && data [index ] < data [parent (index )]) {
250
+ int temp = data [index ];
251
+ data [index ] = data [parent (index )];
252
+ data [parent (index )] = temp ;
253
+ index = parent (index );
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Get the index of the parent node.
259
+ *
260
+ * @param i The index of the given node.
261
+ * @return The index of the parent node.
262
+ */
263
+ private int parent (int i ) {
264
+ return (i - 1 ) / 2 ;
265
+ }
266
+
267
+ /**
268
+ * Get the index of the left child node.
269
+ *
270
+ * @param i The index of the given node.
271
+ * @return The index of the left child node.
272
+ */
273
+ private int left (int i ) {
274
+ return 2 * i + 1 ;
275
+ }
276
+
277
+ /**
278
+ * Get the index of the right child node.
279
+ *
280
+ * @param i The index of the given node.
281
+ * @return The index of the right child node.
282
+ */
283
+ private int right (int i ) {
284
+ return 2 * (i + 1 );
285
+ }
286
+
287
+ /**
288
+ * Construct tree structure recursively.
289
+ *
290
+ * @param index The index of the subtree to be constructed.
291
+ * @return The root node of the constructed subtree.
292
+ */
293
+ private Node constructSubtree (int index ) {
294
+ if (index >= size ()) {
295
+ return null ;
296
+ }
297
+ Node root = new Node (data [index ]);
298
+ root .left = constructSubtree (left (index ));
299
+ root .right = constructSubtree (right (index ));
300
+ return root ;
301
+ }
302
+
303
+ // Flag to indicate whether this heap is a min heap or a max heap.
304
+ private final boolean isMinHeap ;
305
+
306
+ // Underlying array data.
307
+ private int [] data ;
308
+
309
+ // The number of elements in this heap.
310
+ private int size ;
311
+
312
+ // The capacity of this heap.
313
+ public int capacity ;
314
+
315
+ }
0 commit comments