• 数组模拟队列进阶版本——环形队列(真正意义上的排队)


    数组模拟环形队列(真正意义上的排队)

    昨天我们做了数组模拟队列的基本情景。可以进行排队和取出数据(最早的人离开队列),但是我们发现,取出的地方不能重复利用。让我们的队列成为了一次性队列。今天我们来看如何将我们的队列改进称数组模拟环形队列。实现已释放位置的重复利用

    基本原理:

    要知道我们实现队列的基本是头和尾。rear和front。这两个的指向决定了队列的头尾。也就是队列本身。这个具体指向头部本身索引或者前一个后一个不是固定的。是根据具体算法而定的。这次我们规定头和尾默认指向0索引。

    对前面的数组模拟队列的优化,充分利用数组. 因此将数组看做是一个环形的。(通过取模的方式式来实现即可)

    分析说明:

    1:尾索引的下一个为头索引时表示队列满,即将队 列容量空出一个作为约定,这个在做判断队列满的 时候需要注意 (rear + 1) % maxSize == front 满]

    2:rear == front [空]

    代码如下:

    package com.joseph.sparseArray;
    
    import java.util.Map;
    import java.util.Scanner;
    
    public class CircularQueue {
        public static void main(String[] args) {
    
                CQueue cQueue = new CQueue(5);
                Scanner sc = new Scanner(System.in);
            int i;
                while(true) {
                    System.out.println("---------------排队系统--------------");
                    System.out.println("---------------1:排队咨询--------------");
                    System.out.println("---------------2:结束排队(最早成功的人)--------------");
                    System.out.println("-------------- 3:查看当前排队详情--------------");
                    System.out.println("---------------88:SHOW REAR AND FRONT");
                    System.out.println("---------------4:退出--------------");
                    i = sc.nextInt();
                    switch (i) {
    
                        case 1:
                            System.out.println("请输入你的电话");
                            int tel = sc.nextInt();
                            cQueue.add(tel);
                            if(cQueue.rear == 0){
                                if(cQueue.arr[cQueue.MaxSize-1] == tel) {
                                    System.out.println("排队成功!");
                                    System.out.println("已结束最早完成排队的人。当前空闲位置为:" + ((cQueue.MaxSize - 1) - (cQueue.rear - cQueue.front + cQueue.MaxSize) % cQueue.MaxSize));
                                }
                            }else if (cQueue.arr[cQueue.rear - 1] == tel) {
                                System.out.println("排队成功!");
                                System.out.println("已结束最早完成排队的人。当前空闲位置为:" + ((cQueue.MaxSize -1) - (cQueue.rear - cQueue.front + cQueue.MaxSize) % cQueue.MaxSize));
                                break;
                            } else {
                                System.out.println("排队失败!");
                                System.out.println("已结束最早完成排队的人。当前空闲位置为:" + ((cQueue.MaxSize -1) - (cQueue.rear - cQueue.front + cQueue.MaxSize) % cQueue.MaxSize));
                                break;
                            }
                        case 2:
                            int oldFront = cQueue.front;
                            cQueue.get();
                            if (cQueue.front != oldFront) {
                                System.out.println("已结束最早完成排队的人。当前空闲位置为:" + ((cQueue.MaxSize -1) - (cQueue.rear - cQueue.front + cQueue.MaxSize) % cQueue.MaxSize));
                                break;
                            }
                            System.out.println("结束失败");
                            break;
                        case 3:
                            cQueue.List();
                            break;
                        case 4:
                            System.out.println("谢谢使用!");
                            break;
                        case 88:
                            System.out.println("front:" + cQueue.front);
                            System.out.println("rear:"+cQueue.rear);
                    }
                }
        }
    }
    class CQueue{
        int MaxSize ;//数组最大容量,因为我们的REAR(尾部)指向的是最后一个数据索引的后一个。这也就是说我们的真实存储长度要比MaxSize小一个。因为总要空出一个由rear指向。这是一个约定。前面有说到。
        int rear ;//尾部。指向队列最后一个数据的后一个位置
        int front ;//头部。直接指向第一个数据索引下标
        int arr[] ;//数组
        public CQueue(int MaxSize){//基本没变。rear和front初始值和上次不一样。不懂得先看上次数组模拟队列基础版
            this.MaxSize = MaxSize ;
            arr = new int[MaxSize];
            this.rear = 0;
            this.front = 0;
        }
        public boolean isFull(){
            return (rear+1)%MaxSize == front ;//由于环形队列,其实队列满的状态。是他们两个差"一个",因为rear指向的是数据的后一个。而front指向的第一个数据。因为是环形,0和4要联系起来只差一个就需要取模。利用rear+1和MaxSize取模。等于front就代表满了。这个需要好好理解。比较有难度
        }
        public boolean isEmpty(){//判断为空。当他们两个相等。不管在什么位置。就代表没有数据。
            return rear == front ;
        }
    
        public void add(int key){//添加数据
            if(isFull()){
                System.out.println("QUEUE IS FULL,CAN'T ADD ANYTHING");
                return ;
            }
            arr[rear] = key ;//直接将rear的下标赋值。
            rear = (rear+1)%MaxSize ;//这里不能再自增了。因为是环形的。需要利用+1后取模实现周期性。否则会下标越界
        }
        public int get(){
            if(isEmpty()){
                throw new RuntimeException("QUEUE IS EMPTY,NO THINGS BE GETED");
            }
            int temp = arr[front] ;//这里先把头部数据拿出来。放到temp
            front = (front+1)%MaxSize ;//给front移位。当数据取出。就往后+1作为初始第一个数据。但是是环形的。继续利用+1后取模实现周期性+1.不然会下标越界
            return temp ;
        }
        public void List(){
            //判断
            if(isEmpty()){
                System.out.println("QUEUE IS EMPTY!");
                return ;
            }
            for(int i = front ; i < (rear - front + MaxSize)%MaxSize +front ;i++){//这里不能用传统思维去输出了。要从front开始输出。也就是队列的开头
                //而i的范围。不再是队列长度。而是队列的有效数据个数+front。前面有算出是(rear-front+MaxSize)%MaxSize,其实rear是最后一个数据的后一个,而front就是第一个。我认为rear-front就是有效数据个数。而由于环形。往往出现负数。所以继续取模达到绝对值的效果。由于我们是环形的。front初始位置会由于用户取出导致变化。所以必须再加上front。因为front才是开始的位置。再加上有效数据个数。就是i的范围
                System.out.printf("队伍第[%d]号 : %d\n",i%MaxSize,arr[i%MaxSize]);//这里输出用printf方法做一个格式化。不能用i,要取模。否则会越界
            }
        }
    }
    /**
     * @author JosephWang
     * @date 2021/8/10 11:58
     */
    

    __EOF__

  • 本文作者: userName
  • 本文链接: https://www.cnblogs.com/F-Fan/p/16182274.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    Springcloud----Nacos集群的搭建
    拓展(华为优秀网站)
    AndroidBaseFrameMVVM 框架
    基于STM32设计的小龙虾养殖系统(带手机APP)
    FastGpt流程
    String,StringBuffer, StringBuilder 的区别是什么?String为什么是不可变的?
    ESP8266-Arduino编程实例-SPIFFS及数据上传(Arduino IDE和PlatformIO IDE)
    代码技巧——Apache集合类&字符串工具包中实用的API
    【校招VIP】互联网校招项目&实习对项目的要求不重要?大错特错!你忽略掉的项目考察重点都在这里!
    编译 libcurl 静态库
  • 原文地址:https://www.cnblogs.com/F-Fan/p/16182274.html