数组实现普通队列和环形队列

单向队列和循环队列


前言

本文主要介绍队列这种数据结构,并介绍使用数组如何实现,供大家参考


一、队列是什么?

  这里引用百度百科介绍 : 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

  从上面一段介绍中我们可以得到什么信息呢

  1. 队列是一种特殊的线性表
  2. 队列只允许在表的前段(front)删除,在表的后段(rear)插入

  一提到线性表大家首先会想到什么呢?对!数组,队列是一种特殊的线性表,换句话说,可以使用数组实现

二、实现思路和代码实现

实现思路

   我们先来一张数组实现队列的示意图:
在这里插入图片描述

如图中的示例,实现思路如下
1)根据队列的定义,可以得知,队列有两个特点,只允许在队列头进行删除(出队),在队列尾进行插入(入队),所以我们定义两个指针分别标示队列头(front)和队列尾(rear)
2) 插入元素(入队),由百度百科的定义我们可以得知,队列只能在尾端(rear)插入,插入元素(入队)的时候我们需要把尾指针+1,即rear+1,当然这里也要考虑队列满的情况,如果 rear+1=MaxSize-1,说明数组满了,不能再插入数据了
3) 删除元素,也是一样的,删除元素只能在队列头部进行,就是是头部指针front , 首先要考虑是否是空对列,如图所示,把指针初始化成-1,即front = rear的时候,队列是取不出元素的,如果不是队列不是空的话,我们把头指针+1,即front +1的位置,即可完成出队的操作

代码如下(示例):

package arr;


import java.util.Arrays;

public class MyQueueTest {

    public static void main(String[] args) {
        //初始化队列
        MyQueue queue = new MyQueue(4);
        System.out.println(queue.toString());
        //添加第一个元素
        queue.addQueue("1");
        System.out.println(queue.toString());
        //把队列加满
        queue.addQueue("2");
        queue.addQueue("3");
        queue.addQueue("4");
        System.out.println(queue.toString());
        //继续添加会抛出异常
//        queue.addQueue("5");

        //取出第一个元素
        System.out.println(queue.takeQueue());
        System.out.println(queue.toString());
        //取出所有元素
        System.out.println(queue.takeQueue());
        System.out.println(queue.takeQueue());

        //继续取出会提示队列为空
//        System.out.println(queue.takeQueue());
        System.out.println(queue.toString());

        //取出所有元素之后再添加元素,仍会抛出异常
        queue.addQueue("5");
    }
}


class MyQueue{

    private static final int DEFAULT_SIZE = 16;

    private int front;
    private int rear;
    private String[] arr;
    private int size;

    /**
     * 初始化默认大小的队列
     */
    public MyQueue(){
        this.front = -1;
        this.rear = -1;
        this.arr = new String[DEFAULT_SIZE];
    }

    /**
     * 初始化制定大小的队列
     */
    public MyQueue(int maxSize){
        this.size = maxSize;
        this.front = -1;
        this.rear = -1;
        this.arr = new String[size];
    }

    /**
     * 判断对列是否为空
     */
    public boolean isEmpty(){
        return this.front == this.rear;
    }
    /**
     * 判断队列是否满
     */
    public boolean isFull(){
        return rear == arr.length -1;
    }

    /**
     * 入队操作
     */
    public void addQueue(String element){
        if(isFull()){
            throw new RuntimeException("队列已满! 无法继续添加元素!");
        }
        this.arr[++ rear] = element;
    }

    /**
     * 出队操作
     */
    public String takeQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        String element = this.arr[++ front];
        this.arr[front] = null;
        return element;
    }

    @Override
    public String toString() {
        return "MyQueue{" +
                "front=" + front +
                ", rear=" + rear +
                ", arr=" + Arrays.toString(arr) +
                ", size=" + size +
                '}';
    }
}

遗留问题

   大家运行上面代码可以比较清晰的看到数组实现队列,模拟入队,出队操作。但是在代码的最后一行,把队列元素全部取出之后,还是没法继续再添加元素。也就是说上面实现的这个队列是一次性的。还需要继续优化,这样就有了环形队列,可以重复使用的队列。

三、环形队列

环形队列实现思路

   环形队列是可以循环使用的,是上面实现队列的一个加强版,话不多说,直接上图 :
在这里插入图片描述

如图中的示例,是环形队列的逻辑结构,内存结构还是普通队列的图示,为了方便理解,把首尾连接,看到就是这个样子。下面开始分析实现思路
1) 对环形队列而言,会遇到第一个问题,怎么判断队列空和队列满?从图中可以想象的出来,队列空和满如果都是rear = front, 这样肯定有问题。这里有两种判断思路,一种是空出一个位置,不存放元素,头指针front和尾指针rear只要有元素存在就不会重合,这也是最常用的一种方式;另外一种是重新引入一个变量,可以通过计算队列中元素的个数加上指针位置来判断。这里的实现是采用第一种方式,先对指针含义做一个调整:front指向第一个元素;rear指向数组最后一个元素的后一个位置,这样我们就可以空出一个位置,判断队列是否满
2)当队列为空时(左图) front == rear; 当队列满时(右图),代码如下

if(rear + 1 == maxSize){
	rear = 0;
|else{
	rear = rear + 1;
}

使用模运算转换一下 : ( rear + 1) % maxSize = front;
3) 队列中元素的个数也根据图示何以推算出来 (rear - front + maxSize) % maxSize
4)出队和入队操作也是一样的可以使用模运算来处理

代码如下(示例):

package arr;

import java.util.Arrays;

public class MyCircularQueueTest {

    public static void main(String[] args) {
        //初始化队列
        MyCircularQueue queue = new MyCircularQueue(4);
        System.out.println(queue.toString());
        //添加第一个元素
        queue.addQueue("1");
        System.out.println("队列的长度 : "+queue.getLength() + " 队列 : " +  queue.toString());
        //把队列加满
        queue.addQueue("2");
        queue.addQueue("3");
        System.out.println("队列的长度 : "+queue.getLength() + " 队列 : " +  queue.toString());
        //继续添加会抛出异常
//        queue.addQueue("5");

        //取出第一个元素
        System.out.println(queue.takeQueue());
        System.out.println("队列的长度 : "+queue.getLength() + " 队列 : " +  queue.toString());
        //取出所有元素
        System.out.println(queue.takeQueue());
        System.out.println(queue.takeQueue());

        //继续取出会提示队列为空
//        System.out.println(queue.takeQueue());
        System.out.println("队列的长度 : "+queue.getLength() + " 队列 : " +  queue.toString());

        //取出所有元素之后再添加元素,仍会抛出异常
        queue.addQueue("5");

        System.out.println("队列的长度 : "+queue.getLength() + " 队列 : " +  queue.toString());
    }
}

class MyCircularQueue{

    private static final int DEFAULT_SIZE = 16;

    private int front;
    private int rear;
    private String [] arr;
    private int maxSize;

    public MyCircularQueue(int maxSize) {
        this.front = 0;
        this.rear = 0;
        this.maxSize = maxSize;
        arr = new String[maxSize];
    }

    /**
     * 队列是否为空
     */
    public boolean isEmpty(){
        return front == rear;
    }

    /**
     * 对列是否已满
     */
    public boolean isFull(){
        return (rear + 1) % maxSize == front;
    }

    /**
     * 环形队列中数组的元素
     */
    public int getLength(){
        return (rear - front + maxSize) % maxSize;
    }

    /**
     * 入队
     */
    public void addQueue(String element){
        if(isFull()){
            throw new RuntimeException("队列已满!");
        }
        arr[rear] = element;
        rear = (rear + 1) % maxSize ;
    }

    /**
     * 出队
     */
    public String takeQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空!");
        }
        String result = arr[front];
        arr[front] = null;
        front = ( front + 1 ) % maxSize;
        return result;
    }

    @Override
    public String toString() {
        return "MyCircularQueue{" +
                "front=" + front +
                ", rear=" + rear +
                ", arr=" + Arrays.toString(arr) +
                ", maxSize=" + maxSize +
                '}';
    }
}


总结

以上就是使用数组实现队列的具体思路和代码实现,欢迎大家参考!有任何想法随时可以交流,有不对的地方欢迎指正!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值