Java数据结构-队列(顺序队列,循环队列)

1. 什么是队列?

  • 队列的定义:

    队列是一种操作受限的线性表,是指只允许在表的一端进行插入操作的数据结构

  • 队列的特点:

    1. 队列是一种先进先出(FIFO)的顺序结构。先存入的数据先取出,后存入的数据后取出。

    2. 在队尾插入元素,在队头删除元素
      Java数据结构-队列(顺序队列,循环队列)_第1张图片

2. 队列的分类

  • 顺序队列:

    1. 数组(顺序存储结构)实现的队列称为顺序队列
    2. front 指向队列第一个元素的前一个位置
    3. rear 指向队列的最后一个元素的位置
    4. 有效数据个数 = rear - front
  • 循环队列:

    1. 顺序队列的优化版,可以解决顺序队列的“假溢出现象”
    2. front 指向队列的第一个元素
    3. rear 指向队列的最后一个元素的后一个位置
    4. 有效数据个数 = (rear + capacity - front) % capacity
  • 链队列:

    1. front 指向队列的第一个元素
    2. rear 指向队列

    链表(链式存储结构)实现的队列称为链队列

  • 顺序队列和链队列的区别:

    1. 顺序队列一次性要分配大量保证够用的空间,效率较高,因为是基于数组的,长度也是固定的。所以可能会发生”假溢出现象“,解决方法就是将队列的数据区看成头尾相连的循环结构,称为”循环队列
    2. 链队列是基于链表的,要动态创建和删除节点,效率较低,但是可以动态增长

3. 顺序队列实现代码

//顺序队列
public class ArrayQueue {
    //模拟 c语言 中的头指针
    private int front;
    //模拟 c语言 中的尾指针
    private int rear;
    //初始化数组的最大容量
    private int capacity;
    //存放数据的数组,(可以存任何类)
    private Object[] arr;

    /**
     * 通过有参构造创建顺序队列
     * @param capacity 容量大小
     */
    public ArrayQueue(int capacity) {
        this.capacity=capacity;
        this.arr=new Object[capacity];
        //指向队列头部第一个数据的前一个位置,初始值为 -1
        this.front=-1;
        //指向队列尾部,初始值为 -1
        this.rear=-1;
    }

    /**
     * 判断队列是否满了
     * @return 返回布尔值(满 or 未满)
     */
    public boolean isFull(){
        return rear==capacity-1;
    }

    /**
     * 判断队列是否为空
     * @return 返回布尔值(空 or 非空)
     */
    public boolean isEmpty(){
        return front==rear;
    }

    /**
     * 入队列
     * @param obj 所以存放的数据
     */
    public void add(Object obj){
        //先判断队列是否满了
        if (isFull()) {
            System.out.println("队列已满,不能再添加数据...");
        }else {
            // ++rear 是让尾指针后移一位,并且可以作为数组的下标
            arr[++rear]=obj;
        }
    }

    /**
     * 出队列
     * @return 返回出队的数据
     */
    public Object poll(){
        //先判断队列是否为空,空的话则不能取出数据
        if (isEmpty()) {
            //有返回值的方法,必须得抛异常,不然提示后还得return一个数据,这样我们也无法确定到底是取出的数据还是提示的数据
            throw new RuntimeException("队列为空,不能取出数据...");
        }else {
            //返回出队的数据
            return arr[++front];
        }
    }

    /**
     * 显示队列的所有数据
     */
    public void show(){
        //判断队列是否为空
        if (isEmpty()) {
            System.out.println("队列为空...");
        }else {
            for (int i = front+1; i < rear+1; i++) {
                System.out.print(arr[i]+"\t");
            }
        }
    }

    /**
     * 查看队列的第一个数据,不是出队
     * @return 队列的第一个数据
     */
    public Object head(){
        //判断队列是否为空
        if (isEmpty()) {
            //有返回值的方法,必须得抛异常,不然提示后还得return一个数据,这样我们也无法确定到底是取出的数据还是提示的数据
            throw new RuntimeException("队列为空...");
        }else {
            return arr[front+1];
        }
    }

}

4. 循环队列的实现代码

//循环队列
public class CircleQueue {
    //模拟 c语言 中的头指针
    private int front;
    //模拟 c语言 中的尾指针
    private int rear;
    //初始化数组的最大容量
    private int capacity;
    //存放数据的数组,(可以存任何类)
    private Object[] arr;

    /**
     * 通过有参构造创建顺序队列
     * @param capacity 容量大小
     */
    public CircleQueue(int capacity) {
        this.capacity=capacity;
        //在队列尾部预留一个空间,形成约定
        this.arr=new Object[capacity+1];
        //指向队列头部的第一个数据,初始值为 0
        this.front= 0;
        //指向队列尾部最后一个数据的后一个位置,初始值为 0
        this.rear = 0;
    }

    /**
     * 判断队列是否满了
     * @return 返回布尔值(满 or 未满)
     */
    public boolean isFull(){
        //只有当头指针和尾指针紧挨着时,队列才是满的(想一下环形结构)
        return (rear+1)%(capacity+1)==front;
    }

    /**
     * 判断队列是否为空
     * @return 返回布尔值(空 or 非空)
     */
    public boolean isEmpty(){
        return front==rear;
    }

    /**
     * 入队列
     * @param obj 所以存放的数据
     */
    public void add(Object obj){
        //先判断队列是否满了
        if (isFull()) {
            System.out.println("队列已满,不能再添加数据...");
        }else {
            // 直接将数据加入
            arr[rear]=obj;
            //将尾指针后移一位,为下次入队做准备
            rear = (rear+1)%(capacity+1);
        }
    }

    /**
     * 出队列
     * @return 返回出队的数据
     */
    public Object poll(){
        //先判断队列是否为空,空的话则不能取出数据
        if (isEmpty()) {
            //有返回值的方法,必须得抛异常,不然提示后还得return一个数据,这样我们也无法确定到底是取出的数据还是提示的数据
            throw new RuntimeException("队列为空,不能取出数据...");
        }else {
            //用临时变量保存要出队的数据
            Object target = arr[front];
            //将头指针后移一位,为下次出队做准备
            front = (front+1)%(capacity+1);
            //返回要出队的数据
            return target;
        }
    }

    /**
     * 显示队列的所有数据
     */
    public void show(){
        //判断队列是否为空
        if (isEmpty()) {
            System.out.println("队列为空...");
        }else {
            //利用 size()方法求出有效数据个数,这样就知道应该遍历几次了
            for (int i = front; i < front + size(); i++) {
                System.out.print(arr[i]+"\t");
            }
        }
    }

    /**
     * 查看队列的第一个数据,不是出队
     * @return 队列的第一个数据
     */
    public Object head(){
        //判断队列是否为空
        if (isEmpty()) {
            //有返回值的方法,必须得抛异常,不然提示后还得return一个数据,这样我们也无法确定到底是取出的数据还是提示的数据
            throw new RuntimeException("队列为空...");
        }else {
            return arr[front];
        }
    }

    /**
     * 求循环队列的有效数据个数
     * @return 有效数据个数
     */
    public int size(){
        return (rear+(capacity+1)-front)%(capacity+1);
    }

}

你可能感兴趣的:(Java-数据结构与算法)