-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBinaryHeap.m
More file actions
352 lines (333 loc) · 11.5 KB
/
BinaryHeap.m
File metadata and controls
352 lines (333 loc) · 11.5 KB
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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#import "BinaryHeap.h"
/* Reference links:
* https://www.linkedin.com/pulse/heap-sort-algorithm-swift-objective-c-implementations-mario
* https://en.wikipedia.org/wiki/Binary_heap
* https://github.com/mzaks/priority-queue/blob/master/ASPriorityQueue/ASPriorityQueue.m
* http://www.geeksforgeeks.org/heap-using-stl-c/
* http://www.cplusplus.com/reference/queue/priority_queue/
* http://stackoverflow.com/questions/17684170/objective-c-priority-queue
* http://www.cplusplus.com/reference/queue/priority_queue/priority_queue/
*/
#define NSPrintf(...) printf( "%s", [[NSString stringWithFormat: __VA_ARGS__] UTF8String] )
#define leftChildOf(i) ((i<<1)+1)
#define rightChildOf(i) ((i<<1)+2)
#define parentOf(i) ((i-1)>>1)
// These are generalizable for an N-ary Heap (i.e., N children for each node)
// #define firstChildOf(i) ((N*i)+1)
// #define secondChildOf(i) ((N*i)+2)
// #define nthChildOf(n,i) ((N*i)+n)
// #define parentOf(i) ((i-1)/N)
// Heapify start point: (size-1)/N
#define HeapIndexNotFound NSUIntegerMax
#define DEFAULT_COMPARITOR ^NSComparisonResult( id first, id second ) { \
return [first compare: second]; }
#define LOCAL_FIND 1
// "Private" methods
@interface BinaryHeap ()
- (void) bubbleUpFromIndex: (NSUInteger) i;
- (void) heapifyDownFromIndex: (NSInteger) parent;
#if LOCAL_FIND
- (NSUInteger) findIndexOfObject: (ObjectType) object;
- (NSUInteger) findIndexOfObject: (ObjectType) object fromIndex: (NSUInteger) idx;
#endif
- (void) removeObjectAtIndex: (NSUInteger) indexOfObject;
- (void) replaceObjectAtIndex: (NSUInteger) indexOfObject withObject: (id) newObject;
- (NSString *) descriptionFromParent: (NSUInteger) p atLevel: (int) level;
- (void) printDescriptionFromParent: (NSUInteger) p atLevel: (int) level;
@end
@implementation BinaryHeap {
NSMutableArray *_objects;
}
- (instancetype) init {
if( (self = [super init]) ) {
_objects = [NSMutableArray array];
}
return self;
}
- (instancetype) initMax {
if( (self = [super initMax]) ) {
_objects = [NSMutableArray array];
}
return self;
}
- (instancetype) initMin {
if( (self = [super initMin]) ) {
_objects = [NSMutableArray array];
}
return self;
}
- (instancetype) initWithComparator: (NSComparator) comparator {
return [self initWithComparator: comparator andCapacity: 0];
}
- (instancetype) initWithSortDescriptor: (NSSortDescriptor *) sd {
return [self initWithSortDescriptor: sd andCapacity: 0];
}
- (instancetype) initWithCapacity: (NSUInteger) numItems {
if( (self = [super init]) ) {
if( numItems > 0 )
_objects = [NSMutableArray arrayWithCapacity: numItems];
else _objects = [NSMutableArray array];
}
return self;
}
- (instancetype) initMinWithCapacity: (NSUInteger) numItems {
if( (self = [super initMin]) ) {
if( numItems > 0 )
_objects = [NSMutableArray arrayWithCapacity: numItems];
else _objects = [NSMutableArray array];
}
return self;
}
- (instancetype) initMaxWithCapacity: (NSUInteger) numItems {
if( (self = [super initMax]) ) {
if( numItems > 0 )
_objects = [NSMutableArray arrayWithCapacity: numItems];
else _objects = [NSMutableArray array];
}
return self;
}
- (instancetype) initWithComparator: (NSComparator) comparator andCapacity: (NSUInteger) numItems {
if( (self = [super initWithComparator: comparator]) ) {
if( numItems > 0 )
_objects = [NSMutableArray arrayWithCapacity: numItems];
else _objects = [NSMutableArray array];
}
return self;
}
- (instancetype) initWithSortDescriptor: (NSSortDescriptor *) sd andCapacity: (NSUInteger) numItems {
if( (self = [super initWithSortDescriptor: sd]) ) {
if( numItems > 0 )
_objects = [NSMutableArray arrayWithCapacity: numItems];
else _objects = [NSMutableArray array];
}
return self;
}
- (void) printDescription {
if( self.empty ) {
NSPrintf( @"Empty Binary Heap\n" );
} else {
NSPrintf( @"Dump of Binary Heap with %lu Nodes\n", self.size );
NSPrintf( @"%@", self );
}
}
//- description; // Formatted as a property list...?
- (NSString *) description {
return [self descriptionFromParent: 0 atLevel: 0];
}
- (NSString *) descriptionFromParent: (NSUInteger) p atLevel: (int) level {
NSMutableString *description = [NSMutableString string];
NSUInteger child = leftChildOf( p );
if( child < self.size )
[description appendString: [self descriptionFromParent: child atLevel: level + 1]];
for( int i = 0; i < level; ++i )
[description appendString: @" " ];
[description appendFormat: @"%-6@\n", _objects[p]];
child = rightChildOf( p );
if( child < self.size )
[description appendString: [self descriptionFromParent: child atLevel: level + 1]];
return description;
}
- (void) printDescriptionFromParent: (NSUInteger) p atLevel: (int) level {
NSUInteger child = leftChildOf( p );
if( child < self.size )
[self printDescriptionFromParent: child atLevel: level + 1];
for( int i = 0; i < level; ++i )
NSPrintf( @" " );
NSPrintf( @"%-6@\n", _objects[p] );
child = rightChildOf( p );
if( child < self.size )
[self printDescriptionFromParent: child atLevel: level + 1];
}
- (NSUInteger) size { return [_objects count]; }
- (NSUInteger) count { return [_objects count]; }
- (BOOL) empty { return [_objects count] == 0; }
- (ObjectType) top { return _objects.firstObject; }
- (void) push: (ObjectType) object {
if( object != nil ) {
NSUInteger i = _objects.count;
// Make sure there is room? If not throw NSRangeException?
_objects[i] = object;
[self bubbleUpFromIndex: i];
}
}
- (void) bubbleUpFromIndex: (NSUInteger) i {
NSUInteger p = parentOf(i);
// Bubble-up
while( i > 0 && [self heapCompareNode: _objects[i] toNode: _objects[p]] == NSOrderedDescending) {
ObjectType t = _objects[p];
_objects[p] = _objects[i];
_objects[i] = t;
i = p;
p = parentOf(i);
}
}
- (ObjectType) pop {
ObjectType top = _objects.firstObject;
if( _objects.count > 0 ) {
_objects[0] = _objects.lastObject;
[_objects removeLastObject];
[self heapifyDownFromIndex: 0];
}
return top;
}
- (ObjectType) topObject { return self.top; }
- (NSArray *) allObjects { return [NSArray arrayWithArray: _objects]; }
- (void) addObject: (ObjectType) object { [self push: object]; }
- (void) addObjectsFromArray: (NSArray *) array {
// This might be faster with Floyd's algorithm, or might not
// it may depend on how big the array is to start with???
for( ObjectType o in array ) {
[self push: o ];
}
}
- (void) removeAllObjects { [_objects removeAllObjects]; }
- (void) removeTopObject { [self pop]; }
- (void) replaceTopObjectWithObject: (id) object {
if( object != nil ) {
_objects[0] = object;
[self heapifyDownFromIndex: 0];
} else [self pop];
}
- (BOOL) containsObject: (ObjectType) object {
#if LOCAL_FIND
return( [self findIndexOfObject: object] != HeapIndexNotFound );
#else
return [_objects containsObject: object];
#endif
}
#if LOCAL_FIND
- (NSUInteger) findIndexOfObject: (ObjectType) object {
return [self findIndexOfObject: object fromIndex: 0];
}
- (NSUInteger) findIndexOfObject: (ObjectType) object fromIndex: (NSUInteger) idx {
NSUInteger indexOfObject;
if( !object || idx >= _objects.count ||
[self heapCompareNode: _objects[idx] toNode: object] == NSOrderedAscending ) {
indexOfObject = HeapIndexNotFound;
} else if( [object isEqual: _objects[idx]] ) {
indexOfObject = idx;
} else if( (indexOfObject = [self findIndexOfObject: object fromIndex: leftChildOf(idx)]) == HeapIndexNotFound ) {
indexOfObject = [self findIndexOfObject: object fromIndex: rightChildOf(idx)];
}
return indexOfObject;
}
#endif
// Find the node with the object and delete it...
- (void) removeObject: (id) object {
NSUInteger indexOfObject = [self findIndexOfObject: object];
[self removeObjectAtIndex: indexOfObject];
}
- (void) removeObjectAtIndex: (NSUInteger) indexOfObject {
if( indexOfObject != HeapIndexNotFound && _objects.count > 0 ) {
_objects[indexOfObject] = _objects.lastObject;
[_objects removeLastObject];
[self heapifyDownFromIndex: indexOfObject];
}
}
- (void) replaceObject: (id) object withObject: (id) newObject {
NSUInteger indexOfObject = [self findIndexOfObject: object];
[self replaceObjectAtIndex: indexOfObject withObject: newObject];
}
- (void) replaceObjectAtIndex: (NSUInteger) indexOfObject withObject: (id) newObject {
if( indexOfObject == HeapIndexNotFound || _objects.count <= 0 ) {
// If the object does not exist, then just add it to the heap
// This is most consistent with the default implementation remove;push;
[self push: newObject];
// This was the older, unfriendly way...
//[NSException raise: NSInvalidArgumentException
// format: @"Object is not in the heap."];
} else if( !newObject ) {
[self removeObjectAtIndex: indexOfObject];
} else if( [self heapCompareNode: newObject toNode: _objects[indexOfObject]] == NSOrderedAscending ) {
_objects[indexOfObject] = newObject;
[self heapifyDownFromIndex: indexOfObject];
//[NSException raise: NSInvalidArgumentException
// format: @"New object is not 'better' than old object."];
} else {
_objects[indexOfObject] = newObject;
[self bubbleUpFromIndex: indexOfObject];
}
}
- (void) setObjectsFromArray: (NSArray *) array {
_objects = [NSMutableArray arrayWithArray: array];
// I should verify that _objects.count is <= NSMAXINTEGER since
// I cast it to a NSInteger on this call...
if( _objects.count > 1 ) {
for( NSInteger i = parentOf((NSInteger)_objects.count - 1); i >= 0; --i ) {
[self heapifyDownFromIndex: i];
}
}
}
- (BOOL) isEqualToHeap: (Heap *) heap {
// Call the super's isEqualToHeap...
if( ![super isEqualToHeap: heap] )
return NO;
// If any of the objects in self are not in heap then they are not equal
for( NSUInteger i = 0; i < _objects.count; ++i ) {
if( ![heap containsObject: _objects[i]] )
return NO;
}
return YES;
}
- (void) filterUsingPredicate: (NSPredicate *) predicate {
[_objects filterUsingPredicate: predicate];
for( NSInteger i = parentOf(_objects.count - 1); i >= 0; --i ) {
[self heapifyDownFromIndex: i];
}
}
// ------- //// Internal / Private Methods //// ------ //
- (void) setObjectsFromObject: (id) firstObj andArgs: (va_list) args {
if( !firstObj ) {
_objects = [NSMutableArray array];
} else {
id arg = nil;
// Should I count the args first?
_objects = [NSMutableArray arrayWithObject: firstObj];
while( (arg = va_arg( args, id )) ) {
[_objects addObject: arg];
}
for( NSInteger i = parentOf((NSInteger)_objects.count - 1); i >= 0; --i ) {
[self heapifyDownFromIndex: i];
}
}
}
- (void) heapifyDownFromIndex: (NSInteger) p {
NSInteger l, r;
NSInteger largest;
NSUInteger size = _objects.count;
//NSLog( @"Entering heapifyDown for parent %ld for _objects of size %lu\n", p, size );
if( size > 0 && p < size && p >= 0 ) {
// Bubble down
for( ; ; ) {
// Compare root with children...
largest = p;
// This would work for N-ary tree with k looped to N
//for( int k = 1; k <= 2; ++k ) {
// l = ((p)<< 1) + k;
// if( l < size &&
// [self heapCompareNode: _objects[l] toNode: _objects[largest]] == NSOrderedDescending ) {
// largest = l;
// }
//}
l = leftChildOf(p);
r = rightChildOf(p);
if( l < size && l >= 0 &&
[self heapCompareNode: _objects[l] toNode: _objects[largest]] == NSOrderedDescending )
largest = l;
if( r < size && r >= 0 &&
[self heapCompareNode: _objects[r] toNode: _objects[largest]] == NSOrderedDescending )
largest = r;
// If in correct order, we are done
if( largest == p ) {
break;
} else { /* largest != p */
// If not swap and move down
ObjectType t = _objects[p];
_objects[p] = _objects[largest];
_objects[largest] = t;
p = largest;
}
}
}
}
@end