Introduction

Queue Queue is a very common data structure. The so-called queue is a first-in first-out sequence structure.

Imagine our daily queuing to buy tickets, we can only insert data to the end of the line, and then get the data from the head of the line. The message middleware commonly used in large projects is a very good implementation of a queue.

Implementation of the queue

A queue requires an enQueue entry operation and a DeQueue operation. Of course, there can also be some auxiliary operations, such as isEmpty to determine whether the queue is empty, isFull to determine whether the queue is full, and so on.

In order to implement convenient operations at the head and tail of the queue, we need to save the markers of the head and tail of the queue.

First look at the animation, and intuitively feel how the queue enters and exits the queue.

First look at joining the team:

Look at the team again:

It can be seen that entering the team is from the end of the team, and leaving the team is from the first.

Array implementation of queue

Like stacks, queues can be implemented in many ways. The most basic can be implemented using arrays or linked lists.

First consider the case of using an array to store data.

We use head to represent the index of the head of the team, and use rear to represent the index of the end of the team.

When the end of the team is constantly inserted and the head of the team is constantly fetching data, the following situations are likely to occur:

In the above figure, the index of head is already 2, and the rear has reached the end of the array. How to insert data into the array?

If you insert data after the rear, the two spaces before the head are wasted. At this time, we need to use a circular array.

How to realize the loop array? You only need to connect the last node of the array to the first node of the array.

Some students have to ask again. How does the array become a circular array? Arrays cannot be connected back and forth like linked lists.

No hurry, let's first consider the concept of a remainder. If we know the capacity of the array, when we want to insert data into the array, we still increase the rear+1 as usual, but finally divide by the capacity of the array, and the end of the line is changed to the line. First, it also indirectly realizes the circular array.

Take a look at how the java code is implemented:

public class ArrayQueue {

    //存储数据的数组
    private int[] array;
    //head索引
    private int head;
    //real索引
    private int rear;
    //数组容量
    private int capacity;

    public ArrayQueue (int capacity){
        this.capacity=capacity;
        this.head=-1;
        this.rear =-1;
        this.array= new int[capacity];
    }

    public boolean isEmpty(){
        return head == -1;
    }

    public boolean isFull(){
        return (rear +1)%capacity==head;
    }

    public int getQueueSize(){
        if(head == -1){
            return 0;
        }
        return (rear +1-head+capacity)%capacity;
    }

    //从尾部入队列
    public void enQueue(int data){
        if(isFull()){
            System.out.println("Queue is full");
        }else{
            //从尾部插入
            rear = (rear +1)%capacity;
            array[rear]= data;
            //如果插入之前队列为空,将head指向real
            if(head == -1 ){
                head = rear;
            }
        }
    }

    //从头部取数据
    public int deQueue(){
        int data;
        if(isEmpty()){
            System.out.println("Queue is empty");
            return -1;
        }else{
            data= array[head];
            //如果只有一个元素,则重置head和real
            if(head == rear){
                head= -1;
                rear = -1;
            }else{
                head = (head+1)%capacity;
            }
            return data;
        }
    }
}

Everyone pay attention to the methods used in our enQueue and deQueue:

rear = (rear +1)%capacity
head = (head+1)%capacity

These two are the realization of circular arrays.

Dynamic array implementation of queue

The above implementation actually has a problem. The size of the array is hard-coded and cannot be dynamically expanded. Let's implement a dynamic array implementation that can dynamically expand.

    //因为是循环数组,这里不能做简单的数组拷贝
    private void extendQueue(){
        int newCapacity= capacity*2;
        int[] newArray= new int[newCapacity];
        //先全部拷贝
        System.arraycopy(array,0,newArray,0,array.length);
        //如果real<head,表示已经进行循环了,需要将0-head之间的数据置空,并将数据拷贝到新数组的相应位置
        if(rear< head){
            for(int i=0; i< head; i++){
                //重置0-head的数据
                newArray[i]= -1;
                //拷贝到新的位置
                newArray[i+capacity]=array[i];
            }
            //重置real的位置
            rear= rear+capacity;
            //重置capacity和array
            capacity=newCapacity;
            array=newArray;
        }
    }

It should be noted that when expanding the array, we cannot simply copy it, because it is a circular array, and the rear may be behind the head. At this time, we need to perform special processing on the array.

The other parts are basically the same as the ordinary array implementation.

Queue's linked list implementation

In addition to using arrays, we can also use linked lists to implement queues, which only need to be deleted at the head and added at the tail.

Look at the java code implementation:

public class LinkedListQueue {
    //head节点
    private Node headNode;
    //rear节点
    private Node rearNode;

    class Node {
        int data;
        Node next;
        //Node的构造函数
        Node(int d) {
            data = d;
        }
    }

    public boolean isEmpty(){
        return headNode==null;
    }

    public void enQueue(int data){
        Node newNode= new Node(data);
        //将rearNode的next指向新插入的节点
        if(rearNode !=null){
            rearNode.next=newNode;
        }
        rearNode=newNode;
        if(headNode == null){
            headNode=newNode;
        }
    }

    public int deQueue(){
        int data;
        if(isEmpty()){
            System.out.println("Queue is empty");
            return -1;
        }else{
            data=headNode.data;
            headNode=headNode.next;
        }
        return data;
    }
}

Queue time complexity

The above three implementations of enQueue and deQueue methods can basically be positioned immediately to enter the queue or exit the queue, so their time complexity is O(1).

The code address of this article:

learn-algorithm

This article has been included in http://www.flydean.com/12-algorithm-queue/

The most popular interpretation, the most profound dry goods, the most concise tutorial, and many tips you don't know are waiting for you to discover!

Welcome to pay attention to my official account: "Program those things", know technology, know you better!


flydean
890 声望433 粉丝

欢迎访问我的个人网站:www.flydean.com