Data Structures: Circular Queue in TypeScript

Circular Queues: Revolving Around Efficiency in TypeScript

Hello there, folks! Ever been in a situation where you felt like you were going around in circles? Well, in the world of data structures, that's not always a bad thing. Today, we're diving deep into the concept of Circular Queues and how they twirl around in TypeScript. Buckle up, because we're in for a thrilling ride!

To review what a Queue is, you can check out the following article on a Queue in TypeScript.

Introduction to Circular Queues

Picture a queue at your favorite coffee shop. People join the end of the line and leave from the front. But what if, by some magic, the end of the line seamlessly connected to the front? Mind-boggling, isn't it? That's the essence of a Circular Queue.

What Makes Circular Queues Special?

  • Efficient Space Utilization: They make the most of the space they occupy. It's like having a suitcase that automatically makes room for more clothes. Who wouldn't want that?
  • No Need for Shifting Elements: Unlike linear queues, where you gotta shuffle everyone forward, circular queues are like a merry-go-round; everyone just moves in a circle.
  • Fixed Size Advantage: They come with a preset size, making them predictable and stable.

Implementing Circular Queues in TypeScript

Let's roll up our sleeves and get our hands dirty with some TypeScript code. We'll build a Circular Queue from scratch, and no, you don't need to be a TypeScript wizard to follow along.

Laying the Groundwork


export class CircularQueue {
	items
	capacity
	currentLength
	front
	rear
	
	constructor(capacity: number) {
		this.items = new Array(capacity)
		this.capacity = capacity
		this.currentLength = 0
		this.front = -1
		this.rear = -1
	}
}

Useful utility functions

Before we start defining the methods to utilitze the queue, we will need and want some helpful utility functions

isEmpty()

This does exactly as it sounds. It checks the current length to see if it is zero or not. If not, then it's not empty.


    isEmpty() {
		return this.currentLength === 0
	}

isFull()

Does the opposite of isEmpty(), and checks if it is full. It compares the length against the capacity which is defined at initialization.


    isFull() {
		return this.currentLength === this.capacity
	}

Here, we're setting up our Circular Queue with some basic properties. Think of it as building the foundation for our circular mansion.

Adding Elements: The Enqueue Operation


    enqueue(element: any) {
		if (this.isFull()) {
			return null
		} else {
			this.rear = (this.rear + 1) % this.capacity // the modulo operator is used to wrap around the array
			this.items[this.rear] = element
			this.currentLength++
			if (this.front === -1) {
				this.front = this.rear
			}
		}
	}

Enqueuing is like inviting someone to join the party. But remember, there's only so much room in the mansion!

Removing Elements: The Dequeue Operation


    dequeue() {
		if (this.isEmpty()) {
			return null
		} else {
			const element = this.items[this.front]
			this.items[this.front] = null
			this.front = (this.front + 1) % this.capacity // the modulo operator is used to wrap around the array
			this.currentLength--
			if (this.isEmpty()) {
				this.front = -1
				this.rear = -1
			}

			return element
		}
	}

Dequeuing is like bidding farewell to the first guest who arrived. It's a cycle of hellos and goodbyes.

Peeking and print

Peeking is a method that allows you to see inside the queue


    peek() {
		if (this.isEmpty()) {
			return null
		} else {
			return this.items[this.front]
		}
	}

Peeking is like taking a quick glance at who's at the front of the line.


    print() {
		if (this.isEmpty()) {
			console.log("Queue is empty")
		} else {
			let i
			let str = ""
			for (i = this.front; i !== this.rear; i = (i + 1) % this.capacity) {
				str += this.items[i] + " "
			}
			str += this.items[i]
			console.log(str)
		}
	}

Print is basically just console logging what is inside the queue.

Practical Tips and Tricks

Size Matters: Choose your queue's size wisely. It's like picking the right-sized pot for cooking; too big or too small can be troublesome. Error Handling: Always handle those full and empty scenarios. It's like having a plan B when your party gets too crowded or too empty. Testing is Key: Test your queue with various scenarios. It's like taste-testing your cooking; you gotta make sure it's just right.

Wrapping It Up

Circular Queues in TypeScript are like a Ferris wheel; they take you on a smooth, circular journey of efficiency and elegance. They're nifty for problems where space and performance matter. So, next time you're coding up a storm in TypeScript, remember the Circular Queue, your merry-go-round of efficiency!

And there you have it, folks. A whirlwind tour of Circular Queues in TypeScript. Implementing them is like learning a new dance move; practice makes perfect. So, go ahead, give it a whirl!