Skip to content

Add Heap #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/algorithms/sorting/merge-sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ function merge(left: Array<number>, right: Array<number>, order: SortingOrder):
/**
* Sort the array of numbers in either ascending or descending order, applying the merge sort algorithm.
*
* - Time complexity: O(N log(N)) where N is the size of the array.
* - Time complexity: O(N log(N))
* - Space complexity: O(N)
*
* where N is the size of the array.
*
* @param input the array of numbers to sort.
* @param order specify the order of sorting: ascending or descending.
Expand Down
65 changes: 65 additions & 0 deletions src/collections/Heap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import Collection from 'src/collections/Collection';
import Comparable from 'src/util/Comparable';

/**
* A heap is a binary tree that satisfies two properties:
* 1) Completeness: Every level of the tree (except last) is completely filled.
* All holes in the last level are all the way to the right.
* 2) Heap Order Invariant: Every element in the tree is <= (or >=) its parent
* depending if it's a max heap or a min heap.
*
* The items stored in this data structure must be comparable. For this reason,
* it only accepts types that extends the "Comparable" interface.
*/
export default interface Heap<T extends Comparable<T>> extends Collection<T> {
/**
* Adds a new element to the heap.
*
* @param element the comparable element to add.
* @complexity time: O(log n)
*/
add(element: T): void;

/**
* Removes the root element and returns it.
* The root element can be the maximum one if it's a max heap,
* or the minimum one if it's a min heap.
*
* @returns the maximum element if a max heap, or the minimum if a min heap.
* @complexity time: O(log n)
*/
poll(): T;

/**
* Returns the root element without removing it.
* The root element can be the maximum one if it's a max heap,
* or the minimum one if it's a min heap.
*
* @returns the maximum element if a max heap, or the minimum if a min heap.
* @complexity time: O(1)
*/
peek(); T;

/**
* Returns the heap in array form.
*/
toArray(): Array<T>;
}

// class Person implements Comparable<Person>{
// private name;

// constructor(name: string) {
// this.name = name;
// }

// getName() {
// return this.name;
// }

// compare(person: Person): Comparison {
// if (this.getName() === person.getName()) return Comparison.Equal;

// return Comparison.LessThan;
// }
// }
115 changes: 115 additions & 0 deletions src/collections/HeapArray.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import Heap from 'src/collections/Heap';
import Comparable, { Comparison } from 'src/util/Comparable';

enum HeapType {
MaxHeap = 0,
MinHeap = 1
}

enum Operand { Left, Right };
enum HeapType { Max, Min };

/**
* Returns the right operand if:
* - It's a Max Heap and the right operand is strictly greater than the left one
* - It's a Min Heap and the right operand is strictly less than the left one
*
* Returns the left operand otherwise.
*
* @param left the left operand
* @param right the right operand
* @param heapType the type of heap (Max or Min)
*/
function whoWins(left: number, right: number, heapType: HeapType): Operand {
if (heapType === HeapType.Max && right > left || heapType === HeapType.Min && right < left) {
return Operand.Right;
} else {
return Operand.Left;
}
}
export default class HeapArray<T extends Comparable<T>> implements Heap<T> {

private heap: Array<T>;
private type: HeapType;

constructor(input: Array<T> = [], type: HeapType = HeapType.MaxHeap) {
this.heap = input;
this.type = type;
const current = Math.floor(this.heap.length / 2);
this.buildHeap(current);
}

private buildHeap(current: number): void {
for (let index = current; index >= 0; index--) {
this.bubbleDown(index);
}
}

private bubbleDown(current: number): void {
// if it is a leaf, exit
if (this.isLeaf(current)) return;
// if it is greater than or equal to the greatest of its children, exit
const leftChild = this.getLeftChild(current);
const rightChild = this.getRightChild(current);
const maxChild = this.getMax(leftChild, rightChild);
if (this.heap[current] >= this.heap[maxChild]) return;

this.swap(current, maxChild);
this.bubbleDown(maxChild);
}

private test() {
const left = this.heap[leftChild];
const right = this.heap[rightChild];
const operand = whoWins(left, right);
if (operand === Operand.Left)
}

private getMax(indexOne: number, indexTwo: number): number {
let one = this.heap[indexOne];
let two = this.heap[indexTwo];
if (one === undefined) return indexTwo;
if (two === undefined) return indexOne;
if (two > one) return indexTwo;
return indexOne;
}

private swap(indexOne: number, indexTwo: number): void {
const temp = this.heap[indexOne];
this.heap[indexOne] = this.heap[indexTwo];
this.heap[indexTwo] = temp;
}

private getParent(index: number): number {
return Math.floor((index - 1) / 2);
}

private getLeftChild(index: number): number {
return index * 2 + 1;
}

private getRightChild(index: number): number {
return index * 2 + 2;
}

private isRoot(index: number): boolean {
return index === 0;
}

private isLeaf(index: number): boolean {
// all elements in the second half of the array are leaves
return index >= Math.floor(this.heap.length / 2);
}

public add(element: T): void {

}

public poll(): T {
throw new Error('');
}

public peek(); T {
throw new Error('');
}
}
6 changes: 3 additions & 3 deletions src/collections/PriorityQueueArray.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import QueueArray from './QueueArray.js';
import QueueArray from 'src/collections/QueueArray';

export default class PriorityQueueArray extends QueueArray<number> {

Expand All @@ -12,8 +12,8 @@ export default class PriorityQueueArray extends QueueArray<number> {
} else {
let added = false;
for (let i = 0; i < super.size(); i++) {
if (item <= super.queue[i]) {
super.queue.splice(i, 0, item);
if (item <= this.queue[i]) {
this.queue.splice(i, 0, item);
added = true;
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/collections/Queue.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Collection from './Collection';
import Collection from 'src/collections/Collection';

/**
* The {@code Queue} interface represents a first-in-first-out
Expand Down
2 changes: 1 addition & 1 deletion src/collections/Stack.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Collection from './Collection';
import Collection from 'src/collections/Collection';

/**
* The {@code Stack} interface represents a last-in-first-out
Expand Down
3 changes: 3 additions & 0 deletions src/collections/StackArray.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import Stack from 'src/collections/Stack';

/**
* This class implements the Stack interface using the JavaScript dynamic array.
*/
export default class StackArray<T> implements Stack<T> {

private stack: Array<T>;
Expand Down
102 changes: 102 additions & 0 deletions src/heapWithNumbers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
class Heap {

private heap: Array<number>;

constructor(input: Array<number> = []) {
this.heap = input;
const current = Math.floor(this.heap.length / 2);
this.buildHeap(current);
}

private buildHeap(current: number): void {
for (let index = current; index >= 0; index--) {
this.bubbleDown(index);
}
}

private bubbleDown(current: number): void {
// If the current node is a leaf, exit
if (this.isLeaf(current)) return;
// Get the max child
const maxChild = this.getMax(this.getLeftChild(current), this.getRightChild(current));
// If the current node is smaller than the max child
if (this.heap[current] < this.heap[maxChild]) {
// swap positio between the current node and its child
this.swap(current, maxChild);
// recursively call this function
this.bubbleDown(maxChild);
}
}

private bubbleUp(current: number): void {
// if it is root, exit
if (this.isRoot(current)) return;
// if it is not strictly greater than its parent, exit
const parent = this.getParent(current);
if (this.heap[current] <= this.heap[parent]) return;

this.swap(current, parent);
this.bubbleUp(parent);
}

private getParent(index: number): number {
return Math.floor((index - 1) / 2);
}

private getLeftChild(index: number): number {
return index * 2 + 1;
}

private getRightChild(index: number): number {
return index * 2 + 2;
}

private isRoot(index: number): boolean {
return index === 0;
}

private isLeaf(index: number): boolean {
const leftChild = this.getLeftChild(index);
const rightChild = this.getRightChild(index);
const N = this.heap.length;
return leftChild >= N && rightChild >= N;
}

private getMax(indexOne: number, indexTwo: number): number {
let one = this.heap[indexOne];
let two = this.heap[indexTwo];

if (one === undefined) return indexTwo;
if (two === undefined) return indexOne;

if (two > one) return indexTwo;

return indexOne;
}

private swap(indexOne: number, indexTwo: number): void {
const temp = this.heap[indexOne];
this.heap[indexOne] = this.heap[indexTwo];
this.heap[indexTwo] = temp;
}
}


const h = new Heap([2, 4, 7, 1, 5, 3]);
// const h = new Heap();
// h.add(2).add(4).add(7).add(1).add(5).add(3);
console.log(h.toArray());
console.log(h.getRoot());
console.log(h.toArray());
console.log(h.getRoot());
console.log(h.toArray());
console.log(h.getRoot());
console.log(h.toArray());
console.log(h.getRoot());
console.log(h.toArray());
console.log(h.getRoot());
console.log(h.toArray());
console.log(h.getRoot());
console.log(h.toArray());
console.log(h.getRoot());
console.log(h.toArray());
48 changes: 36 additions & 12 deletions src/util/Comparable.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
/**
* An enumeration that represents the result
* of the comparison.
* A comparable object.
*/
export enum Comparison {
EqualTo = 1,
LessThan = 2,
GreaterThan = 4,
LessThanOrEqualTo = 3,
GreaterThanOrEqualTo = 5
export default interface Comparable<T> {
compare(item: T): ComparisonOperator;
}

/**
* A class that implements this interface must define
* a way to compare its objects.
* An enumeration that represents the comparison operator:
* - EqualTo: "="
* - LessThan: "<" (strictly less than)
* - GreaterThan: ">" (strictly greater than)
*/
export default interface Comparable<T> {
compare(element: T): Comparison;
export enum ComparisonOperator { EqualTo, LessThan, GreaterThan };

/**
*
*/
export enum ComparisonType { Max, Min };

/**
* An enumeration that represents the left and right operands of a comparison.
*/
export enum Operand { Left, Right };

/**
* Tells which operand wins based on the comparison type (i.e. max or min).
* @param leftOperand
* @param rightOperand
* @param comparisonType
*/
export function whoWins<T extends Comparable<T>>(leftOperand: T, rightOperand: T, comparisonType: ComparisonType): Operand {
const comparison = rightOperand.compare(leftOperand);

if (
comparisonType === ComparisonType.Max && comparison === ComparisonOperator.GreaterThan ||
comparisonType === ComparisonType.Min && comparison === ComparisonOperator.LessThan
) {
return Operand.Right;
}

return Operand.Left;
}