数据结构之队列

队列简介
队列是一种特殊的线性表,只允许在表的前端(front)进行删除操作,表后端(rear)进行插入操作。进行删除操作的位置叫做对头,进行插入操作的位置叫做队尾。

特性
FIFO-First In First Out,先进先出存储数据。

队列实现主要分为顺序队列和循环队列。

  • 顺序队列

建立顺序队列结构必须为其静态或者动态分配一片的连续存储空间,并且设置两个指针进行管理,一个是对头指针front,一个是队尾指针rear。
初始化队列时,rear=front=0,每次新增元素,rear增1;每次删除元素,front增1。随着新增和删除操作的依次进行,队列元素的个数不断变化,队列所占用的存储空间也在为队列结构所分配的空间中移动。当rear增加到指向分配的连续空间之外时,队列无法在插入元素,但这时往往还有大量的可用空间未被占用,这些空间是已经出队的队列元素曾经占用过的存储单元。
顺序队列的溢出情况:
1)“下溢”现象:当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用于程序控制转义的条件。
2)“真上溢”现象:当队列满时,做入队运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
3)“假上溢”现象:由于入队和出队操作中,头尾指针只增加不减少,导致被删除元素所占用过的空间无法被重新利用。当队列中实际的元素个数小于存储空间规模时,也可能由于尾指针已经到达存储空间的上界点而不能做入队操作。该现象称之为“假上溢”现象。

图示

顺序队列java代码数组实现

点击查看代码
/**
 * 数据实现顺序队列,包含isFull()、isEmpty()、insert()、remove()、peekFront()基本操作。
 * @date 2021/12/24
 */
@Data
@Slf4j
public class SequentialQueue {
    /** 队列最大值 */
    private int maxSize;
    /** 数组实现 */
    private Object[] queueArray;
    /** 队头 */
    private int front;
    /** 队尾 */
    private int rear;

    public SequentialQueue(int maxSize) {
        this.maxSize = maxSize;
        this.queueArray = new Object[maxSize];
        this.front = 0;
        this.rear = 0;
    }

    /** 队列是是否已满 */
    public boolean isFull() {
        return rear == maxSize;
    }
    /** 队列是否为空 */
    public boolean isEmpty() {
        return rear == 0;
    }
    /** 入队 */
    public void insert(Object object) {
        // 队尾是否是最大值
        boolean isFull = this.isFull();
        if (isFull) {
            log.error("队列已满,入队失败。");
        } else {
            queueArray[rear] = object;
            rear++;
        }
    }
    /** 出队,删除数据,对头后移 */
    public void remove() {
        if (this.isEmpty()) {
            log.error("队列已空,出队失败。");
        } else {
            queueArray[front] = null;
            front++;
        }

    }
    /** 出队,删除数据,对头后移 */
    public Object peekFront() {
        return this.queueArray[front];
    }

    public static void main(String[] args) {
        SequentialQueue queue = new SequentialQueue(3);
        queue.insert(10);
        queue.insert(23);
        queue.insert(34);
        log.info("入队后对头值,num = {}", queue.peekFront());
        queue.remove();
        log.info("出队后对头值,num = {}", queue.peekFront());
    }
}
  • 循环队列

在实际使用队列时,为了能使队列空间得到重复使用,往往会对队列的使用方法稍加改进。无论插入或删除操作,一旦rear指针或front指针增加1时超过了所分配的存储空间,就让它们指向存储空间的起始位置。指针从maxSize-1增1变为0,可用取余运算rear%maxSize和front%maxSize来实现。
实际上就是把队列空间想象成环形空间,在空间中的存储单元循环使用,用这种方法管理的队列就是循环队列。除了一些简单应用之外,真正实用的队列就是循环队列。
图示

循环队列Java数据实现

点击查看代码
/**
 * 数组实现循环队列,包含insert()、remove()、peekFront()、isFull()和isEmpty()方法。
 * @author Yoko
 */
@Data
@Slf4j
public class LoopQueue {
    /** 队头 */
    private int front;
    /** 队尾 */
    private int rear;
    /** 实现数组 */
    private Object[] queueArray;
    /** 数组长度 */
    private int maxSize;
    /** 实际数据量 */
    private int nItem;

    public LoopQueue(int maxSize) {
        this.maxSize = maxSize;
        this.queueArray = new Object[maxSize];
        this.front = 0;
        this.rear = 0;
        this.nItem = 0;
    }

    /** 队列是否为空 */
    public boolean isEmpty() {
        return this.nItem == 0;
    }
    /** 队列是否已满 */
    public boolean isFull() {
        return this.nItem == this.maxSize;
    }
    /** 入队 */
    public void insert(Object object) {
        if (this.isFull()) {
            log.info("队列已满,入队失败。");
        } else {
            this.queueArray[rear] = object;
            this.rear = (this.rear + 1) % this.maxSize;
            this.nItem++;
        }
    }
    /** 出队 */
    public void remove() {
        if (this.isEmpty()) {
            log.info("队列已空,出队失败。");
        } else {
            this.queueArray[front] = null;
            this.front = (this.front + 1) % this.maxSize;
            this.nItem--;
        }
    }
    /** 查看队头的值 */
    public Object peekFront() {
        if (!this.isEmpty()) {
            return this.queueArray[front];
        }
        return null;
    }

    public static void main(String[] args) {
        LoopQueue queue = new LoopQueue(4);
        queue.insert(155);
        queue.insert(10);
        queue.insert(2);
        log.info("入队后数据:loopArray = {}", queue);
        log.info("对头的值:front= {}", queue.peekFront());

        queue.remove();
        log.info("出队后,queueArray = {}", queue);
        log.info("出队后,对头的值:front= {}", queue.peekFront());
        queue.insert(223);
        queue.insert(15);
        queue.insert(190);
        log.info("再次入队后数据:loopArray = {}", queue);
    }
}
posted @ 2021-12-30 15:50  梨猫南北  阅读(212)  评论(0编辑  收藏  举报