JAVA data structure and algorithm (2) queue

Last week, I learned about queues in JAVA data structures and algorithms. I wrote something and recorded it for later review. It mainly introduced from four aspects: (1) Queue application scenarios (2) Queue detailed introduction (3) Array simulation queue ideas Analysis and code implementation (4) The idea analysis and code implementation of the circular queue (5) Summary.

(1) Application scenarios of queues

       Realistic scenario: Queues are very common in daily life, for example: banks line up for business, canteens line up for meals, etc. The bank queuing to call the number, four clerk, to serve the people in the line, after each clerk completes the service, then the next person to be served will be generated from the queue below. The people in the queue follow the principle of first-come, first-served and wait to be called by the window once to provide the required services. Then, the people in the queue are equivalent to a queue.

           

For example, when we go to a movie theater to line up to buy tickets, the first person who enters the queue is the first person who buys a ticket and leaves the queue, and the last person who enters the queue is the last person who buys the ticket.

For example, in a computer operating system, there are various queues working quietly, such as a printer waiting to print in a printing queue.

So, when is the queue? How to use Java to implement the queue?

(2) Queue detailed introduction

      A queue is an ordered linear list, which can be implemented by an array or a linked list. It follows the principle of first-in, first-out, that is, the data stored in the queue first must be taken out first, and the data stored later must be taken out later. The difference from the stack is that the queue is a structure that can be used at both ends, one end is used to add new elements and the other end deletes elements, or only one end can insert or delete data. The end that performs the insertion operation is called the end of the team, and the end that performs the deletion operation is called the head of the team. When there are no elements in the queue, it is called an empty queue.

å¨è¿éæå ¥ å¾çæè¿ °

 The queue is divided into:

  1.   One-way queue (Queue): You can only insert data at one end and delete data at the other end.
  2.   Two-way queue (Deque): Each end can insert data and delete data operations.

In the queue, the head and tail: the end that allows elements to be inserted is called the tail, and the end that allows elements to be deleted is called the head of the queue. Enqueue: insert operation of queue, dequeue: delete operation of queue, as follows, we show the push operation to a complete queue, adding numbers 1, 2, 3 to it, the process is as follows:

Take 1, 2, 3 from a queue; the operation of popping is as follows:

 

(3) Thinking analysis and code analysis of array simulation queue

         The queue itself is an ordered list. So, how to use an array to add, delete, modify and check the queue?

        If the structure of an array is used to store the data of the queue, the declaration of the queue array is as shown in the figure below, where maxSize is the maximum capacity of the queue. Because the output and input of the queue are processed separately from the front and back ends, two variables front and rear are required to record the subscripts of the front and back ends of the queue respectively. The front will change with the data output, and the rear will change with the data input. as the picture shows:

å¨è¿éæå ¥ å¾çæè¿ °

When we store data in the queue, it is called "addQueue". The processing of addQueue requires two steps:

Analysis of thinking moves the tail pointer backward: rear+1, when front == rear [empty], if the tail pointer rear is less than the maximum subscript maxSize-1 of the queue, the data will be stored in the array element pointed to by rear, otherwise it will not be possible Save the data. rear == maxSize-1[queue full]; namely:

  • front is the position before the front element of the queue [not including the front]
  • rear is the last element of the queue [including the last]
  • Insert the queue, determine whether it is full, move the tail pointer backward: rear++, then insert arr[rear]
  • Move out of the queue, determine whether it is empty, move the front pointer back: front++, and then move out arr[front]
  • Queue is empty judgment condition: when front == rear 【empty】
  • The condition for judging whether the queue is full: rear == maxSize-1 [queue full]

When we understand the implementation logic of the queue, the implementation code using the array is:

package JAVADATASTRTUCRE;

import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * User:  yongping Li
 * Date: 2020/11/16
 * Time: 17:06
 * Description: No Description
 */

/*
问题:队列不能重复使用
 */
public class arrayQueueDemo {
    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(3);
        char key;//接受用户输入
        Scanner scanner =new Scanner(System.in);
        boolean loop=true;
        while(loop){
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列中取数据");
            System.out.println("h(head):查看队列头部数据");
            key=scanner.next().charAt(0);
            switch (key){
                case 's':
                    arrayQueue.showQueue();
                    break;
                case 'a':
                    System.out.println("请输入一个数");
                    int value=scanner.nextInt();
                    arrayQueue.addQueue(value);
                    break;
                case 'g':
                    try{
                        int res =arrayQueue.getQueue();
                        System.out.println("去除的数据为"+res);
                    }catch(Exception E){
                        System.out.println(E.getMessage());
                    }
                    break;
                case 'h':
                    try{
                        int head =arrayQueue.headQueue();
                        System.out.println("头部的数据为"+head);
                    }catch(Exception E){
                        System.out.println(E.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop=false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出!!!!");
    }
}

class ArrayQueue{

    private int maxSiaze;//队列的最大容量
    private int front;//队列头部
    private int rear;//队列尾部
    private int []arr;//用于1存放数据,模拟队列

    //创建队列的构造器
    public ArrayQueue(int arrMaxSize){
          maxSiaze=arrMaxSize;
          arr=new int[maxSiaze];
          front=-1;//指向队列头部的前一个位置,
          rear=-1;//指向队列尾部的数据(即队列的最后一个数据)
    }

//判断队列是否满
    public  boolean isFull(){
        return rear==maxSiaze-1;
    }
//判断队列是否为空
    public boolean isEmpty(){
     return rear==front;
    }
//添加数据到队列
public void addQueue(int n){
    //判断队列是否满
    if(isFull()){
        System.out.println("队列已满,");
        return;
    }
      rear++;
      arr[rear]=n;

}
//出队列
public  int getQueue(){
        //判断队列是否为空

    if(isEmpty()){
        //抛出异常
        throw new RuntimeException("队列空,不能取数据");
    }
    front++;
    return arr[front];
}
//显示队列所有数据
public void showQueue(){
 if(isEmpty()){
     System.out.println("队列为空,没有数据");
     return;
 }
   for(int i=0;i<arr.length;i++){
       System.out.printf("arr[%d]=%d\n",i,arr[i]);
   }
}
//显示队列的头数据,并非取数据
public int headQueue(){
        if(isEmpty()){
            //System.out.println("队列为空");
            throw new RuntimeException("队列为空");
        }
        return arr[front+1];
    }
}

The results of the operation are:

 s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
s
队列为空,没有数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
a
请输入一个数
12
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
a
请输入一个数
23
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
a
请输入一个数
32
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
s
arr[0]=12
arr[1]=23
arr[2]=32
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
g
去除的数据为12
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
h
头部的数据为23
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据

Realization idea two:

package DataStrtureDemo;

import java.util.LinkedList;

/**
 * Created with IntelliJ IDEA.
 * User:  yongping Li
 * Date: 2020/11/20
 * Time: 8:57
 * Description: No Description
 */
public class arrayQueueDemo {
    public static void main(String[] args) {
        ArrayQueue queue = new ArrayQueue(5);
        queue.printAll();
        System.out.println(queue.isFull());
        //queue.enQueue(6);
        System.out.println(queue.isEmpty());



    }
}

class ArrayQueue{
    private int first,last,size;
    private Object[]  storage;

    public ArrayQueue(){
        this(100);
    }
    public ArrayQueue(int n){
        size=n;
        storage=new Object[size];
        first=last=-1;
    }
    public boolean isFull(){
        return first==0 && last==size-1||first==last+1;
    }
    public boolean isEmpty(){
        return first==-1;
    }
    //队列尾部添加元素
    public void enQueue(Object e){
        if(last==size-1||last==-1){
            storage[0]=e;
            last=0;
            if(first==-1){
                first=0;
            }
        } else{
            storage[++last]=e;
        }
    }
    //从队列中取出元素
    public Object  dequeue(){
        Object tmp=storage[first];
        if(first==last){
            last=first=-1;
        }else if(first==size-1){
            first=0;
        }else {
            first++;
        }
        return tmp;
    }
    public void printAll(){
        for(int i=0;i<size;i++){
            System.out.println(storage[i]+"   ");
        }
    }



}

class  Queue{
    private LinkedList list=new  LinkedList();

    //构造器
    public Queue(){

    }
    public boolean isEmpty(){
        return list.isEmpty();
    }
    //第一个元素
    public Object firstEl(){
        return list.getFirst();
    }
//获取最后一个元素
    public Object  lastEl(){
        return list.getLast();
    }
    public Object dequeue(){
        return list.removeFirst();
    }
    public void enqueue(Object e){
        list.addLast(e);
    }
    public String toString(){
        return list.toString();
    }
}

The results of the operation are:

null   
null   
null   
null   
null   
false
true

Process finished with exit code 0

 

(4) Thinking analysis and code implementation of circular queue

Reasons for using circular queues:

(1) At present, the queue can be used only once, and reuse cannot be achieved

(2) Design a circular queue and take the modulus%

 If the team head pointer will point to a higher subscript position, as shown below:

  

  When new data is added to the queue, the rear pointer at the end of the queue will move upward, that is, in the downward direction. When the data item is removed, the front pointer of the line head moves upward. So this design seems to be contrary to the reality, such as queuing to buy movie tickets, the head of the team will leave after buying the tickets, and then the team will move forward as a whole. It is also possible to delete a number in the queue on the computer, and the whole queue moves forward, but this is very inefficient. The way we choose is to move the pointers at the head and tail of the team.

 If you move the pointer in this way, I believe that the tail pointer of the team will soon move to the end of the data. At this time, the data may have been removed, then there will be an empty position at the head of the team, and then a new data item will come, because the end of the team cannot Moving up again, what should I do? As shown below:

  

  In order to avoid the queue being dissatisfied but not being able to insert new data, we can make the tail pointer wrap around back to the beginning of the array, which is also called a "circular queue".

  

That is as shown below:

Implementation considerations of circular queues:

1. Adjust the meaning of the front variable: front points to the first element of the queue, that is, arr[front] is the first element of the queue

2. Adjust the meaning of the rear variable: rear points to the element after the last element of the queue, because it hopes to free up a space as a convention (the actual capacity of the queue = maxSize-1, which is understood to prevent errors from pointing to places beyond the array range) .

3. When the queue is full, the condition is: (rear + 1)% maxSize == front [full] 

4. When the queue is empty, the condition is: rear == front [empty]

5. The number of valid data in the queue: (rear + maxSize-front)% maxSize

6. When inserting into the queue, judge that the queue is full, first insert into the queue arr[rear], then rear++

7. When moving out of the queue, judge the team is empty, first move out of the queue arr[front], then front++

In summary: The design idea of ​​the circular queue is:

The code for the circular queue is implemented as:

package JAVADATASTRTUCRE;

import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * User:  yongping Li
 * Date: 2020/11/16
 * Time: 21:24
 * Description: No Description
 */
public class circleArrayQueueDemo {
    public static void main(String[] args) {
        System.out.println("测试数组环形队列");
        circleArrayQueue arrayQueue = new circleArrayQueue(3);
        char key;//接受用户输入
        Scanner scanner =new Scanner(System.in);
        boolean loop=true;
        while(loop){
            System.out.println("s(show):显示队列");
            System.out.println("e(exit):退出程序");
            System.out.println("a(add):添加数据到队列");
            System.out.println("g(get):从队列中取数据");
            System.out.println("h(head):查看队列头部数据");
            key=scanner.next().charAt(0);
            switch (key){
                case 's':
                    arrayQueue.showQueue();
                    break;
                case 'a':
                    System.out.println("请输入一个数");
                    int value=scanner.nextInt();
                    arrayQueue.addQueue(value);
                    break;
                case 'g':
                    try{
                        int res =arrayQueue.getQueue();
                        System.out.println("去除的数据为"+res);
                    }catch(Exception E){
                        System.out.println(E.getMessage());
                    }
                    break;
                case 'h':
                    try{
                        int head =arrayQueue.headQueue();
                        System.out.println("头部的数据为"+head);
                    }catch(Exception E){
                        System.out.println(E.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop=false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出!!!!");
    }
}

class circleArrayQueue{

    private int maxSiaze;//队列的最大容量
    private int front;//队列头部,指向队列第一个元素,初始值为0
    private int rear;//队列尾部,指向对列最后一个元素的最后一个位置,初始值为0
    private int []arr;//用于1存放数据,模拟队列

    //创建队列的构造器
    public circleArrayQueue(int arrMaxSize){
        maxSiaze=arrMaxSize;
        arr=new int[maxSiaze];

    }

    //判断队列是否满
    public  boolean isFull(){
        return (rear+1)%maxSiaze==front;
    }
    //判断队列是否为空
    public boolean isEmpty(){
        return rear==front;
    }
    //添加数据到队列
    public void addQueue(int n){
        //判断队列是否满
        if(isFull()){
            System.out.println("队列已满,");
            return;
        }
        arr[rear]=n;
        //将rear后移,取模
        rear=(rear+1) % maxSiaze;

    }
    //出队列,取数据
    public  int getQueue(){
        //判断队列是否为空
        if(isEmpty()){
            //抛出异常
            throw new RuntimeException("队列空,不能取数据");
        }
        //分析front指向队列第一个元素
        //1,front保存到一个临时变量 2.临时保存的变量返回
        //3,front后移,考虑取模
        int value=arr[front];
        front=(front+1)%maxSiaze;
        return value;
    }
    //显示队列所有数据
    public void showQueue(){
        if(isEmpty()){
            System.out.println("队列为空,没有数据");
            return;
        }
        //从front开始便利,遍历多少个元素
        for(int i=0;i<front+getQueueSize();i++){
            System.out.printf("arr[%d]=%d\n",i%maxSiaze,arr[i%maxSiaze]);
        }
    }
    //显示队列的头数据,并非取数据
    public int headQueue(){
        if(isEmpty()){
            //System.out.println("队列为空");
            throw new RuntimeException("队列为空");
        }
        return arr[front];
    }

    //返回当前队列有效数据的个数
    public int getQueueSize(){
        return (rear+maxSiaze-front)%maxSiaze;
    }

}

The results of the operation are:

测试数组环形队列
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
s
队列为空,没有数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
a
请输入一个数
12
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
a
请输入一个数
34
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
a
请输入一个数
234
队列已满,
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
s
arr[0]=12
arr[1]=34
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
h
头部的数据为12
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
g
去除的数据为12
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
s
arr[0]=12
arr[1]=34
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
g
去除的数据为34
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
g
队列空,不能取数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
a
请输入一个数
1
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据
s
arr[0]=12
arr[1]=34
arr[2]=1
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(get):从队列中取数据
h(head):查看队列头部数据

(5) Summary

The queue is a linear table that stores data in accordance with the first-in first-out principle. It is usually used to simplify the data structure of certain program operations, rather than mainly for storing data. For queues, adding, deleting, modifying, and checking can be implemented through arrays. The purpose of designing circular lists is the repeated use of arrays.

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/weixin_41792162/article/details/109906039