数组模拟队列和数组模拟环形队列

队列

队列介绍:
1、队列是一个有序列表,可以用数组或是链表来实现。
2、遵循先进先出的原则。即:先存入队列的数据,要先取出。后存入的数据,后取出

数组模拟队列示意图:
在这里插入图片描述

  • maxSize 是该队列的最大容量
  • 存入数据时从 尾节点存入,尾节点移动,头节点不动
  • 取出数据时从头节点取出,头节点移动,尾节点不动

加入数据的思路分析

当我们将数据存入队列时称为 ”addQueue“,addQueue 的处理需要有两个步骤
1、将尾指针往后移:rear+1,当front == rear 【队列为空】
2、若尾指针 rear 小于队列的最大下标 maxSize-1,则将数据存入所指的数组元素中,否则无法存入数据。 rear == maxsize -1 [队列满]

tip:数组模拟队列是从 0 开始, 第 一 个数据是放在第 0 的位置,第 二个数据是放在第 1 的位置,因此 队列最大值是 Maxsize - 1

代码实现:

package com.aiguigu.queue;

import java.util.Scanner;

public class ArrayQueueDemo {
    public static void main(String[] args) {
        ArrayQueue queue = new ArrayQueue(5);
        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(getQueue):从队列取出数据");
            System.out.println("h(head):显示队列头的数据");
            key = scanner.next().charAt(0);//接收一个字符

            switch (key){
                case 's'://显示数据
                     queue.showQueue();
                    break;
                case 'a'://添加数据
                    System.out.println("输入一个数");
                    int value = scanner.nextInt();
                    queue.addQueue(value);
                    break;
                case 'g'://取出数据
                    try {
                        int res = queue.getQueue();
                        System.out.printf("取出的数据是%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h'://查看队列头的数据
                    try {
                        int res = queue.headQueue();
                        System.out.printf("队列的头数据是%d\n",res);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e'://退出
                    scanner.close();
                    loop = false;
                    break;
                default:
                    break;
            }

        }
        System.out.println("程序退出");
    }

}

 class ArrayQueue{
    private int maxSize;//表示数组的最大容量
    private int front;//队列头
    private int rear;//队列尾
    private int[] arr;//该数组用于存放数据,模拟队列

    //创建队列的构造器
    public  ArrayQueue(int arrMaxSize){
        maxSize = arrMaxSize;
        arr = new int[maxSize];
        front = -1;//指向队列头部,front是指向队列头的前一个位置
        rear = -1; //指向队列尾部,指向队列的最后一个数据
    }

    //判断队列是否已满
    public boolean isFull(){
        return rear == maxSize -1;
    }

    //判断队列是否为空
    public boolean isEmpty(){
        return front == rear;
    }

    //添加数据到队列
    public void addQueue(int n){
        //判断队列是否已满
        if(isFull()){
            System.out.println("队列已满,不能加入数据");
            return;
        }
        //添加数据到队列
        arr[++rear] = n;//让 rear 后移,在 rear 的位置插入数据
    }


    //获取队列的数据
    public int getQueue(){
        //判断队列是否为空
        if (isEmpty()){
            System.out.println("队列为空的,没有数据~~");
            throw new RuntimeException("队列空,不能取数据");//抛异常的效果和 return一样
        }
        front++;//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()){
            System.out.println("队列为空的,没有数据~~");
            throw new RuntimeException("队列空,不能取数据");//抛异常的效果和 return一样
        }
        return arr[front + 1];
    }

}

运行效果:

s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
队列为空的,没有数据~~
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
2
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[0]=2
arr[1]=0
arr[2]=0
arr[3]=0
arr[4]=0
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
3
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
4
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[0]=2
arr[1]=3
arr[2]=4
arr[3]=0
arr[4]=0
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
5
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
6
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[0]=2
arr[1]=3
arr[2]=4
arr[3]=5
arr[4]=6
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
1
队列已满,不能加入数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
h
队列的头数据是2
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是2
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
h
队列的头数据是3
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是3
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是4
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是5
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是6
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
队列为空的,没有数据~~
队列空,不能取数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
1
队列已满,不能加入数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
e
程序退出

Process finished with exit code 0

数组模拟队列存在的问题和优化

1、目前数组使用一次1就不能用,没有达到服用的效果
2、将这个数组使用算法,改进成一个环形的队列 取模:%

数组模拟环形队列

在这里插入图片描述
思路:
1、front 变量的含义做一个调整:front 就指向队列的第一个元素,就是说 arr[front] 是队列的第一个元素, front的初始值 = 0
2、rear 变量的含义做一个调整:rear 就指向队列的最后一个元素的后一个位置,因为希望空出一个空间作为约定, rear的初始值 = 0
3、当队列满时,条件是 (rear + 1 + maxSize)% maxSize = front
4、队列为空的条件,rear == front
5、队列有效的数据的个数 (rear+maxSize-front)% maxSize
6、我们就可以在原来的队列上修改得到,一个环形队列

个人理解:
当 rear 的上面那个位置是front 时 队列满 因此是 (rear+1 + maxsize)%maxsize = front
Rear – front 表示 它两节点中间还有几个元素,但是 rear 有可能跑到 front 前面 ,这样Rear – front 得到的值就是负数,但是元素个数不能是负数,因此加上maxsize 再对 maxsize 取模,这样既不影响 元素的真实个数 又能使 元素的真实个数一直为正数,
(Rear-front + maxsize)%maxsize

package com.aiguigu.queue;

import java.util.Scanner;

public class CircleAraayQueueDemo {
        public static void main(String[] args) {
            CircleArrayQueue circleQueue = new CircleArrayQueue(5);
            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(getQueue):从队列取出数据");
                System.out.println("h(head):显示队列头的数据");
                key = scanner.next().charAt(0);//接收一个字符

                switch (key){
                    case 's'://显示数据
                        circleQueue.showQueue();
                        break;
                    case 'a'://添加数据
                        System.out.println("输入一个数");
                        int value = scanner.nextInt();
                        circleQueue.addQueue(value);
                        break;
                    case 'g'://取出数据
                        try {
                            int res = circleQueue.getQueue();
                            System.out.printf("取出的数据是%d\n",res);
                        }catch (Exception e){
                            System.out.println(e.getMessage());
                        }
                        break;
                    case 'h'://查看队列头的数据
                        try {
                            int res = circleQueue.headQueue();
                            System.out.printf("队列的头数据是%d\n",res);
                        }catch (Exception e){
                            System.out.println(e.getMessage());
                        }
                        break;
                    case 'e'://退出
                        scanner.close();
                        loop = false;
                        break;
                    default:
                        break;
                }

            }
            System.out.println("程序退出");
        }
}

class CircleArrayQueue{

    private int maxSize;//表示数组的最大容量
    private int front;//队列头
    private int rear;//队列尾
    private int[] arr;//该数组用于存放数据,模拟队列

    //创建队列的构造器
    public CircleArrayQueue(int arrMaxSize){
        maxSize = arrMaxSize ;
        arr = new int[maxSize];
    }

    //判断队列是否已满
    public boolean isFull(){
        return (rear+1+maxSize)%maxSize== front ;
    }
    //判断队列是否为空
    public boolean isEmpty(){
        return front == rear;
    }

    //添加数据到队列
    public void addQueue(int n){
        //判断队列是否已满
        if(isFull()){
            System.out.println("队列已满,不能加入数据");
            return;
        }
        //添加数据到队列
        arr[rear] = n;//直接将数据加入
        rear = (rear+1)%maxSize;//将 rear后移,这里考虑到取模
    }

    //获取队列的数据
    public int getQueue(){
        //判断队列是否为空
        if (isEmpty()){
            System.out.println("队列为空的,没有数据~~");
            throw new RuntimeException("队列空,不能取数据");//抛异常的效果和 return一样
        }
        int value = arr[front];//先定义一个变量将数组的值存放再移动front
        front = (front+1)%maxSize;//front后移,考虑取模
        return value;
    }

    //显示队列信息
    public void showQueue(){
        //判断队列是否为空
        if (isEmpty()){
            System.out.println("队列为空的,没有数据~~");
            return;
        }
        //从 front开始遍历,变历 front +有效数据个数
        for (int i = front; i <front+size(); i++) {
            System.out.printf("arr[%d]=%d\n",i % maxSize,arr[i % maxSize]);
        }
    }

    //求出当前队列的有效个数
    public int size(){
        return (rear-front+maxSize) % maxSize;
    }

    //显示队列的头数据,注意不是取数据
    public int headQueue(){
        //判断队列是否为空
        if (isEmpty()){
            System.out.println("队列为空的,没有数据~~");
            throw new RuntimeException("队列空,不能取数据");//抛异常的效果和 return一样
        }
        return arr[front];
    }

}

运行结果:

s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
队列为空的,没有数据~~
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
10
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
20
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
30
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
40
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[0]=10
arr[1]=20
arr[2]=30
arr[3]=40
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
a
输入一个数
50
队列已满,不能加入数据
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
h
队列的头数据是10
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
g
取出的数据是10
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据
s
arr[1]=20
arr[2]=30
arr[3]=40
s(show):显示队列
e(exit):退出程序
a(add):添加数据到队列
g(getQueue):从队列取出数据
h(head):显示队列头的数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值