-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ARSN-298: add Min/Max heap data structure
- Loading branch information
1 parent
c1dd2e4
commit 054f61d
Showing
3 changed files
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
export enum HeapOrder { | ||
Min = -1, | ||
Max = 1, | ||
} | ||
|
||
export enum CompareResult { | ||
LT = -1, | ||
EQ = 0, | ||
GT = 1, | ||
} | ||
|
||
export type CompareFunction = (x: any, y: any) => CompareResult; | ||
|
||
export class Heap { | ||
size: number; | ||
_maxSize: number; | ||
_order: HeapOrder; | ||
_heap: any[]; | ||
_cmpFn: CompareFunction; | ||
|
||
constructor(size: number, order: HeapOrder, cmpFn: CompareFunction) { | ||
this.size = 0; | ||
this._maxSize = size; | ||
this._order = order; | ||
this._cmpFn = cmpFn; | ||
this._heap = new Array<any>(this._maxSize); | ||
} | ||
|
||
_parent(i: number): number { | ||
return Math.floor((i - 1) / 2); | ||
} | ||
|
||
_left(i: number): number { | ||
return Math.floor((2 * i) + 1); | ||
} | ||
|
||
_right(i: number): number { | ||
return Math.floor((2 * i) + 2); | ||
} | ||
|
||
_shouldSwap(childIdx: number, parentIdx: number): boolean { | ||
return this._cmpFn(this._heap[childIdx], this._heap[parentIdx]) as number === this._order as number; | ||
} | ||
|
||
_swap(i: number, j: number) { | ||
const tmp = this._heap[i]; | ||
this._heap[i] = this._heap[j]; | ||
this._heap[j] = tmp; | ||
} | ||
|
||
_heapify(i: number) { | ||
const l = this._left(i); | ||
const r = this._right(i); | ||
let c = i; | ||
|
||
if (l < this.size && this._shouldSwap(l, c)) { | ||
c = l; | ||
} | ||
|
||
if (r < this.size && this._shouldSwap(r, c)) { | ||
c = r; | ||
} | ||
|
||
if (c != i) { | ||
this._swap(c, i); | ||
this._heapify(c); | ||
} | ||
} | ||
|
||
add(item: any): any { | ||
if (this.size >= this._maxSize) { | ||
return new Error('Max heap size reached'); | ||
} | ||
|
||
++this.size; | ||
let c = this.size - 1; | ||
this._heap[c] = item; | ||
|
||
while (c > 0) { | ||
if (!this._shouldSwap(c, this._parent(c))) { | ||
return null; | ||
} | ||
|
||
this._swap(c, this._parent(c)); | ||
c = this._parent(c); | ||
} | ||
|
||
return null; | ||
}; | ||
|
||
remove(): any { | ||
if (this.size <= 0) { | ||
return null; | ||
} | ||
|
||
const ret = this._heap[0]; | ||
this._heap[0] = this._heap[this.size - 1]; | ||
this._heapify(0); | ||
--this.size; | ||
|
||
return ret; | ||
}; | ||
|
||
peek(): any { | ||
if (this.size <= 0) { | ||
return null; | ||
} | ||
|
||
return this._heap[0]; | ||
}; | ||
} | ||
|
||
export class MinHeap extends Heap { | ||
constructor(size: number, cmpFn: CompareFunction) { | ||
super(size, HeapOrder.Min, cmpFn); | ||
} | ||
} | ||
|
||
export class MaxHeap extends Heap { | ||
constructor(size: number, cmpFn: CompareFunction) { | ||
super(size, HeapOrder.Max, cmpFn); | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
'use strict' | ||
|
||
import * as Heap from '../../../../lib/algos/heap/Heap'; | ||
|
||
function numberCompare(x: any, y: any): Heap.CompareResult { | ||
if (x > y) { | ||
return Heap.CompareResult.GT; | ||
} | ||
|
||
if (x < y) { | ||
return Heap.CompareResult.LT; | ||
} | ||
|
||
return Heap.CompareResult.EQ; | ||
} | ||
|
||
describe('Heap', () => { | ||
describe('Heap::add', () => { | ||
it('should set max heap size and return error if max size is reached', () => { | ||
const heap = new Heap.Heap(1, Heap.HeapOrder.Min, numberCompare); | ||
expect(heap.add(1)).toBeNull(); | ||
expect(heap.add(2)).not.toBeNull(); | ||
}); | ||
}); | ||
|
||
describe('Heap::remove', () => { | ||
it('should return null if heap is empty', () => { | ||
const heap = new Heap.Heap(1, Heap.HeapOrder.Min, numberCompare); | ||
expect(heap.remove()).toBeNull(); | ||
}); | ||
}); | ||
|
||
describe('Heap::peek', () => { | ||
it('should return null if heap is empty', () => { | ||
const heap = new Heap.Heap(1, Heap.HeapOrder.Min, numberCompare); | ||
expect(heap.peek()).toBeNull(); | ||
}); | ||
}); | ||
}); | ||
|
||
describe('MinHeap', () => { | ||
it('should maintain min heap properties', () => { | ||
const minHeap = new Heap.MinHeap(5, numberCompare); | ||
expect(minHeap.add(5)).toBeNull(); | ||
expect(minHeap.add(3)).toBeNull(); | ||
expect(minHeap.add(2)).toBeNull(); | ||
expect(minHeap.add(4)).toBeNull(); | ||
expect(minHeap.add(1)).toBeNull(); | ||
expect(minHeap.size).toEqual(5); | ||
expect(minHeap.remove()).toEqual(1); | ||
expect(minHeap.remove()).toEqual(2); | ||
expect(minHeap.remove()).toEqual(3); | ||
expect(minHeap.remove()).toEqual(4); | ||
expect(minHeap.remove()).toEqual(5); | ||
expect(minHeap.size).toEqual(0); | ||
}); | ||
}); | ||
|
||
describe('MaxHeap', () => { | ||
it('should maintain max heap properties', () => { | ||
const maxHeap = new Heap.MaxHeap(5, numberCompare); | ||
expect(maxHeap.add(5)).toBeNull(); | ||
expect(maxHeap.add(3)).toBeNull(); | ||
expect(maxHeap.add(2)).toBeNull(); | ||
expect(maxHeap.add(4)).toBeNull(); | ||
expect(maxHeap.add(1)).toBeNull(); | ||
expect(maxHeap.size).toEqual(5); | ||
expect(maxHeap.remove()).toEqual(5); | ||
expect(maxHeap.remove()).toEqual(4); | ||
expect(maxHeap.remove()).toEqual(3); | ||
expect(maxHeap.remove()).toEqual(2); | ||
expect(maxHeap.remove()).toEqual(1); | ||
expect(maxHeap.size).toEqual(0); | ||
}); | ||
}); |