• 新知识-Queue_循环队列


    新知识-Queue(FIFO)

    FIFO:First in First out; 队列:先进先出

    • 入队和出队。入队会向队列追加一个新元素,而出队会删除第一个元素,一个索引来指出起点。

    代码:

    /** ... 动态数组和指向起点的标志位*/
    class MyQueue {
        // store elements
        private List<Integer> data;         
        //start sign
        private int p_start;            
        public MyQueue() {
            data = new ArrayList<Integer>();
            p_start = 0;
        }
        /** 插入值,返回是否成功. */
        public boolean enQueue(int x) {
            data.add(x);
            return true;
        };    
        /** 删除. */
        public boolean deQueue() {
            if (isEmpty() == true) {    /** 非空判断,空队列不能删除,返回false*/
                return false;
            }
            p_start++;	/*删除队首,指针后移*/
            return true;
        }
        /** 队首. */
        public int Front() {
            return data.get(p_start);
        }
        /** 检查非空. */
        public boolean isEmpty() {
            return p_start >= data.size();	/*队首>=长度==0  队列为空*/
        }     
    };
    
    public class Main {
        public static void main(String[] args) {
            MyQueue q = new MyQueue();		/* ...  动态数组对象建立,起点位初始化*/
            q.enQueue(5);
            q.enQueue(3);
            if (q.isEmpty() == false) {
                System.out.println(q.Front());   /* FIFO*/
            }
            q.deQueue();
            if (q.isEmpty() == false) {
                System.out.println(q.Front());
            }
            q.deQueue();
            if (q.isEmpty() == false) {
                System.out.println(q.Front());
            }
        }
    }
    
    #include <iostream>
    
    class MyQueue {
        private:
            // store elements
            vector<int> data;       
            // a pointer to indicate the start position
            int p_start;            
        public:
            MyQueue() {p_start = 0;}
            /** Insert an element into the queue. Return true if the operation is successful. */
            bool enQueue(int x) {
                data.push_back(x);
                return true;
            }
            /** Delete an element from the queue. Return true if the operation is successful. */
            bool deQueue() {
                if (isEmpty()) {
                    return false;
                }
                p_start++;
                return true;
            };
            /** Get the front item from the queue. */
            int Front() {
                return data[p_start];
            };
            /** Checks whether the queue is empty or not. */
            bool isEmpty()  {
                return p_start >= data.size();
            }
    };
    
    int main() {
        MyQueue q;
        q.enQueue(5);
        q.enQueue(3);
        if (!q.isEmpty()) {
            cout << q.Front() << endl;
        }
        q.deQueue();
        if (!q.isEmpty()) {
            cout << q.Front() << endl;
        }
        q.deQueue();
        if (!q.isEmpty()) {
            cout << q.Front() << endl;
        }
    }
    

    循环队列

    • 基础实现非常的低效,当队列排队溢满时,我们要想继续insert则需要将队首delete

    • 我们在这里引入双指针思路,在固定的数组中两个指针表示起始位置和结束位置,达到重用我们浪费的存储空间

    1. 头指针和尾指针之间实现循环的作用(环形缓冲器),利用先前使用的空间。

    2. 当front和Tail(头尾指针)都指向-1时,队列为空。

    3. insert第一位时,front和Tail都向后移一位,指向0,后面insert非第一位时,Tail单独向后移动。

    4. 当Tail指向最后一位时,通过取余%位数或者==0,返回队首,完成循环,继续插入,当Tail移动到front前面时,队列满队。

    5. 通过front往后移动完成delete,当front移动到Tail前面时,frontTail-1完成清空。

    • 自我实现代码:

      后面有标准答案,自寻,学习的话建议先粗略看一下我的过程,发现一下我的哪一步需要完善,再去看标准答案,会有柳暗花明的感觉...反面教材来一手

    class MyCircularQueue {
        private int[] data;
        private int front,tail;
    
        public MyCircularQueue(int k) {
            data = new int[k + 1];    /**-1位导致循环队列要比数值多一位 */
            front = 0;
            tail = 0;
        }
        
        public boolean enQueue(int value) {
            if(isFull()){
                return false;
            }else{
                data[tail] = value;
                tail = (tail + 1) % data.length;
                return true;
            }
        }
        
        public boolean deQueue() {
            if(isEmpty()){
                return false;
            }else{
                front = (front + 1) % data.length;
                return true;
            }
        }
        
        public int Front() {
            if(isEmpty()){
                return -1;
            }else{
                 return data[front];
            }   
        }
        
        public int Rear() {
            if(isEmpty()){
                return -1;
            }else{
                 return data[(tail - 1 + data.length) % data.length];
            } 
        }
        
        public boolean isEmpty() {
            if(front == tail){
                return true;
            }
            return false;
        }
        
        public boolean isFull() {
            if((tail + 1)%data.length == front){
                return true;
            }
            return false;
        }
    }
    
    • 实现循环列表错误记录:

      1. 判满的时候注意tail+1==front注意取余,不然会影响到enQueue,错误的判满导致错误的插入,

      2. 入列要判满,出列要判空,取队首尾先判空。

        3.k+1好像这个思路可有可无

    标准实现

    class MyCircularQueue {
        
        private int[] data;
        private int head;
        private int tail;
        private int size;
    
        public MyCircularQueue(int k) {
            data = new int[k];
            head = -1; 			/** ..-1起步,嗯这才是标准*/
            tail = -1;
            size = k;			/**  存放数组大小,这个地方不知道干嘛,往后看...*/
        }
        
        public boolean enQueue(int value) {
            if (isFull() == true) {
                return false;
            }
            if (isEmpty() == true) {	/**加了个判空,空意味着第一步,前面说了第一步先设0,没错*/
                head = 0;
            }
            tail = (tail + 1) % size;		//偷懒的,没事了
            data[tail] = value;/**把tail设0放在了后面,就可以变成先移动指针再设值,嗐我怎么没想到*/
            return true;
        }
        
        public boolean deQueue() {
            if (isEmpty() == true) {
                return false;
            }
            if (head == tail) {			/**谨慎的加了个清空,先前说了头尾为-1为初始化状态*/
                head = -1;
                tail = -1;
                return true;		/**属于最后一步出列,return true*/
            }
            head = (head + 1) % size;		
            return true;
        }
        
        public int Front() {
            if (isEmpty() == true) {
                return -1;
            }
            return data[head];
        }
    
        public int Rear() {
            if (isEmpty() == true) {
                return -1;
            }
            return data[tail];  /**这个地方就可以省略那一大步了。。。*/
        }
    
        public boolean isEmpty() {
            return head == -1;
        }
    
        public boolean isFull() {
            return ((tail + 1) % size) == head;    /**important*/
        }
    }
    
    • 内置队列库实现:

      public class Main {
          public static void main(String[] args) {
              Queue<Integer> q = new LinkedList();		/**LinkedList*/
              System.out.println("The first element is: " + q.peek());	/*peek队首*/
              //offer入列
              q.offer(1);
              q.offer(2);
              q.offer(3);
              q.offer(123);
              //poll出列
              q.poll();
              // 队首
              System.out.println("The first element is: " + q.peek());
              // 队列长度size
              System.out.println("The size is: " + q.size());
          }
      }
      
  • 相关阅读:
    tomcat 设置session过期时间(四种方式)
    Delphi7程序调用C#写的DLL解决办法
    delphi 获取大于2G的物理内存大小
    delphi 判断目录是否可写
    DLL编写与调用全解
    API Hook基本原理和实现
    dotnet tools 运行 dotnet run
    .NET Core & ASP.NET Core 1.0
    WebApp模版并运行
    配置系统引导启动SuperScoekt
  • 原文地址:https://www.cnblogs.com/husiyu/p/15133632.html
Copyright © 2020-2023  润新知