使用数组来实现循环队列

文章目录

  • 队列
  • 队列的接口
  • 循环队列的实现

使用数组来实现循环队列

队列

我们知道,在计算机科学中,程序本质上就是数据结构加上算法。数据结构是计算机存储、组织数据的方式。一般来讲,数据结构按照数据的逻辑结构分为线性结构和非线性结构两种。几乎所有的线性结构都是建立在两种最基本的结构上的:内存中连续存储的数组结构以及内存中分散存储的链表结构。

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列是先进先出的线性结构,而栈(stack)是先进后出的线性结构。

队列作为一种线性结构,既可以使用数组来实现,也可以用链表进行实现,本文就用Java语言以数组为基础完成一个循环队列的实现。

队列的接口

基于队列的特点,我们简单的为我们的队列创建一个接口,规定该队列需要实现的方法。

package com.hebin.datastructure.queue;

public interface IQueue {
     
    public void add(int a);

    public int get();

    public void show();

}

我们创建的是一个存储int数字的队列,需要有从后端增加数字、从前端取出数字,查看队列元素等方法。

循环队列的实现

分析队列和数组的特点,我们知道,数组是无法变更大小的,并且数组元素下标必须从0开始,最大不能大于(数组数量-1)。

/**
 * 使用数组来实现循环队列,队列本质上是一个数组。
 * 队列的特点是先进先出,后进后出;增加元素添加到队列尾部,取出元素从头部获取。
 */
public class MyArrayQueue implements IQueue {
     
    // 队列的最大容量
    private int maxSize;
    // 循环队列的当前容量size;
    private int size;
    //循环队列的队头坐标,每次取出数据,该标志位向后移动一位,位于数组尾部时,移动到数组头部
    private int front;
    //循环队列的队尾坐标,每次增加数据,该标志位向后移动一位,位于数组尾部时,移动到数组头部
    private int end;
    // 队列的本体,是一个数组
    private int[] array;
    
     /**
     * 队列的构造函数
     * @param maxSize 指定队列的最大元素个数
     */
    public MyArrayQueue(int maxSize) {
     
        // 队列的初始大小为0
        this.size = 0;
        // 给定队列的最大容量
        this.maxSize = maxSize;
        // 为了防止数组越界异常,将数组元素位置array[0]作为冗余位,因此数组大小比队列的最大容量大1位。
        this.array = new int[maxSize + 1];
        // 初始化时,队列的队头和队尾标志位置零,一旦发生添加元素或者取出元素操作之后,这俩标志位将从1到maxSize之间循环变化。
        this.front = 0;
        this.end = 0;
    }
    
        /**
     * 判断循环队列是否已满。
     *
     * @return 如果队列已满,返回true,否则返回false。
     */
    private boolean isFull() {
     
        if (front == 0) {
     
            // 如果还未取过元素,那么end==maxsize时,队列已满。
            return end == maxSize;
        }

        // 如果队列取过元素,那么front一定不为0,循环队列已满,那么array[end]后一位一定是array[front]。
        return end % maxSize + 1 == front;//%为取模操作
    }

    /**
     * 判断队列是否空队列
     * @return 空队列返回true,否则返回false。
     */
    private boolean isEmpty() {
     
        // 如果队列没有取过元素,那么front=0,若队列是空队列,那么end没有下移,end==front==0.
        // 如果队列取过元素,那么队列的end和front一定不等于0,那么空队列则一定有end==front.
        return end == front;
    }
    
    // 队列方法的实现。
    
     @Override
    public void add(int a) {
     
        if (isFull()) {
     
            throw new RuntimeException("队列已满,无法添加数据");
        }
        /* 当队列没有满,添加元素时,首先end向下移动一位,然后给array【end】赋值。
           假如maxsize=3,而end=3,此时添加元素,end下移一位,因为array[0]为冗余位,因此end=1。
        */
        end = end % maxSize + 1;
        array[end] = a;
        // 添加元素后,队列大小加一。
        size++;
    }

    @Override
    public int get() {
     

        if (isEmpty()) {
     
            throw new RuntimeException("队列无元素可取");
        }
        front = front % maxSize + 1;
        int temp = array[front];
        size--;
        return temp;
    }

    @Override
    public void show() {
     
        // 队列有几个元素就打印几次
        if (isEmpty()) {
     
            System.out.println("队列为空队列");
            return;
        }

        // 因为队列初始化时,front为0,因此,为了防止取到array[0],进行判断。
        // 同时,如果front==0,则表明队列还未取过元素,同时队列不为空队列,因此array[1]一定是可以取到元素的。
        int temp = front == 0 ? 1 : front;
        for (int i = 0; i < size; i++) {
     
            System.out.println("array[" + temp + "]=" + array[temp]);
            temp = temp % maxSize + 1;
        }
    }
}

上面代码就是循环队列的一个基本实现,为了方便我们测试,在该队列实现类中增加一个main方法测试,如下:

public class MyArrayQueue implements IQueue {
     

    public static void main(String[] args) {
     

        Scanner scanner = new Scanner(System.in);
        boolean flag = true;
        System.out.println("请输入循环队列的容量:");
        int size = scanner.nextInt();
        MyArrayQueue myArrayQueue = new MyArrayQueue(size);
        while (flag) {
     
            System.out.println("请输入指令:");
            System.out.println("a 表示增加元素:");
            System.out.println("g 表示取出元素:");
            System.out.println("s 表示显示队列所有元素:");
            System.out.println("e 表示退出程序:");


            String input = scanner.next();
            switch (input) {
     
                case "a": {
     
                    int ele = scanner.nextInt();
                    myArrayQueue.add(ele);
                    break;
                }
                case "s": {
     
                    myArrayQueue.show();
                    break;
                }
                case "g": {
     
                    int i = myArrayQueue.get();
                    System.out.println(i);
                    break;
                }
                case "e":
                    flag = false;
                    break;
            }
        }

    }
    // 下面是队列的实现,略
    ...
}

你可能感兴趣的:(数据结构,队列,数据结构,java)