On the use and implementation of stack and queue in Java collection framework

Posted by Krash on Wed, 12 Jan 2022 09:10:41 +0100

1. Queue

1.1 concept

Queue: a special linear table that only allows inserting data at one end and deleting data at the other end. The queue has the characteristics of first in first out FIFO(First In First Out).
Queue entry: the end of the insertion operation is called Tail/Rear
Out of queue: the end for deletion is called Head/Front

Illustration:

1.2 copy Queue interface

You can refer to the Jjava api documentation and find:

  • Queue inherits from the Collection interface and is implemented by LinkedList

  • A group of methods notifies the caller of an error through a special return value:

    • boolean: offer (E): Insert
    • E peek(): View
    • E poll(): delete
  • A group of methods notifies the caller of the error by exception:

    • Boolean add (E): Insert
    • E element(): View
    • E remove(): delete

Imitate the real Queue interface, element type, and fix it into Integer type without generics
Example code:

public interface Queue {
    /**
     * Notify the error by throwing an exception
     */

    /**
     *
     * Always return true
     */
   default boolean add(Integer e){
       if(offer(e)==false){
           throw new IllegalStateException();
       }
       return true;
   }

    /**
     * View team leader element
     */

    default Integer element(){
        Integer e = peek();
        if(e==null){
            throw new NoSuchElementException();
        }
        return e;
    }
    /**
     * Return and delete element
     */
    default Integer remove(){
        Integer e = poll();
        if(e==null){
            throw new NoSuchElementException();
        }
        return e;
    }


    /**
     * The error is notified by a special return value
     */
    /**
     * insert
     * true Success, false, failure
     */
    boolean offer(Integer e);

    /**
     * View team leader element
     */

    Integer peek();

    /**
     * Return and delete element
     */
    Integer poll();

}

1.3 implementation of circular queue

1.3.1 no additional space

By introducing size to distinguish whether the queue is empty or full, there is no need to open up additional space, that is, k is the array length

Illustration:
Insert element:

Delete element:

Method description:

  • For enQueue: if the queue is not satisfied, the real and size are + +. If the real is equal to the array length, the real is set to 0
  • For deQueue: if the queue is not empty, size is --, front is + +, and finally if front = = array length, set front to 0
  • For Front: not null, return array[front]
  • For Rear: not null. If rear==0, array[length-1] will be returned; otherwise, array[rear-1] will be returned
  • Null for isEmpty: size 0
  • For IsFull: size = = array length is full

Code example:

public class MyCircularQueue {

    private int[] array;
    private int size;
    private int front;
    private int rear;
    public MyCircularQueue(int k) {
        array = new int[k];
        size=0;
        front = 0;
        rear = 0;
    }

    public boolean enQueue(int value) {
        if(isFull()) {
            return false;
        }
        array[rear++] = value;
        size++;
        if(rear==array.length) {
            rear = 0;
        }
        return true;
    }

    public boolean deQueue() {
        if(isEmpty()) {
            return false;
        }
        size--;
        front++;
        if(front==array.length) {
            front = 0;
        }
        return true;
    }

    public int Front() {
        if(isEmpty()) {
            return -1;
        }
        return array[front];
    }

    public int Rear() {
        if(isEmpty()) {
            return -1;
        }
        if(rear == 0) {
            return array[array.length-1];
        }
        return array[rear-1];
    }

    public boolean isEmpty() {

        return size==0;
    }

    public boolean isFull() {
        return size==array.length;
    }
}

1.3.2 need to open up an additional space

If you directly use front and rear to judge empty and full, you need to open up an additional space, that is, k+1 is the array length

Illustration:
Insert element:

Delete element:

Method description:

  • For enQueue: if rear==k+1, set rear to 0
  • For deQueue: if front==k+1, set front to 0
  • For Front: not null, return array[front]
  • For rear: if it is not empty and rear is 0, array[k] is returned; otherwise, array[rear-1] is returned
  • For IsEmpty: null when front equals rear
  • For IsFull: full when rear + 1% K + 1 = = front

Code example:

public class MyCircularQueue {
    private int[] array;
    private int rear,front;
    private int k;
    public MyCircularQueue_self(int k) {
        this.k = k;
        array = new int[k+1];
        front = rear = 0;
    }

    /**
     * k+1 Is the array length
     * @param value
     * @return
     */
    public boolean enQueue(int value) {
        if(isFull()){
            // System.out.println("sasd");
            return false;
        }
        array[rear++] = value;
        if(rear==k+1){
            rear = 0;
        }
        return true;
    }

    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        front++;
        if(front==k+1){
            front = 0;
        }

        return true;
    }

    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return array[front];
    }

    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        if(rear==0){
            return array[k];
        }
        return array[rear-1];
    }

    public boolean isEmpty() {
        return front==rear;
    }

    public boolean isFull() {
       return (rear+1)%(k+1)==front;
    }

2. Dual Ended queue (Deque)

2.1 concept

deque refers to a queue that allows both ends to enter and leave the queue. deque is the abbreviation of "double ended queue".
That means that elements can be out of the team and in the team from the head of the team, or out of the team and in the team from the end of the team.

2.2 imitation Deque interface

It can be found from the Java api documentation that Deque inherits from Queue

Method description:

  • A group of methods report errors through special values:

    • boolean offerFirst/offerLast(E e): head insertion, tail insertion
    • E peekfirst() / peeklast(): View team head / tail elements
    • E pollfirst() / polllast(): header deletion and tail deletion
  • A set of methods notify the caller of an error through an exception:

    • Void addfirst / addlast (E): head / tail insertion
    • E removeFirst/removeLast(): delete header / footer, return and delete elements
    • E getFirst/getLast(): view the team head / tail elements

Copy:

public interface Deque extends Queue {
    //Error reporting by special value

    boolean offerFirst(Integer e);
    Integer peekFirst();
    Integer pollFirst();

    boolean offerLast(Integer e);
    Integer peekLast();
    Integer pollLast();

    //An error is reported by throwing an exception

    default void addFirst(Integer e){
        if(offerFirst(e)==false){
            throw new IllegalStateException();
        }

    }

    default Integer getFirst(){
        Integer e = peekFirst();
        if(e==null){
            throw new NoSuchElementException();
        }
        return e;
    }

    default Integer removeFirst(){
        Integer e = pollFirst();
        if(e==null){
            throw new NoSuchElementException();
        }
        return e;

    }


    default void addLast(Integer e){
        if(offerLast(e)==false){
            throw new IllegalStateException();
        }

    }

    default Integer getLast(){
        Integer e = peekLast();
        if(e==null){
            throw new NoSuchElementException();
        }
        return e;
    }

    default Integer removeLast(){
        Integer e = pollLast();
        if(e==null){
            throw new NoSuchElementException();
        }
        return e;

    }


    //This set of methods inherits from Queue

    default boolean offer(Integer e){
        return offerLast(e);
    }
    default Integer peek(){
        return peekFirst();
    }

    default Integer poll(){
        return pollFirst();
    }


    //The following set of methods are prepared for the form of stack

    default void push(Integer e){
        addFirst(e);
    }

    default Integer pop(){
        return removeFirst();
    }
}

3. Stack

3.1 concept

Stack: a special linear table that allows insertion and deletion of elements only at a fixed end. One end for data insertion and deletion is called the top of the stack, and the other end is called the bottom of the stack.

  • The data elements in the stack follow the principle of Last In First Out LIFO (Last In First Out).
  • Stack pressing: the stack insertion operation is called stack entering / stack pressing / stack entering, and the input data is at the top of the stack.
  • Stack out: stack deletion is called stack out. The output data is at the top of the stack

Illustration:

3.2 implementation of stack

Array can be used to achieve, but the linked list is more efficient. Through the Java api document, it is found that LinkedList implements the Deque interface, and Deque inherits the Queue interface

Imitation of LinkedList:

public class LinkedList implements Deque{
    private static class Node{
        private Integer v;
        Node prev;
        Node next;

        Node(Integer x){
            v = x;
        }
    }
    private Node head;
    private Node tail;
    private int size;

    /**
     * Head insert
     * @param e
     * @return
     */
    @Override
    public boolean offerFirst(Integer e) {
        Node node = new Node(e);
        if(size==0){
            head = tail = node;
        }else{
            node.next = head;
            head.prev = node;
            head = node;
        }

        return true;
    }

    /**
     * View header elements
     * @return
     */
    @Override
    public Integer peekFirst() {
        if(size==0){
            return null;
        }
        return head.v;
    }

    /**
     * Header deletion
     * @return
     */
    @Override
    public Integer pollFirst() {
        if(size==0){
            return null;
        }
        Integer e = head.v;
        head = head.next;
        if(head!=null){
            head.prev=null;
        }else{
            tail = null;
        }
        return e;
    }

    /**
     * Tail insertion
     * @param e
     * @return
     */
    @Override
    public boolean offerLast(Integer e) {
        Node node = new Node(e);
        return false;
    }

    /**
     * View tail element
     * @return
     */
    @Override
    public Integer peekLast() {
        if(size==0){
            return null;
        }
        return tail.v;
    }

    /**
     * Tail deletion
     * @return
     */
    @Override
    public Integer pollLast() {
        if(size==0){
            return null;
        }
        Integer e = tail.v;

        tail = tail.prev;
        if(tail!=null){
            tail.next=null;

        }else{
            head = null;
        }
        size--;
        return e;
    }
}

Because LinkedList implements Deque and Deque inherits Queue, you can find:
When used as a stack, the core method is:

  • E push(E item): stack pressing
  • E pop(): out of stack
  • E peek(): View stack top elements
  • boolean isEmpety(): judge whether the stack is empty

4. Summary

The stacks and queues in java are actually represented by LinkedList, so when:

4.1 use as a Stack

methodexplain
E push(E item)Stack pressing
E pop()Out of stack
E peek()View stack top element
boolean isEmpety()Determine whether the stack is empty

4.2 use as a Queue

error handlingThrow exceptionReturn special value
Queueadd(e)offer(e)
Out of queueremove()poll()
Team leader elementelement()peek()

4.3 use as Deque

Topics: Java data structure queue stack