第02篇 队列

一、介绍

队列是一种先进先出的有序数据结构,可以用数组或者链表来实现。
总的来说,数组模拟队列有两种情况

  1. 简单队列。当添加到最后一个位置的时候,队列就不能使用了
  2. 环形队列。当数组添加到最后一个位置的时候,如果前面因为取出元素有了空的位置,可以重复利用空出的位置。

我们可以通过很多方式来实现队列,比较常见的有数组和链表来实现

二、数组实现简单队列

(一)思路分析

使用数组来模拟队列也就是说把数据存放在数组中,实现思路如下:

  1. 定义的数据结构如下:
    public class ArrayQueue {
      private int capacity;
      private Object[] data;
      private int putIndex;
      private int takeIndex;
    
    各个字段的含义如下:
    capacity:可以存放的元素的个数,也就是数组的长度
    data:用来存放元素的数组
    putIndex:下一个可以放入元素的下标;
    takeIndex:下一个能获取到元素的下标;
  2. 初始的时候putIndex和takeIndex都为0,表示没有任何元素,结构如下:
    在这里插入图片描述
  3. 加入元素之后,按照我们1里面putIndex的含义,下一个可以放入的元素下标应该+1,比如,当我们加入一个元素后,那么下一个可以放入的元素下标就是1了,当加入三个元素后,效果如下(红色背景表示已经存放了元素):
    在这里插入图片描述
  4. 当取出元素的时候,会从头部取,这个时候,takeIndex下标后移,效果如下:
    在这里插入图片描述
  5. 当putIndex到5的后面(就是最大容量capicity)的时候,表明已经满了,不能再添加元素
  6. 当takeIndex和putIndex相等的时候,表明队列已经空了,不能再取元素

(二)代码实现

package com.firewolf.javabase.s002_queue;

/**
 * 不可复用的队列----使用数组实现。一旦添加满了,即便取走了前面的元素,也不能再添加元素
 */
public class ArrayQueue {

  /**
   * 默认容量为10
   */
  private static final Integer DEFAULT_CAPICITY = 10;
  /**
   * 队列容量
   */
  private int capacity;

  /**
   * 存放数据的容器
   */
  private Object[] data;

  /**
   * index for next put
   */
  private int putIndex;

  /**
   * index for next put
   */
  private int takeIndex;

  public ArrayQueue(int capacity) {
    this.capacity = capacity;
    data = new Object[this.capacity];
  }

  public ArrayQueue() {
    this(DEFAULT_CAPICITY);
  }

  /**
   * 添加元素到队列尾部
   *
   * @param el 要加入的元素
   * @return 添加成功返回true, 否则返回false
   */
  public boolean addElement(Object el) {
    if (isFull()) {
      System.out.println("队列已经满了");
      return false;
    }
    data[putIndex++] = el;
    return true;
  }

  /**
   * 获取头部元素
   */
  public Object getElement() {
    if (isEmpty()) {
      System.out.println("没有可以获取的元素了");
      return null;
    }
    return data[takeIndex++];
  }


  /**
   * 显示所有的队列元素
   */
  public void showElements() {
    for (int i = takeIndex; i < putIndex; i++) {
      System.out.println(data[i]);
    }
  }


  /**
   * 获取元素个数
   */
  public int size() {
    return putIndex - takeIndex;
  }


  /**
   * 是否满了
   */
  public boolean isFull() {
    return putIndex == capacity;
  }

  /**
   * 是否为空
   */
  public boolean isEmpty() {
    return takeIndex == putIndex;
  }
}

三、数组实现环形队列

环形队列要求能够对前面已经移除的元素位置进行复用,也就是说当出现如下情况的时候,并不能认为数组满了,从而能够继续添加元素。
在这里插入图片描述
如果是在简单队列里面,上面这种情况是队列已经满了,因为putIndex==capacity了,而实际上我们看的到0,1,2三个位置已经空出来了,我们可以循环利用,也就是说,下一个可以放元素的位置变成0就可以了,也就是说,应该形成如下结构:
在这里插入图片描述

(一)思路分析

  1. 构建如下数据结构
    public class CyclicArrayQueue {
      private int capacity;
      private Object[] data;
      private int count;
      private int putIndex;
      private int takeIndex;
    
    可以看到,相对于简单队列,多了一个count,各自含义如下:
    capacity:可以存放的元素的个数,也就是数组的长度
    data:用来存放元素的数组
    putIndex:下一个可以放入元素的下标;
    takeIndex:下一个能获取到元素的下标;
    count:队列中元素个数,方便能够判断队列空满情况,其实不要也是可以的,不过使用这个更加方便。
  2. 开始的时候,putIndex=takeIndex=0,count=0,此时没有任何元素,队列为空。
  3. 加入元素的时候,count加1,putIndex增加,如果putIndex==capacity了,证明到了数组的最后一个元素,那么下一个能存放数据的位置为0,总结为:putIndex = (putIndex+1)%capacity。
  4. 获取元素的时候,count减1,同时takeIndex增加,同样的,如果到了takeIndex==capacity,那么也要回到队列的头部。总结为:takeIndex = (takeIndex+1)%capacity。
  5. count==0的时候,表示队列为空,此时不能获取元素。
  6. count==capacity的时候,表示队列满了,不能加入元素。

(二)代码实现

package com.firewolf.javabase.s002_queue;

/**
 * 可以循环复用的队列----数组实现
 */
public class CyclicArrayQueue {

  /**
   * 默认容量为10
   */
  private static final Integer DEFAULT_CAPICITY = 10;
  /**
   * 队列容量
   */
  private int capacity;

  /**
   * 存放数据的容器
   */
  private Object[] data;

  /**
   * 已经存放的元素个数
   */
  private int count;

  /**
   * index for next put
   */
  private int putIndex;

  /**
   * index for next take
   */
  private int takeIndex;

  public CyclicArrayQueue(int capacity) {
    this.capacity = capacity;
    data = new Object[this.capacity];
  }

  public CyclicArrayQueue() {
    this(DEFAULT_CAPICITY);
  }

  /**
   * 添加元素到队列尾部
   *
   * @param el 要加入的元素
   * @return 添加成功返回true, 否则返回false
   */
  public boolean addElement(Object el) {
    if (isFull()) {
      System.out.println("队列已经满了");
      return false;
    }
    count++; //元素数量+1
    data[putIndex] = el; //放入元素
    putIndex = (putIndex + 1) % capacity; //更新索引
    return true;
  }

  /**
   * 获取头部元素
   */
  public Object getElement() {
    if (isEmpty()) {
      System.out.println("没有可以获取的元素了");
      return null;
    }
    Object value = data[takeIndex]; //获取到元素
    count--;//更新元素数量
    takeIndex = (takeIndex + 1) % capacity;//更新索引
    return value;
  }


  /**
   * 显示所有的队列元素
   */
  public void showElements() {
    if (isEmpty()) {
      System.out.println("没有元素");
      return;
    }
    for (int i = takeIndex; i < takeIndex + count; i++) {
      System.out.println(data[i % capacity]);
    }
  }


  /**
   * 获取元素个数
   */
  public int size() {
    return count;
  }


  /**
   * 是否满了
   */
  public boolean isFull() {
    return count == capacity;
  }

  /**
   * 是否为空
   */
  public boolean isEmpty() {
    return count == 0;
  }
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值