DEV Community

Khadija Ashraf
Khadija Ashraf

Posted on

1

Data structure: Implement Type safe, Generic, Double-ended Queue.

Today we will implement a Double-ended queue in Java. We will use generics so that our queue can work with any datatypes, like Integer, Double, String, Cars, Trucks, Cats, Dogs, etc... :)

The source code is in this github repository. https://github.com/khadija-ashraf/data-structure-algorithm.git

The Node is a generic class. That means this class can take different dataypes. A Node object has a generic type 'data' and two pointer 'prev' and 'next'. 'prev' points to the previous node, and 'next' pointer points to the next node in the queue.

Nodes in a deque

package com.deque;


class Node<T>{
    T data;
    Node<T> prev;
    Node<T> next;

    public Node(T data){
        this.data = data;
        this.prev = null;
        this.next = null;
    }
}
Enter fullscreen mode Exit fullscreen mode

MyDeque is the deque interface. It layout the deque behaviour.

package com.deque;

// A custom Double Ended Queue (Deque) implementation:

public interface MyDeque<T> {

    public <T> T addHead(T data);
    public <T> T addTail(T data);

    public T getHead();
    public T getTail();

    public <T> boolean contains(T data);

    public T removeHead();
    public T removeTail();

    public T peekHead();
    public T peekTail();

    public T pollHead();
    public T pollTail();

    public T pop();

    public int size();
    public void printDequq() ;

}
Enter fullscreen mode Exit fullscreen mode

A deque is a queue in which we can insert and remove from both the front and rear end. Conversely, in an original queue we insert at the front and remove from the rear end.

In a deque, we have a head node and a tail node representing the start and the end of the queue respectively. We add remove from both front and rear ends from the head and tail referencing nodes.

class MyDequeImpl<T> implements MyDeque<T>{
    private Node<T> head;
    private Node<T> tail;
    private int size;

    public MyDequeImpl(){
        head = null;
        tail = null;
        size = 0;
    }

    public <T> T addHead(T data) {
        Node current = new Node<>(data);
        if(head == null) {
            head = current;
            tail = current;
            size++;
            return data;
        }
        current.next = head;
        head.prev = current;
        head = current;
        size++;

        return data;
    }

    public <T> T addTail(T data) {
        Node current = new Node<T>(data);

        if(tail == null) {
            head = current;
            tail = current;
            size++;
            return data;
        }
        tail.next = current;
        current.prev = tail;
        tail = current;
        size++;
        return data;
    }

    public T getHead() {
        if (head == null)
            return null;
        return head.data;
    }

    public T getTail() {
        if(tail == null)
            return null;
        return tail.data;
    }

    public <T> boolean contains(T data) {
        if(head == null)
            return false;

        if(head.data == data) {
            return true;
        }

        if(tail.data == data) {
            return true;
        }

        Node current = head;

        while(current != null) {
            if(current.data == data) {
                return true;
            }
            current = current.next;
        }
        return false;
    }

    public T removeHead() {
        if(head == null) {
            return null;
        }

        T removedData = head.data;

        head = head.next;

        if(head == null) {
            tail = null;
        } else {
            head.prev = null;
        }
        size--;
        return removedData;
    }

    public T removeTail() {
        if(tail == null) {
            return null;
        }
        if(tail.prev == null) {
            return null;
        }
        T removedData = tail.data;
        tail = tail.prev;
        if(tail == null) {
            head = null;
        } else {
            tail.next = null;
        }
        size--;
        return removedData;
    }

    public T peekHead() {
        if(head == null)
            return null;

        return head.data;
    }

    public T peekTail() {
        if(tail == null)
            return null;

        return tail.data;
    }

    public T pollHead() {
        if(head == null)
            return null;

        T polledData = head.data;

        head = head.next;

        if(head == null) {
            tail = null;
        } else {
            head.prev = null;
        }
        size--;

        return polledData;
    }

    @Override
    public T pollTail() {
        if(tail == null) {
            return null;
        }
        T pollData = tail.data;

        tail = tail.prev;

        if(tail == null)
            head = null;
        else {
            tail.next = null;
        }

        size--;
        return pollData;
    }

    public T pop() {
        if(tail == null)
            return null;

        T popedData = tail.data;

        tail = tail.prev;

        if(tail == null)
            head = null;
        else {
            tail.next = null;
        }
        size--;
        return popedData;
    }

    public int size() {
        return size;
    }
    public void printDequq() {
        System.out.println("Printing the deque of size: "+size());
        if (head == null) {
            System.out.println("Dequq is empty.");
        }
        Node<T> current = head;
        while(current != null) {
            System.out.println(current.data);
            current = current.next;
        }
    }

}
Enter fullscreen mode Exit fullscreen mode

Below is some test insertions, removal, polling, peeking, and pop.

package com.deque;

public class TestDeque{
    public static void main(String arg[]) {
        MyDeque<String> deque = new MyDequeImpl<>();
        deque.addHead("cat");
        deque.printDequq();
        deque.addHead("dog");
        deque.printDequq();
        deque.addHead("rabbit");
        deque.printDequq();
        deque.addHead("elephant");
        deque.printDequq();
        deque.addTail("squirrel");
        deque.printDequq();

        System.out.println("=============");
        System.out.println(deque.getHead());
        System.out.println(deque.getTail());
        System.out.println(deque.contains("monkey"));
        System.out.println(deque.contains("rabbit"));
        System.out.println(deque.removeHead());
        System.out.println(deque.removeTail());
        System.out.println("=======");

        System.out.println(deque.getHead());
        System.out.println(deque.getTail());
        System.out.println("=======");
        System.out.println(deque.peekHead());
        System.out.println(deque.peekTail());
        System.out.println("========");
        System.out.println(deque.pollHead());
        System.out.println(deque.pollTail());
        deque.printDequq();

        System.out.println("========");
        System.out.println(deque.pop());
        deque.printDequq();

        deque.addHead("birds");

        deque.printDequq();
    }
}


Enter fullscreen mode Exit fullscreen mode

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay