Skip to content
Merged
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
7 changes: 7 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/sh
# Automatically bump patch version before each commit

npm version patch --no-git-tag-version > /dev/null

# stage version files
git add package.json package-lock.json
2 changes: 1 addition & 1 deletion DEVELOPMENT_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ This document outlines possible improvements and future developments for the `TS
## New Data Structures

- **Graph**: Implement a basic graph structure with common algorithms such as BFS, DFS, and shortest path algorithms.
- **PriorityQueue**: Provide a priority queue implementation for efficient task scheduling.
- **PriorityQueue**: Provide a priority queue implementation for efficient task scheduling. *(Implemented)*
- **Balanced Trees**: Add self-balancing tree variants (e.g., AVL or Red-Black trees) for more efficient search and insert operations.

## Documentation
Expand Down
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,44 @@ queue.size(); // 2

```

## PriorityQueue<T>

#### push(value: T, priority: number)

Insert an element into the queue with an associated priority.

#### pop(): T | null

Removes and returns the element with the highest priority, or `null` if the queue is empty.

#### peek(): T | null

Returns the element with the highest priority without removing it, or `null` if the queue is empty.

#### size(): number

Returns the number of elements in the queue.

#### isEmpty(): boolean

Returns `true` if the queue has no elements, otherwise `false`.

#### toArray(): T[]

Returns an array of the values in priority order.

```typescript

const pq = new PriorityQueue<number>();
pq.push(5, 5);
pq.push(1, 1);
pq.push(3, 3);
pq.pop(); // 1
pq.peek(); // 3
pq.size(); // 2

```

## BinaryTree<T>

#### getRoot(): BinaryTreeNode<T>
Expand Down Expand Up @@ -422,3 +460,13 @@ Traverse the tree in breadth-first order and apply the given callback function t


If you have an advice, please feel free to contact with me

## Git Hooks

This project uses a pre-commit hook stored in `.githooks/pre-commit` to
automatically bump the package patch version each time you commit. Enable the
hooks with the following command:

```bash
git config core.hooksPath .githooks
```
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "datastructure-ts",
"version": "0.1.20",
"version": "0.1.21",
"description": "Collection of data structures(LinkedList, DoubleLinkedList, Stack, Queue, Dictionary and etc...) for TypeScript.",
"scripts": {
"build": "tsc",
Expand Down
93 changes: 93 additions & 0 deletions src/PriorityQueue/PriorityQueue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
export interface PriorityQueueItem<T> {
value: T;
priority: number;
}

export class PriorityQueue<T> {
private heap: PriorityQueueItem<T>[] = [];

constructor(private compare: (a: number, b: number) => boolean = (a, b) => a < b) {}

push(value: T, priority: number): void {
this.heap.push({ value, priority });
this.bubbleUp(this.heap.length - 1);
}

pop(): T | null {
if (this.isEmpty()) {
return null;
}
const top = this.heap[0].value;
const end = this.heap.pop()!;
if (!this.isEmpty()) {
this.heap[0] = end;
this.bubbleDown(0);
}
return top;
}

peek(): T | null {
return this.isEmpty() ? null : this.heap[0].value;
}

size(): number {
return this.heap.length;
}

isEmpty(): boolean {
return this.heap.length === 0;
}

toArray(): T[] {
return this.heap.map(item => item.value);
}

private bubbleUp(index: number): void {
const element = this.heap[index];
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
const parent = this.heap[parentIndex];
if (this.compare(element.priority, parent.priority)) {
this.heap[parentIndex] = element;
this.heap[index] = parent;
index = parentIndex;
} else {
break;
}
}
}

private bubbleDown(index: number): void {
const length = this.heap.length;
const element = this.heap[index];
while (true) {
const leftChildIdx = 2 * index + 1;
const rightChildIdx = 2 * index + 2;
let swapIdx: number | null = null;

if (leftChildIdx < length) {
const left = this.heap[leftChildIdx];
if (this.compare(left.priority, element.priority)) {
swapIdx = leftChildIdx;
}
}

if (rightChildIdx < length) {
const right = this.heap[rightChildIdx];
if (
(swapIdx === null && this.compare(right.priority, element.priority)) ||
(swapIdx !== null && this.compare(right.priority, this.heap[swapIdx].priority))
) {
swapIdx = rightChildIdx;
}
}

if (swapIdx === null) {
break;
}
this.heap[index] = this.heap[swapIdx];
this.heap[swapIdx] = element;
index = swapIdx;
}
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export * from './Nodes/DoubleLinkedNode';
export * from './Nodes/LinkedNode';
export * from './Stack/Stack';
export * from './Queue/Queue';
export * from './PriorityQueue/PriorityQueue';
export * from './Nodes/BinaryTreeNode';
export * from './BinaryTree/BinaryTree';
34 changes: 34 additions & 0 deletions tests/PriorityQueue/PriorityQueue.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { PriorityQueue } from '../../src/PriorityQueue/PriorityQueue';
import { expect } from 'chai';

describe('PriorityQueue', () => {
let queue: PriorityQueue<string>;

beforeEach(() => {
queue = new PriorityQueue<string>();
});

it('push/pop works according to priority', () => {
queue.push('low', 5);
queue.push('high', 1);
queue.push('medium', 3);

expect(queue.pop()).equal('high');
expect(queue.pop()).equal('medium');
expect(queue.pop()).equal('low');
});

it('peek returns highest priority', () => {
queue.push('a', 2);
queue.push('b', 1);

expect(queue.peek()).equal('b');
expect(queue.size()).equal(2);
});

it('handles empty queue', () => {
expect(queue.pop()).equal(null);
expect(queue.peek()).equal(null);
expect(queue.size()).equal(0);
});
});