Skip to content

Commit 2ac83c8

Browse files
authored
feat(structure): implements circular queue (TheAlgorithms#116)
* feat(structure): implements circular queue * feat: circular queue no longer implements queue interface
1 parent ea783b9 commit 2ac83c8

File tree

2 files changed

+174
-0
lines changed

2 files changed

+174
-0
lines changed
+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Circular Queue implementation using array.
3+
*
4+
* @template T The type of the elements in the queue.
5+
* @param {T[]} queue The array that holds the elements of the queue.
6+
* @param {number} frontIndex The index of the front element of the queue.
7+
* @param {number} rearIndex The index of the rear element of the queue.
8+
* @param {number} size The size of the queue.
9+
*/
10+
export class CircularQueue<T> {
11+
private queue: T[];
12+
private frontIndex: number;
13+
private rearIndex: number;
14+
private size: number;
15+
16+
constructor(size: number) {
17+
this.queue = new Array(size);
18+
this.frontIndex = -1;
19+
this.rearIndex = -1;
20+
this.size = size;
21+
}
22+
23+
/**
24+
* Adds an item to the queue.
25+
*
26+
* @param item The item being added to the queue.
27+
*/
28+
enqueue(item: T): void {
29+
if (
30+
(this.frontIndex == 0 && this.rearIndex == this.size - 1) ||
31+
this.rearIndex == (this.frontIndex - 1) % (this.size - 1)
32+
) {
33+
throw new Error("Queue is full");
34+
} else if (this.frontIndex == -1) {
35+
this.frontIndex = 0;
36+
this.rearIndex = 0;
37+
this.queue[this.rearIndex] = item;
38+
} else if (this.rearIndex == this.size - 1 && this.frontIndex != 0) {
39+
this.rearIndex = 0;
40+
this.queue[this.rearIndex] = item;
41+
} else {
42+
this.rearIndex++;
43+
this.queue[this.rearIndex] = item;
44+
}
45+
}
46+
47+
/**
48+
* Removes an item from the queue and returns it.
49+
*
50+
* @throws Queue Underflow if the queue is empty.
51+
* @returns The item that was removed from the queue.
52+
*/
53+
dequeue(): T | undefined {
54+
if (this.frontIndex == -1) {
55+
throw new Error("Queue is empty");
56+
}
57+
58+
const item = this.queue[this.frontIndex];
59+
if (this.frontIndex == this.rearIndex) {
60+
this.frontIndex = -1;
61+
this.rearIndex = -1;
62+
} else if (this.frontIndex == this.size - 1) {
63+
this.frontIndex = 0;
64+
} else {
65+
this.frontIndex++;
66+
}
67+
68+
return item;
69+
}
70+
71+
/**
72+
* Returns the item at the front of the queue.
73+
*
74+
* @returns The item at the front of the queue or null if the queue is empty.
75+
*/
76+
peek(): T | null | undefined {
77+
if (this.frontIndex == -1) {
78+
return null;
79+
}
80+
81+
return this.queue[this.frontIndex];
82+
}
83+
84+
/**
85+
* Checks if the queue is empty.
86+
*
87+
* @returns {boolean} Whether the queue is empty or not.
88+
*/
89+
isEmpty(): boolean {
90+
return this.frontIndex == -1;
91+
}
92+
93+
/**
94+
* Returns the number of items in the queue.
95+
*
96+
* @returns {number} The number of items in the queue.
97+
*/
98+
length(): number {
99+
if (this.frontIndex == -1) {
100+
return 0;
101+
}
102+
103+
if (this.rearIndex >= this.frontIndex) {
104+
return this.rearIndex - this.frontIndex + 1;
105+
}
106+
107+
return this.size - (this.frontIndex - this.rearIndex - 1);
108+
}
109+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { CircularQueue } from "../circular_queue";
2+
3+
describe("Circular Queue", () => {
4+
let queue: CircularQueue<number>;
5+
6+
beforeEach(() => {
7+
queue = new CircularQueue(5);
8+
});
9+
10+
it("should enqueue an element", () => {
11+
queue.enqueue(1);
12+
13+
expect(queue.peek()).toBe(1);
14+
});
15+
16+
it("should throw an error on enqueue when queue is full", () => {
17+
queue.enqueue(1);
18+
queue.enqueue(2);
19+
queue.enqueue(3);
20+
queue.enqueue(4);
21+
queue.enqueue(5);
22+
23+
expect(() => queue.enqueue(6)).toThrowError("Queue is full");
24+
});
25+
26+
it("should dequeue an element", () => {
27+
queue.enqueue(1);
28+
queue.enqueue(2);
29+
30+
expect(queue.dequeue()).toBe(1);
31+
});
32+
33+
it("should throw an error on dequeue when queue is empty", () => {
34+
expect(() => queue.dequeue()).toThrowError("Queue is empty");
35+
});
36+
37+
it("should peek an element", () => {
38+
queue.enqueue(1);
39+
queue.enqueue(2);
40+
41+
expect(queue.peek()).toBe(1);
42+
});
43+
44+
it("should return null on peek when queue is empty", () => {
45+
expect(queue.peek()).toBeNull();
46+
});
47+
48+
it("should return true on isEmpty when queue is empty", () => {
49+
expect(queue.isEmpty()).toBeTruthy();
50+
});
51+
52+
it("should return false on isEmpty when queue is not empty", () => {
53+
queue.enqueue(1);
54+
55+
expect(queue.isEmpty()).toBeFalsy();
56+
});
57+
58+
it("should return the correct length", () => {
59+
queue.enqueue(1);
60+
queue.enqueue(2);
61+
queue.enqueue(3);
62+
63+
expect(queue.length()).toBe(3);
64+
});
65+
});

0 commit comments

Comments
 (0)