数据结构和算法之队列

33 篇文章 0 订阅
32 篇文章 0 订阅

数组模拟队列

将数组模拟成队列的思想:

/*将数组模拟成队列的思想:
* 1·因为是先进先出,所以我们可以采用尾巴添加值进入数组,头部从数组中将值取出,然后将下标进行++
* 2·front指向的是头元素的前一个位置,也就是说arr[front+1]才是表示队列的第一个元素
* 3·rear指向的当前队列的最后一个元素,也就是说rear+1的时候才能进行插值
* 4·front的初始值=-1;;;;;rear的初始值=-1
* 5·队列为空的条件:front==rear;
* 6·队列为满的条件:rear+1=maxSize;
* 7·当前队列的有效个数就是rear-front的值即可
* 8·存在的问题是:这样的数组模拟队列只能用一次,不能进行复用
* 9·进行优化的算法就是:采用取模运算,将队列变成一个循环队列*/

代码实现如下:

import java.util.Scanner;
//队列:特点先进先出
/*
* 1·有两种存储方法:数组(顺序存储)和链表(链式存储)
* */
//(一)使用数组模拟队列:
class ArrayQueue{
    private int maxSize;//模拟对列的最大值,也就是该队列未满的时候的输的个数
    private int front;//指向队列的头部的前一个数据
    private int rear;//指向队列尾部的当前数据
    private int[]arr;//该处是数组模拟队列的数组

    //数组模拟队列的构造方法
    public ArrayQueue(int arrMaxSize){
        maxSize=arrMaxSize;
        front=-1;
        rear=-1;
        arr=new int[maxSize];
    }

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

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

    //添加数据到队列:也就是从尾部rear开始添加数据
    /*若队列已经满了则就不能添加数据了*/
    public void addQueue(int n){//进队列
        //判断队列是否为空的情况下,直接退出假如,并提示队列已满
        if(isFull()){
            System.out.println("队列已经满了不能再添加数据了");
            return;
        }
        //然后就是队列不为满的情况下:
        rear++;//尾巴向后加一位在进行添加,因为刚开始的时候rear=-1
        arr[rear]=n;//加入数据n到队列中
    }

    //从队列中取出数据:也就是从头部front开始去除数据:就是为了达到先进先出的成果
    /*若队列为空的情况下就不能从队列中去除数据了*/
    public int getQueue(){//出队列
        //判断队列是否为空的情况下,直接退出,并提示队列为空
        if(isEmpty()) {
            //return -1;注意:在这里返回-1 是不行的因为front的其实位置就是在-1 的位置,所以可以进行抛异常
            //通过抛出异常来处理
            throw new RuntimeException("队列为空,不能取数据");//注意:在这个抛出异常之后没必要在写return,
            // 因为在这里抛出的异常直接到下面的语句都是不可达的
        }
        //然后就是队列不为空的时候进行取出数据即可
        front++;//因为取出后将队列中的第一个元素变成下一个元素
        return arr[front];
    }

    //显示队列的所有数据:
    public void show(){
        //队列为空的时候,里面没有数据,无法进行打印
        if(isEmpty()){
            System.out.println("队列为空,没有数据");
            return;
        }
        for(int i=0;i<arr.length;i++)
        {
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }

    //显示一个队列的头部数据,注意只是显示不能是取出
    public int headQueue(){
        //首先得判断队列是否为空,若为空则没有数据可显示
        if(isEmpty()){
            throw new RuntimeException("队列为空,没有数据可以显示");
        }
        return arr[front+1];//注意:在这里一定是front+1,因为front指向的是队列头部元素的前一个数据
    }
}
public class Queue {
    public static void main(String[] args) {
        System.out.println("测试数组模拟队列的案例:");
        //创建一个数组队列
        ArrayQueue arrayQueue=new ArrayQueue(3);//创建一个数组队列大小为3
        char key=' ';//接受用户的输入
        Scanner input=new Scanner(System.in);
        System.out.println("请输入的选择");
        boolean loop=true;
        while(loop){
            System.out.println("a:表示添加数据到队列中");
            System.out.println("g:表示从队列中去除数据");
            System.out.println("s:表示显示队列");
            System.out.println("h:表示显示队列的头元素");
            System.out.println("e:表示退出操作");
            key=input.next().charAt(0);//表示读入一行的字母
            switch (key){
                case 'a':
                    System.out.println("请输入一个数:");
                    int val=input.nextInt();
                    arrayQueue.addQueue(val);
                    break;
                case 'g'://因为在去除数据的方法中抛出了异常,所以我们就得进行和异常捕获
                    try {
                        int result=arrayQueue.getQueue();
                        System.out.println("取出的数据是:"+result);//在这里如果发生异常将不会执行该条语句
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 's':
                    arrayQueue.show();//显示队里面的内容
                    break;
                case 'h':
                    try {
                        int result=arrayQueue.headQueue();
                        System.out.println("该队列的头元素是:"+result);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    input.close();
                    loop=false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

总结:因为这样的数组队列有局限性,只能用一次,所有可以对数组进行优化,采用取模算法将其变成一个循环队列

优化思想:

/*循环队列的思想:可已将数组进行复用
* 1·采用一个预留空间
* 2·rear指向的是最后一个元素的后一个位置;
* 3·front指向的是队列的第一个元素,也就是说arr[front]就是队列的第一个元素,希望留出一个预留空间进行判断满的
* 4·rear的初始值=0;;;;;front的初始值=0;
* 5·队列满的条件是:(rear+1)%maxSize==front
* 6·队列空的条件是:rear==front;
* 7·循环队列中的有效数的个数:(rear+maxSize-front)%maxSize(也就是说当前循环队列的有效个数是数组大小-1的值)*/

优化后的代码:

import java.util.Scanner;
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 addCircleQueue(int n){
        if(isFull()){
            System.out.println("队列已满,不能再向里面添加数据了");
            return;
        }
        //现在的rear指向的就是当前的队尾,直接添加即可
        arr[rear]=n;
        //然后将rear后移一位,因为现在是环形队列,所以要进行的是取模运算
        rear=(rear+1)%maxSize;
    }

    //从环形队列中取出数据
    public int getCircleQueue(){
        if(isEmpty()){
            throw new RuntimeException("队列为空,无法取出数据");
        }
        //在这里需要分析front是指向队列的第一个元素
        /*注意:为什么要采用第三变量,因为直接返回front的值的话,就无法将front进行后移一位
        * 1·要采用一个第三个变量将队列中的front的值保存下来
        * 2·front需要后移,为了不越界就得考虑取模运算
        * 3·将第三个变量的值返回即可*/
        //return arr[front];
        int value=arr[front];
        //front++;
        front=(front+1)%maxSize;
        return value;
    }

    //显示循环队队列中的有效元素:
    public void showCircleQueue(){
        if(isEmpty()){
            System.out.println("循环队列为空,没有数据可显示");
            return;
        }
        for(int i=front;i<front+size();i++)//因为是环形队列,所有便利的所有有效的数据
        {
            System.out.println(arr[i%maxSize]+" ");//因为下标是环形的队列
        }
    }
    //求出当前队列中的有效数据:
    public int size(){
        return (rear+maxSize-front)%maxSize;
    }

    //显示一个循环队列的头部数据,注意只是显示不能是取出
    public int headQueue(){
        //首先得判断循环队列是否为空,若为空则没有数据可显示
        if(isEmpty()){
            throw new RuntimeException("队列为空,没有数据可以显示");
        }
        return arr[front];//注意:在这里一定是front+1,因为front指向的是队列头数据(当前头部的元素)
    }

}
public class CircleQueue {
    public static void main(String[] args) {
        System.out.println("测试数组模拟环形队列的案例:");
        //创建一个数组队列
        CircleArray circleArray=new CircleArray(3);//创建一个数组队列大小为3,但是有效数据最大是2
        char key=' ';//接受用户的输入
        Scanner input=new Scanner(System.in);
        System.out.println("请输入的选择");
        boolean loop=true;
        while(loop){
            System.out.println("a:表示添加数据到队列中");
            System.out.println("g:表示从队列中去除数据");
            System.out.println("s:表示显示队列");
            System.out.println("h:表示显示队列的头元素");
            System.out.println("e:表示退出操作");
            key=input.next().charAt(0);//表示读入一行的字母
            switch (key){
                case 'a':
                    System.out.println("请输入一个数:");
                    int val=input.nextInt();
                    circleArray.addCircleQueue(val);
                    break;
                case 'g'://因为在去除数据的方法中抛出了异常,所以我们就得进行和异常捕获
                    try {
                        int result=circleArray.getCircleQueue();
                        System.out.println("取出的数据是:"+result);//在这里如果发生异常将不会执行该条语句
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 's':
                    circleArray.showCircleQueue();//显示队里面的内容
                    break;
                case 'h':
                    try {
                        int result=circleArray.headQueue();
                        System.out.println("该队列的头元素是:"+result);
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    input.close();
                    loop=false;
                    break;
                default:
                    break;
            }
        }
        System.out.println("程序退出");
    }
}

总结:采用循环队列的好处就是数组得到了复用,提高了数组的利用率

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值