diff --git a/data_structures/heap/heap.ts b/data_structures/heap/heap.ts index 71f03be3..a5def710 100644 --- a/data_structures/heap/heap.ts +++ b/data_structures/heap/heap.ts @@ -1,8 +1,24 @@ +/** + * A heap is a complete binary tree + * In a complete binary tree each level is filled before lower levels are added + * Each level is filled from left to right + * + * In a (min|max) heap the value of every node is (less|greater) than that if its children + * + * The heap if often implemented using an array structure. + * In the array implementation, the relationship between a parent index and its two children + * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) + * + */ + export abstract class Heap { - protected heap: T[]; + private heap: T[]; + // A comparison function. Returns true if a should be the parent of b. + private compare: (a: any, b: any) => boolean; - constructor(elements: T[] = []) { + constructor(elements: T[] = [], compare: (a: T, b: T) => boolean) { this.heap = []; + this.compare = compare; for (let element of elements) { this.insert(element); } @@ -14,19 +30,22 @@ export abstract class Heap { * In a minHeap the value at parentIndex should be smaller than the value at childIndex * */ - protected abstract isRightlyPlaced( - childIndex: number, - parentIndex: number - ): boolean; + private isRightlyPlaced( childIndex: number, parentIndex: number) { + return this.compare(this.heap[parentIndex], this.heap[childIndex]); + } /** * In a maxHeap the index with the larger value is returned * In a minHeap the index with the smaller value is returned */ - protected abstract getChildIndexToSwap( - leftChildIndex: number, - rightChildIndex: number - ): number; + private getChildIndexToSwap(leftChildIndex: number, rightChildIndex: number): number { + if (rightChildIndex >= this.size()) { + return leftChildIndex; + } + return this.compare(this.heap[leftChildIndex], this.heap[rightChildIndex]) + ? leftChildIndex + : rightChildIndex; + } public insert(value: T): void { this.heap.push(value); @@ -49,7 +68,7 @@ export abstract class Heap { return this.size() === 0; } - protected bubbleUp(): void { + private bubbleUp(): void { let index = this.size() - 1; let parentIndex; @@ -64,7 +83,7 @@ export abstract class Heap { } } - protected sinkDown(): void { + private sinkDown(): void { let index = 0; let leftChildIndex = this.getLeftChildIndex(index); let rightChildIndex = this.getRightChildIndex(index); @@ -86,11 +105,11 @@ export abstract class Heap { } } - protected getLeftChildIndex(index: number): number { + private getLeftChildIndex(index: number): number { return index * 2 + 1; } - protected getRightChildIndex(index: number): number { + private getRightChildIndex(index: number): number { return index * 2 + 2; } @@ -98,7 +117,7 @@ export abstract class Heap { return this._check(); } - protected _check(index: number = 0): void { + private _check(index: number = 0): void { if (!this.heap[index]) return; const leftChildIndex = this.getLeftChildIndex(index); const rightChildIndex = this.getRightChildIndex(index); @@ -119,3 +138,15 @@ export abstract class Heap { this._check(rightChildIndex); } } + +export class MinHeap extends Heap { + constructor(elements: T[] = [], compare = (a: T, b: T) => { return a < b }) { + super(elements, compare); + } +} + +export class MaxHeap extends Heap { + constructor(elements: T[] = [], compare = (a: T, b: T) => { return a > b }) { + super(elements, compare); + } +} diff --git a/data_structures/heap/max_heap.ts b/data_structures/heap/max_heap.ts deleted file mode 100644 index 34f2068f..00000000 --- a/data_structures/heap/max_heap.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Heap } from "./heap"; - -/** - * A heap is a complete binary tree - * In a complete binary tree each level is filled before lower levels are added - * Each level is filled from left to right - * - * In a max heap the value of every node is greater than that if its children - * - * The heap if often implemented using an array structure. - * In the array implementation, the relationship between a parent index and its two children - * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) - * - */ -export class MaxHeap extends Heap { - constructor(elements: T[] = []) { - super(elements); - } - - /** - * Checks if the value at the parent index is larger than or equal to - * the value at the child index - */ - protected isRightlyPlaced(childIndex: number, parentIndex: number): boolean { - return this.heap[parentIndex] >= this.heap[childIndex]; - } - - /** - * Returns the child index that stores a larger value - */ - protected getChildIndexToSwap( - leftChildIndex: number, - rightChildIndex: number - ): number { - return this.heap[leftChildIndex] > - (this.heap[rightChildIndex] || -Infinity) - ? leftChildIndex - : rightChildIndex; - } -} diff --git a/data_structures/heap/min_heap.ts b/data_structures/heap/min_heap.ts deleted file mode 100644 index ec71572a..00000000 --- a/data_structures/heap/min_heap.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Heap } from "./heap"; - -/** - * A heap is a complete binary tree - * In a complete binary tree each level is filled before lower levels are added - * Each level is filled from left to right - * - * In a min heap the value of every node is smaller than that if its children - * - * The heap if often implemented using an array structure. - * In the array implementation, the relationship between a parent index and its two children - * are ((parentindex * 2) + 1) and ((parentindex * 2) + 2) - * - */ -export class MinHeap extends Heap { - constructor(elements: T[] = []) { - super(elements); - } - - /** - * Checks if the value at the parent index is lesser than or equal to - * the value at the child index - */ - protected isRightlyPlaced(childIndex: number, parentIndex: number): boolean { - return this.heap[parentIndex] <= this.heap[childIndex]; - } - - /** - * Returns the child index that stores a smaller value - */ - protected getChildIndexToSwap( - leftChildIndex: number, - rightChildIndex: number - ): number { - return this.heap[leftChildIndex] < - (this.heap[rightChildIndex] || Infinity) - ? leftChildIndex - : rightChildIndex; - } -} diff --git a/data_structures/heap/test/max_heap.test.ts b/data_structures/heap/test/max_heap.test.ts index 9a251de9..8ba7c398 100644 --- a/data_structures/heap/test/max_heap.test.ts +++ b/data_structures/heap/test/max_heap.test.ts @@ -1,4 +1,4 @@ -import { MaxHeap } from "../max_heap"; +import { MaxHeap } from "../heap"; describe("MaxHeap", () => { let heap: MaxHeap; diff --git a/data_structures/heap/test/min_heap.test.ts b/data_structures/heap/test/min_heap.test.ts index 07f10b1e..4401d5c0 100644 --- a/data_structures/heap/test/min_heap.test.ts +++ b/data_structures/heap/test/min_heap.test.ts @@ -1,4 +1,4 @@ -import { MinHeap } from "../min_heap"; +import { MinHeap } from "../heap"; describe("MinHeap", () => { let heap: MinHeap;