java数组实现队列(单向队列和环形队列)

标题一:队列的概念

队列是一个有序列表属于线性结构,可以用数组或者是链表实现。
原则:先进先出
单向队列:只能在一端进行入队或者出队
环形队列:一端两种操作都可以实现

标题二:单向队列的操作

思路:先声明一下数组,maxSize是该队列的最大容量队顶的索引也就是maxSize-1因为数组下标是从0开始的嘛,rear和front队列后、前端,初始值都是-1,rear是随着数据的输入而改变,front是随着数据输出而改变。看图即可理解。
在这里插入图片描述
分析下队列满和空的条件:
满:显而易见当rear=MaxSize-1就满了
空:rear=front就是空
下面拿代码分析一下

package queue;

import java.util.Scanner;

public class ArrayQueueDemo {
    
    
    public static void main(String[] args) {
    
    
        //测试一把
        // 创建一个队列
        BrrayQueue queue = new BrrayQueue(3);
        char key = ' ';// 接收用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        //输出一个菜单
        while (loop) {
    
    
            System.out.println("s(show): 显示队列");
            System.out.println("e(exit): 退出程序");
            System.out.println("a(add): 添加数据到队列");
            System.out.println("g(get): 从队列取出数据");
            System.out.println("h(head): 查看队列头的数据");
            key = scanner.next().charAt(0);//接收一个字符
            switch(key)
            {
    
    
                case 's':
                    queue.showQueue();
                    break;
                case 'a':
                    System.out.println("输出一个数");
                    int values=scanner.nextInt();
                    queue.addQueue(values);
                    break;
                case 'g':
                    try
                    {
    
    
                        int res=queue.getQueue();
                        System.out.printf("取出来的数据是%d",res);
                    }catch(Exception e)
                    {
    
    
                        System.out.println(e.getMessage());
                    }
                    System.out.println();
                    break;
                case 'h':
                    try
                    {
    
    
                        int res=queue.headQueue();
                        System.out.printf("取出来的数据是%d",res);
                    }catch(Exception e)
                    {
    
    
                        System.out.println(e.getMessage());
                    }
                    System.out.println();
                    break;
                case 'e'://退出
                    scanner.close();
                    loop=false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("exit!");
    }
}
class BrrayQueue
{
    
    
    private int maxSize;
    private int front;
    private int rear;
    private int[] arr;
    public BrrayQueue(int arrMaxSize)
    {
    
    
        maxSize=arrMaxSize;
        arr=new int[maxSize];
        front=-1;
        rear=-1;
    }
    //判断队列是否满
    public boolean isFull()
    {
    
    
        return rear==maxSize-1;
    }
    //判断队列是否为空
    public boolean isEmpty()
    {
    
    
        return rear==front;
    }
    //添加数据到队列
    public void addQueue(int n)
    {
    
    
        //判断队列是否满
        if(isFull())
        {
    
    
            System.out.println("队列已满,不能加入数据");
            return;
        }
        rear++;
        arr[rear]=n;
    }
    //获取数据出队列
    public int getQueue()
    {
    
    
        //判断队列是否为空
        if(isEmpty())
        {
    
    
            //通过抛出异常处理
            throw new RuntimeException("队列为空!");
        }
        front++;
        return arr[front];

    }
    //显示队列的所有数据
    public void showQueue()
    {
    
    
        //遍历
        if(isEmpty())
        {
    
    
            System.out.println("队列为空!");
            return;
        }
        for(int i=0;i<arr.length;i++)
        {
    
    
            System.out.printf("arr[%d]=%d/n",i,arr[i]);
        }
    }
    //显示队列的头数据
    public int headQueue()
    {
    
    
        if(isEmpty())
        {
    
    
            throw  new RuntimeException("对列为空");
        }
        return arr[front+1];
    }
}
/**
 *  break 跳出总上一层循环,不再执行循环(结束当前的循环体)
 *  continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件)
 *  return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)
 */

相信兄弟萌都能看懂!

标题三:环形队列的操作(需要理解)

front指向的是队列的第一个元素,rear指向的是最后一个元素的后一位,俩初始值都为0。和单向队列是有区别的仔细思考下。
环形队列原理:其实呢内存上不存在环形的,,因此环形队列实际上是数组的线性空间实现的。
当rear回到0这个位置上,这个转回来的操作是由取模实现的,也就是环形对列是由取模实现的。
首先说一下取模:比如任意数%8,取模后的结果都是在0~8之间的。
队满:它的表达式为(rear+1)%maxSize=front
看一下我的分析:当rear<maxSize-1的时候取模不就是白给吗!!!
画个图理解一下
在这里插入图片描述这个时候想让d入队,他就是最后一个元素对吧,那么rear+1等于多少?不就溢出来了嘛,超出了数组的大小,但是这个时候我们的队列还没有满,前面还可以插入,这个时候可以将数组想象成环状,那么d后面的索引就是0,假设现在又要入队一个e,上图。

在这里插入图片描述这个时候rear指向1,那么还能不能再添加一个数据呢?

假设是可以的,那么rear就会指向2,这个时候rear=front,而这个条件恰恰是队列为空的条件。和队列满是一样的,此时就无法判断是空还是满,因此我们要留出最后一个元素的后一个位置当成约定不插入数据,仅仅是用于判断空还是满。
这个时候满的条件就是(rear+1)%maxSize=front,
这个表达式就已经空出一个空间来当约定了。仔细思考下,对照着图。
就像rear=1的时候,maxSize=6;rear+1=2%maxSize=2%6=2=front,这个时候队列已经满了而且空了一个就是rear指向的位置也就是1,前面索引为0的元素就是最后一个数据,索引为1的就是约定。
单向队列有一个问题就是当rear=maxSize的时候,程序就会误以为他是满的,所以不能能继续插入,这个单向队列也就是只能使用一次。
环形队列也就解决了这个问题,这个时候环形队列能存储的数据容量也就是maxSize
但是他有多少有效数据呢?
rear-front?
这个肯定是错误的因为这个是环形哎,rear可能小于front,这个时候你不就是白给吗!!
正确的表达式(rear-front+maxSize)%maxSize
解释一下:
我自己的理解:rear-front也就是队头和队尾之间的距离不考虑负数,因为都一样距离不可能是负数吧,再加上maxSize然后取模不就是有效数据吗,可以结合取模运算理解一下,这个时候取模去的就是除去队头和队尾之间的距离,不就是有效的。
这个时候 知道不能用rear++吧,取模就行了
此时rear=(rear+1)%maxSize,front=(front+1)%maxSize
下面贴下代码理解一下:

package queue;

import java.util.Scanner;

public class CircleArrayQqueue {
    
    
    public static void main(String[] args) {
    
    
        //测试一把
        // 创建一个队列
        CircleArray queue = new CircleArray(4);
        char key = ' ';// 接收用户输入
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;
        //输出一个菜单
        while (loop) {
    
    
            System.out.println("s(show): 显示队列");
            System.out.println("e(exit): 退出程序");
            System.out.println("a(add): 添加数据到队列");
            System.out.println("g(get): 从队列取出数据");
            System.out.println("h(head): 查看队列头的数据");
            key = scanner.next().charAt(0);//接收一个字符
            switch(key)
            {
    
    
                case 's':
                    queue.showQueue();
                    break;
                case 'a':
                    System.out.println("输出一个数");
                    int values=scanner.nextInt();
                    queue.addQueue(values);
                    break;
                case 'g':
                    try
                    {
    
    
                        int res=queue.getQueue();
                        System.out.printf("取出来的数据是%d",res);
                    }catch(Exception e)
                    {
    
    
                        System.out.println(e.getMessage());
                    }
                    System.out.println();
                    break;
                case 'h':
                    try
                    {
    
    
                        int res=queue.headQueue();
                        System.out.printf("取出来的数据是%d",res);
                    }catch(Exception e)
                    {
    
    
                        System.out.println(e.getMessage());
                    }
                    System.out.println();
                    break;
                case 'e'://退出
                    scanner.close();
                    loop=false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("exit!");
    }
}
class CircleArray
{
    
    
    private int maxSize;
    private int front;
    private int rear;
    private int[] arr;
    public CircleArray(int arrMaxSize)
    {
    
    
        maxSize=arrMaxSize;
        arr=new int[maxSize];
        front=0;//默认是0
        rear=0;
    }
    //判断队列是否满
    public boolean isFull()
    {
    
    
        return (rear + 1) % maxSize == front;
    }
    //判断队列是否为空
    public boolean isEmpty()
    {
    
    
        return rear==front;
    }
    //添加数据到队列
    public void addQueue(int n)
    {
    
    
        //判断队列是否满
        if(isFull())
        {
    
    
            System.out.println("队列已满,不能加入数据");
            return;
        }
        //直接将数据加入
        arr[rear] = n;
        //将 rear 后移, 这里必须考虑取模
        rear = (rear + 1) % maxSize;
    }
    //获取数据出队列
    public int getQueue()
    {
    
    
        //判断队列是否为空
        if(isEmpty())
        {
    
    
            //通过抛出异常处理
            throw new RuntimeException("队列为空!");
        }
        // 这里需要分析出 front 是指向队列的第一个元素
        // 1. 先把 front 对应的值保留到一个临时变量,如果不保存return arr[front]此时直接从第二个元素 开始出因为front初始值为0.
        // 2. 将 front 后移, 考虑取模
        // 3. 将临时保存的变量返回
        int value = arr[front];
        front = (front + 1) % maxSize;
        return value;
    }
    //显示队列的所有数据
    public void showQueue()
    {
    
    
        //遍历
        if(isEmpty())
        {
    
    
            System.out.println("队列为空!");
            return;
        }
        for (int i = front; i < front + size() ; i++)
        {
    
    
            System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
        }
    }
    // 求出当前队列有效数据的个数
    public int size()
    {
    
    
        // rear = 2 // front = 1 // maxSize = 3
        return (rear + maxSize - front) % maxSize;
    }
    //显示队列的头数据
    public int headQueue()
    {
    
    
        if(isEmpty())
        {
    
    
            throw  new RuntimeException("对列为空");
        }
        return arr[front];
    }
}

个人理解,帮助到的请兄弟萌点个关注或者评论,哈哈哈。

猜你喜欢

转载自blog.csdn.net/qq_42678668/article/details/106210964