队列 - 数组实现

队列的简介

  • 队列(Queue)是一个有序的列表,可以通过数组和链表的方式实现,队列都是遵循先进先出的原则,即FIFO。
  • 在JDK中的ArrayBlockingQueue类的底层实现就是通过数组来实现有序队列。

数组实现队列的流程

队列的本身是有序的列表,如果使用数组来存储队列数据,则队列声明入下图: 

在这里插入图片描述
putIndex用于标记元素插入的索引,默认初始化为0;
takeIndex用于标记元素被读取的索引,默认初始化为0;
我们需要将这个数组做成可以循环使用的容器。例如如下我们添加了4个元素,如下图:
在这里插入图片描述

这时候putIndex就=4,因为添加完以后,索引需要指向下一个元素的索引。但是这时候读取的索引依旧=0,没有变化,我们如下图,取出第一位:
在这里插入图片描述
这时候takeIndex=1,也是因为弹出之后,需要指向下一个弹出的元素索引。
这时候似乎还是看不出"循环使用"这个词的效果。不要着急,下图所示:
在这里插入图片描述
这是时我们再添加三个数据。这时候如果putIndex一直+1的话可能就会超过这个容器的长度,所以在添加的时候,我们需要做边界值的判断。如果超过容器长度,且容器未满,需要再将索引重置到0,从头部再依次添加。这样就达到了容器循环使用的效果。若容器已满,则不允许从头部再添加,否则会出现数据覆盖,此时应当给出提示,容器已满。

代码演示

以下是一个排队取号的小程序做了一个demo,仅供参考。
不足的地方还请各位指出。
下一篇将介绍链表实现队列。
public class ArrayQueue {

    /***
     * 存储数据
     */
   private Integer[] array;

    /***
     * 标记数组被读取的索引
     */
   private int takeIndex;

    /***
     * 标记数组添加后的索引
     */
   private int putIndex;

    /***
     * 队列中元素的个数
     */
   private int count;

   private ReentrantLock reentrantLock;

   public ArrayQueue(int initSize) {
       // 初始化数组容器
       array = new Integer[initSize];
       reentrantLock = new ReentrantLock();
   }

    /***
     * 添加数据
     * @param value
     */
   public void put(int value) {
       reentrantLock.lock();
       try {
           if (array.length == count) {
               System.out.println("队列已满...");
               putIndex = 0;
               return;
           }
           array[putIndex] = value;
           count++;
           if (++putIndex == array.length) {
               putIndex = 0;
           }
       }finally {
           reentrantLock.unlock();
       }
   }

    /***
     * 弹出数据
     * @return
     */
   public Integer poll() {
       reentrantLock.lock();
       try {
           if (count == 0) {
               System.out.println("队列为空...");
               return null;
           }
           Integer value = array[takeIndex];
           array[takeIndex] = null;
           count--;
           if (++takeIndex == array.length) {
               takeIndex = 0;
           }
           return value;
       }finally {
           reentrantLock.unlock();
       }
   }

    /***
     * 查看队列头部数据
     * @return
     */
   public Integer peek() {
       reentrantLock.lock();
       try {
           if (count == 0) {
               System.out.println("队列为空...");
               return null;
           }
           return array[takeIndex];
       }finally {
           reentrantLock.unlock();
       }
   }

    /***
     * 转为数组
     * @return
     */
   public Integer[] toArray() {
       reentrantLock.lock();
       try {
           if (count == 0) {
               System.out.println("队列为空...");
               return new Integer[0];
           }
           // 重新申请容器,将有效元素都拷贝到新的容器中返回
           Integer[] newArray = new Integer[count];
           // 获取takeIndex后元素个数
           int afterTakeIndexElement = array.length - takeIndex;
           // 判断有效的元素是否都在takeIndex索引之后, 有可能考虑到新添加的元素在takeIndex之前
           if (count <= afterTakeIndexElement) {
               // 数组拷贝
               System.arraycopy(array, takeIndex, newArray, 0, count);
           } else {
               // 此时的场景就是有效元素添加到了takeIndex之前,需要进行两次拷贝
               // 第一次拷贝takeIndex之后的有效元素
               System.arraycopy(array, takeIndex, newArray, 0, afterTakeIndexElement);
               // 第二次拷贝takeIndex之前的有效元素
               System.arraycopy(array, 0, newArray, afterTakeIndexElement, count - afterTakeIndexElement);
           }
           return newArray;
       }finally {
           reentrantLock.unlock();
       }
   }


    public static void main(String[] args) {
        ArrayQueue arrayQueue = new ArrayQueue(10);

        String tip = "取号请按[1]; 查看下一位号请按[2]; 查看当前总共排队号请按[3]; 检票请按[4]";

        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println(tip);
            int inputValue = scanner.nextInt();
            switch (inputValue) {
                case 1: {
                    arrayQueue.put(new Random().nextInt());
                    break;
                }
                case 2: {
                    System.out.println("下一位是: " + arrayQueue.peek() + "号");
                    break;
                }
                case 3: {
                    System.out.println("当前一共有如下排队: " + Arrays.toString(arrayQueue.toArray()));
                    break;
                }
                default: {
                    System.out.println("欢迎[" + arrayQueue.poll() + "]号");
                    break;
                }
            }
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值