Skip to content

feat(structure): implements circular queue #116

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

Merged
merged 2 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
112 changes: 112 additions & 0 deletions data_structures/queue/circular_queue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Queue } from "./queue";

/**
* Circular Queue implementation using array.
*
* @template T The type of the elements in the queue.
* @implements {Queue<T>}
* @param {T[]} queue The array that holds the elements of the queue.
* @param {number} frontIndex The index of the front element of the queue.
* @param {number} rearIndex The index of the rear element of the queue.
* @param {number} size The size of the queue.
*/
export class CircularQueue<T> implements Queue<T> {
private queue: T[];
private frontIndex: number;
private rearIndex: number;
private size: number;

constructor(size: number) {
this.queue = new Array(size);
this.frontIndex = -1;
this.rearIndex = -1;
this.size = size;
}

/**
* Adds an item to the queue.
*
* @param item The item being added to the queue.
*/
enqueue(item: T): void {
if (
(this.frontIndex == 0 && this.rearIndex == this.size - 1) ||
this.rearIndex == (this.frontIndex - 1) % (this.size - 1)
) {
throw new Error("Queue is full");
} else if (this.frontIndex == -1) {
this.frontIndex = 0;
this.rearIndex = 0;
this.queue[this.rearIndex] = item;
} else if (this.rearIndex == this.size - 1 && this.frontIndex != 0) {
this.rearIndex = 0;
this.queue[this.rearIndex] = item;
} else {
this.rearIndex++;
this.queue[this.rearIndex] = item;
}
}

/**
* Removes an item from the queue and returns it.
*
* @throws Queue Underflow if the queue is empty.
* @returns The item that was removed from the queue.
*/
dequeue(): T | undefined {
if (this.frontIndex == -1) {
throw new Error("Queue is empty");
}

const item = this.queue[this.frontIndex];
if (this.frontIndex == this.rearIndex) {
this.frontIndex = -1;
this.rearIndex = -1;
} else if (this.frontIndex == this.size - 1) {
this.frontIndex = 0;
} else {
this.frontIndex++;
}

return item;
}

/**
* Returns the item at the front of the queue.
*
* @returns The item at the front of the queue or null if the queue is empty.
*/
peek(): T | null | undefined {
if (this.frontIndex == -1) {
return null;
}

return this.queue[this.frontIndex];
}

/**
* Checks if the queue is empty.
*
* @returns {boolean} Whether the queue is empty or not.
*/
isEmpty(): boolean {
return this.frontIndex == -1;
}

/**
* Returns the number of items in the queue.
*
* @returns {number} The number of items in the queue.
*/
length(): number {
if (this.frontIndex == -1) {
return 0;
}

if (this.rearIndex >= this.frontIndex) {
return this.rearIndex - this.frontIndex + 1;
}

return this.size - (this.frontIndex - this.rearIndex - 1);
}
}
65 changes: 65 additions & 0 deletions data_structures/queue/test/circular_queue.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { CircularQueue } from "../circular_queue";

describe("Circular Queue", () => {
let queue: CircularQueue<number>;

beforeEach(() => {
queue = new CircularQueue(5);
});

it("should enqueue an element", () => {
queue.enqueue(1);

expect(queue.peek()).toBe(1);
});

it("should throw an error on enqueue when queue is full", () => {
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
queue.enqueue(4);
queue.enqueue(5);

expect(() => queue.enqueue(6)).toThrowError("Queue is full");
});

it("should dequeue an element", () => {
queue.enqueue(1);
queue.enqueue(2);

expect(queue.dequeue()).toBe(1);
});

it("should throw an error on dequeue when queue is empty", () => {
expect(() => queue.dequeue()).toThrowError("Queue is empty");
});

it("should peek an element", () => {
queue.enqueue(1);
queue.enqueue(2);

expect(queue.peek()).toBe(1);
});

it("should return null on peek when queue is empty", () => {
expect(queue.peek()).toBeNull();
});

it("should return true on isEmpty when queue is empty", () => {
expect(queue.isEmpty()).toBeTruthy();
});

it("should return false on isEmpty when queue is not empty", () => {
queue.enqueue(1);

expect(queue.isEmpty()).toBeFalsy();
});

it("should return the correct length", () => {
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);

expect(queue.length()).toBe(3);
});
});