DEV Community

Hamza Hayd
Hamza Hayd

Posted on

Use LinkedList when implementing QUEUES in JS.

There are many discussions about what to use when implementing queues in JavaScript. This is because Queues can be implemented in JavaScript differently using a combination of built-in, higher-level methods like push, pop, shift and unshift. However, since the shift and unshift methods move every item in the list, this approach, though convenient, is inefficient for a large dataset, and this is what happened to me during a project that I have been working on, where things got pretty critical pretty fast.

In this article, I'm not claiming that this is the only way to do it or that this is how you should do it. WHY IS THIS THE CASE? Because there is no such thing as a "right" way of doing things in software development, it is all dependent on your goals and what you want to achieve. I'd like to bring this up, though, so you're aware of this issue when working with large datasets.

So what are Queues anyway?

In computer science, queues are defined as an Abstract Data Type, yea you read that correctly, not a data structure. You can read more about ADT and queues here and here.

As I previously said, there are many approaches to implementing queues, but regardless of which direction we take, we must implement queues as a first-in-first-out structure.

Moreover, Using LinkedList when implementing queues is going to help us perform the operations-enqueueing and dequeuing in O(1) time. This is not the case, though, when you are using built-in shift, or unshift methods.

Queues implementation using a LinkedList

First, let's create our Node class.

class Node {
 constructor(value) {
    this.value = value
    this.next = null 
  }
}
Enter fullscreen mode Exit fullscreen mode

Secondly, now when we created our Node class, let's implement our queue. We'll start by creating our Queue class.

class Queue {
  constructor() {
    this.first = null
    this.last = null
    this.size = 0
  }
}
Enter fullscreen mode Exit fullscreen mode

We created here a Queue class that has three properties. Note that I use the keyword size instead of length. This is optional, but I prefer using size since Arrays have the length property.

In queues, we need to implement several methods like enqueue(add an item to the back of the queue), dequeue(remove an item from the front of the queue), peek(returns the next item that's to be removed), isEmpty(returns true if the queue is empty).

Let's start with the isEmpty method since it's the easiest one. It returns true if the size of our queue is empty.

  isEmpty() {
    return !this.size
  }
Enter fullscreen mode Exit fullscreen mode

Let's now implement the enqueue method. It looks like this.

   enqueue(item) {
    // Create node
    const newNode = new Node(item)
    /**
     * * If our list is empty than both our 
     * * first item and last item is going to point the new node. 
     */
    if (this.isEmpty()) {
      this.first = newNode
      this.last = newNode
    }
    else {
      this.last.next = newNode
      this.last = newNode
    }
    this.size++
    return this 
  }
Enter fullscreen mode Exit fullscreen mode

After the enqueue method let's implement our dequeue and peek methods as well.

  /**
   * 
   * @returns 
   */

  dequeue() {

    //* if our queue is empty we return null 
    if (this.isEmpty()) return null
    const itemToBeRemoved = this.first

    /**
     * * if both our first and last node are pointing the same item
     * * we dequeued our last node. 
     */
    if (this.first === this.last) {
      this.last = null
    }
    this.first = this.first.next
    this.size--
    return itemToBeRemoved
  }

  /**
   * * Returns the next element to be dequeued. 
   * @returns 
   */
  peek() {
    return this.first
  }
}
Enter fullscreen mode Exit fullscreen mode

The whole implementation looks like this.

class Queue {
  constructor() {
    this.first = null
    this.last = null
    this.size = 0
  }


  isEmpty() {
    return !this.size
  }

  enqueue(item) {
    // Create node
    const newNode = new Node(item)
    /**
     * * If our list is empty than both our 
     * * first item and last item is going to point the new node. 
     */
    if (this.isEmpty()) {
      this.first = newNode
      this.last = newNode
    }
    else {
      this.last.next = newNode
      this.last = newNode
    }
    this.size++
    return this 
  }
  /**
   * 
   * @returns 
   */

  dequeue() {

    //* if our queue is empty we return null 
    if (this.isEmpty()) return null
    const itemToBeRemoved = this.first

    /**
     * * if both our first and last node are pointing the same item
     * * we dequeued our last node. 
     */
    if (this.first === this.last) {
      this.last = null
    }
    this.first = this.first.next
    this.size--
    return itemToBeRemoved
  }

  /**
   * * Returns the next element to be dequeued. 
   * @returns 
   */
  peek() {
    return this.first
  }
}
Enter fullscreen mode Exit fullscreen mode

Hope you find this post useful, any feedback and discussion are welcome. By3

Top comments (1)

Collapse
 
kosm profile image
Kos-M

Nice intro to linked lists!
Can i use Queue class in an open source project i'm working on ?