Java队列--顺序队列与链式队列(画图理解)

Java队列

1.概念

​ 队列是一种数据结构。队列的作用就像电影院前的人们站成的排一样:第一个进入窗口的人将最先到达队头买票。最后排队的人最后才能买到票。

2.特性

队列就是一个只允许在一端进行插入,在另一端进行删除操作的线性表。

先进先出(FIFO)

三个基本操作:

  • 从尾部(rear)添加元素
  • 从其(front)头部移除元素
  • 在元素顶部查看
方法描述
boolean add(E e)如果可能,向队列中添加一个元素。否则,它抛出异常。
boolean offer(E e)如果不能添加元素,则将元素添加到队列中,而不抛出异常。 它在失败时返回false,在成功时返回true。
E remove()删除队列的头。如果队列为空,它会抛出异常。此方法返回已移除的项目。
E poll()从队列中删除元素。如果队列为空而不是抛出异常,则返回null。
Eelement()偷看队列的头,而不从队列中删除它。 如果队列为空,它会抛出异常。
E peek()查看队列,如果队列为空而不是抛出异常,则返回null。

3.分类

按照存储方式

  • 基于数组的顺序存储方式
  • 基于链表的链式存储方式
3.1 基于数组的顺序队列
简要理解:

顺序队列和栈的不同

  • :在同一端进栈出栈
  • 顺序队列:在一端进行插入,在另一端进行删除操作

插入队列值
在这里插入图片描述 删除队列值

数据项被移除后,同时队头指针增加一。通常实现队列时,删除的数据项还会保存在内存中,只是它不能被访问了,因为队头指针已经移到它的下一个位置了。

在这里插入图片描述

假溢出 现象:
在这里插入图片描述
实现顺序队列时,是头front和尾rear分别进行出队和入队操作,当尾部插入速度小于头部删除速度时,出现rear==front的现象,但此时队列并没有满,而是队列为空,存储空间最大,但继续插入元素时,rear值已经到达MAXSIZE边界条件,此时无法插入也无法删除。

解决办法可以使用循环队列。循环队列在判断指针位置可以使用rear = (rear + 1) % this.maxSize;front = (front + 1) % this.maxSize;(示例代码中的添加与删除方法)。

  • 循环队列的队满和队空
    由于队满和队空条件都是front = rear,所以队满时损失一个空间。
    在这里插入图片描述
示例代码:

import java.util.Arrays;

/**
 * 顺序队列实现
 *
 * @Author swd
 * @Create 2020/8/7 0007 16:17
 */
public class OrderQueue<T> {

    private T[] datas; //数组模拟队列
    private int maxSize; //队列元素个数
    private int front; //队列中第一个对象位置
    private int rear; //队列中当前对象位置

    public OrderQueue(int maxSize) {
        if (maxSize < 1) {
            maxSize = 1;
        }
        this.maxSize = maxSize;
        this.datas = (T[]) new Object[this.maxSize];//初始化数组必须放到上一行之后
        this.front = 0;
        this.rear = 0;
    }

    //队列的状态 队空 & 队满
    public boolean isNull() {
        if (this.front == this.rear)
            return true;
        else
            return false;
    }

    public boolean isFull() {
        if ((rear + 1) % this.maxSize == front)
            return true;
        else
            return false;
    }

    //添加
    public boolean offer(T data) {
        if (isFull()) {
            return false;//队满
        } else {
            this.datas[this.rear] = data;
            this.rear = (this.rear + 1) % this.maxSize; //队尾指针 +1
            return true;
        }
    }

    //删除
    public T poll() {
        if (isNull()) {
            return null;//队空
        } else {
            T pollData = this.datas[front];
            this.front = (this.front + 1) % this.maxSize; //队头指针 +1
            return pollData;
        }
    }

    //get/set

    public T[] getDatas() {
        return datas;
    }

    public void setDatas(T[] datas) {
        this.datas = datas;
    }

    public int getMaxSize() {
        return maxSize;
    }

    public void setMaxSize(int maxSize) {
        this.maxSize = maxSize;
    }

    public int getFront() {
        return front;
    }

    public void setFront(int front) {
        this.front = front;
    }

    public int getRear() {
        return rear;
    }

    public void setRear(int rear) {
        this.rear = rear;
    }

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

测试
public class TestResult {
    public static void main(String[] args) {
        OrderQueue<String> orderQueue = new OrderQueue<>(5);
        System.out.println("初始化:" + orderQueue.toString());
        System.out.println("队列是否为空:" + orderQueue.isNull());
        orderQueue.offer("a");
        orderQueue.offer("b");
        orderQueue.offer("c");
        orderQueue.offer("d");
        orderQueue.offer("e");//循环队列会减少1个空间,此数据插入不了
        System.out.println("插入数据:" + orderQueue.toString());
        //OrderQueue{datas=[a, b, c, d, null], maxSize=5, front=0, rear=4}

        System.out.println("队列是否已满:" + orderQueue.isFull());
        System.out.println(orderQueue.poll());
        System.out.println("删除1个数据:" + orderQueue.toString());
        System.out.println(orderQueue.poll());
        System.out.println("删除2个数据:" + orderQueue.toString());
        System.out.println(orderQueue.poll());
        System.out.println("删除3个数据:" + orderQueue.toString());
        System.out.println(orderQueue.poll());
        System.out.println("删除4个数据:" + orderQueue.toString());
        System.out.println(orderQueue.poll());
        System.out.println("删除5个数据:" + orderQueue.toString());
    }
}

结果
在这里插入图片描述

3.2 基于链表的链式存储方式
简要理解:
  • 插入队列值
    在这里插入图片描述
  • 删除队列值
    在这里插入图片描述
示例代码
package test;

public class LinkQueue<T>{
    private QNode<T> front;//队头指针
    private QNode<T> rear;//队尾指针
    private int maxSize;//为了便于操作,使用这个变量表示链队的数据容量

    //初始化
    public LinkQueue(){
        this.front = new QNode<T>();
        this.rear = new QNode<T>();
        this.maxSize = 0;
    }

    //初始化队列
    public void initQueue(){
        front.next = null;
        rear.next = null;
        maxSize = 0;
    }

    //队空判断
    public boolean isNull(){
        if(front.next==null || rear.next==null)
            return true;
        else
            return false;
    }

    //进队
    public void push(QNode<T> node){
        if(isNull()){
            //第一次
            front.next = node;
            rear.next = node;
            maxSize++;
        }
        else{
            node.next = front.next;
            front.next = node;
            maxSize++;
        }
    }
    //出队
    public QNode<T> pop(){
        if(isNull())
            return null;//队为空时,无法出队
        else if(maxSize==1){
            //队只有一个元素时直接初始化即可
            QNode<T> node  = front.next;
            initQueue();
            return node;
        }
        else{
            //准备工作
            QNode<T> p = front;//使用p指针来遍历队列
            for(int i=1;i<maxSize-1;i++)
                p = p.next;
            //pop
            QNode<T> node = rear.next;
            rear.next = p.next;
            maxSize--;
            return node;
        }
    }

}

//链队结点
class QNode<T>{
    private T data;//数据域
    public QNode<T> next;//指针域

    //初始化1
    public QNode(){
        this.data = null;
        this.next = null;
    }
    //初始化2
    public QNode(T data){
        this.data = data;
        this.next = null;
    }

    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }

}
测试
package test;

import org.junit.Test;

public class testQueue {

    @Test
    public void fun(){
        LinkQueue<Integer> lq = new LinkQueue<Integer>();

        System.out.println("队列是否为空:"+lq.isNull());

        //依次插入1、2、3、4
        lq.push(new QNode<Integer>(1));
        lq.push(new QNode<Integer>(2));
        lq.push(new QNode<Integer>(3));
        lq.push(new QNode<Integer>(4));

        //依次出队
        System.out.println("依次出队:");
        while(!lq.isNull()){
            System.out.println(lq.pop().getData());
        }

    }
}

参考文章:
作者:风之之
https://www.cnblogs.com/fzz9/p/8159679.html
https://baijiahao.baidu.com/s?id=1637126358227832423&wfr=spider&for=pc
谢谢O(∩_∩)O

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值