循环队列:解决数组队列出队的时间复杂度

思路分析:

1.记录数组的队首和队尾的位置,当front 和tail指在一起的时候数组为空。

2.出队的时候front指针往后挪一位。这样出队操作就由数组队列的 O(N) 变成  循环队列的O(1)了。

让数组循环利用起来:

当前索引+1 再百分之我们数组的长度    比如我们到了最后一位7, 7+1 = 8 就是我们数组的长度    8对8 求余 = 0

就跟钟表一样   找到它的范围  然后让它在范围内循环。    1%12 = 1;  2 % 12 = 2; .... 11%12=11 12%12 = 0  这样就能无限在范围内循环。

然而有一个问题我们front = tail 表示空数组,也可以表示满数组。为了达到区分我们要刻意浪费一个空间,tail+1 = front = 满数组!!

package com.dapeng.Queue;
/**
 * @author gdp
 * @date 2020/4/5 23:06
 */
public class LoopQueue<E> implements Queue<E> {
    private E[] data;
    private int  front, tail; //数据首位   front==tail的时候空数组 但是也代表数组满了 所以我们设计为tail+1 为数组满了有意的浪费一个空间来做出区分
    private int size; //数组数据个数

    public LoopQueue(int capacity){
        data = (E[]) new Object[capacity+1]; //满足了用户需求也满足了程序设计
        front = 0 ;
        tail = 0 ;
        size = 0 ;
    }

    public LoopQueue(){
        this(10);
    }

    public  int getCapacity(){ return data.length -1; }
    @Override
    public boolean  isEmpty(){ return front == tail;}

    @Override
    public   int getSize(){ return size;}
    @Override
    public void enqueue(E e){
         //最后一个元素+1  取模
        if( (tail + 1) % data.length == front )
            resize(this.getCapacity() * 2 );

        data[tail] = e;
        tail = (tail +1 ) % data.length ;
        size ++;
    }

    @Override
    public E dequeue(){
        if(isEmpty()) throw new IllegalArgumentException("Cannot dequeue from  an  empty queue.");
        E ret  = data[front];
        data[front] = null;
        front =  (front +1) % data.length;
        size --;
         if(size  == this.getCapacity() /  4 && getCapacity()/2 != 0)
         {
             resize(getCapacity() / 2);
         }
        return ret;
    }

    @Override
    public E getFront(){
        if(isEmpty()) throw new IllegalArgumentException("  Queue is empty !.");
        return data[front];
    }

    private void resize(int newCapacity) {
         E[] newData = (E[]) new Object [newCapacity +1];
         for(int i = 0; i< size; i++ )
         {
             newData[i] = data[(front + i) % data.length];
             data = newData;
             front = 0;
             tail = size;
         }
    }

    @Override
    public String toString()
    {
        StringBuilder res   = new StringBuilder();
        res.append(String.format("Queen: size = %d, capacity = %d\n",size,getCapacity()));
        res.append("front [");
        for(int i = front; i != tail; i = (i+1) % data.length)
        {
            res.append(data[i]);
            if(i!=size-1)
                res.append(",");
        }
        res.append("]tail");
        return res.toString();
    }

    public static void main(String[] args) {
        LoopQueue<Integer> queue = new LoopQueue<>();
        for(int i = 0 ; i < 10 ; i++ ){
            queue.enqueue(i);

   /*         if(i % 3 == 2){
                queue.dequeue();
                System.out.println(queue);
            }*/
        }
        System.out.println(queue.toString());
    }

}

这个是测试两种队列效率的代码:显然循环队列是快了很多的。

package com.dapeng.Queue;
import java.util.Random;
/**
 * @author gdp
 * @date 2020/4/6 18:41
 */
public class queueTest {
   private static double test(Queue<Integer> queue, int opCount){
       long startTime = System.nanoTime();
       Random random = new Random();
       for (int i = 0; i< opCount ; i++) queue.enqueue(random.nextInt(Integer.MAX_VALUE));
       for (int i = 0; i< opCount ; i++)  queue.dequeue();
       long endTime = System.nanoTime();

       return (endTime - startTime) / 100000000.0;
   }

    public static void main(String[] args) {
        int     opCount = 1000000;
        ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();
        double time1 = test(arrayQueue, opCount);
        System.out.println("ArrayQueue, time:" +time1+"  s");

        LoopQueue<Integer> LoopQueue = new LoopQueue<>();
        double time2 = test(LoopQueue, opCount);
        System.out.println("LoopQueue, time:" +time2+"  s");
    }

}

两个耗时结果比较:

ArrayQueue, time:2926.524975 s
LoopQueue, time:0.457739 s

文章视频链接:https://www.ixigua.com/i6815911054443282948/

原文地址:https://www.cnblogs.com/study-gdp/p/12705223.html

时间: 2024-10-13 22:59:05

循环队列:解决数组队列出队的时间复杂度的相关文章

队列的入队和出队操作

#include<iostream> #include<stdio.h> #include<string.h> #include<conio.h> using namespace std; typedef struct student{ int data; struct student *next; }node; typedef struct linkqueue { node *first, *rear; }queue; //队列的入队 queue *ins

C语言 简单的队列(数组队列)

//简单的队列 #include<stdio.h> #include<stdlib.h> #define datatype int #define N 10 //定义队列结构体 struct queue{ int front;//队头 int endline;//队尾 datatype data[N];//数据 }; typedef struct queue Queue; Queue myQueue = { 0, 0, { 0 } }; //初始化队列 void initQueue

【deque】滑动窗口、双端队列解决数组问题

C++手册之deque 所属头文件 <deque> 常用操作: back()返回尾部元素: front()返回头部元素: push_back()尾部插入元素: pop_bakc()尾部删除元素: push_front()头部插入元素: pop_front()头部删除元素: 问题1:求滑动窗口的最大值(<剑指offer面试题65>) 描述:给定一个数组和滑动窗口的大小,找出所有滑动窗口里的最大值. 示例:数组{2, 3, 4, 2, 6, 2, 5} 窗口大小为 3,一共有7-3+1

循环队列的顺序存储和入队出队操作

今天看图的广度优先遍历的时候,发现用到了循环队列,补一下循环队列的知识,参考<大话数据结构>的P116~117,自己写了一个简单的测试例子便于理解. 首先需要理解以下三条公式. front是队头元素的下标,rear是队尾元素后一位的下标.(书上用头指针和尾指针,front和rear并不是指针,个人觉得不太好) 1.队列空的条件 显然front==rear 注意:如果队列不保留任何元素空间 满足front==rear的情况下,可能是队列空,也可能是队列满.所以为了方便,本文讨论的是采用保留一个元

Python与数据结构[2] -&gt; 队列/Queue[0] -&gt; 数组队列的 Python 实现

队列 / Queue 数组队列 数组队列是队列基于数组的一种实现,其实现类似于数组栈,是一种FIFO的线性数据结构. Queue: <--| 1 | 2 | 3 | 4 | 5 |<-- 下面将使用Python中的list来替代C语言中的数组实现数组队列的数据结构. Note: 这里的实现并没有像C语言中的申请一块固定大小的数组,手动的定制数组中队列的头尾位置,而是利用list的特性直接完成,因此较为简单. 数组队列的实现与数组栈的实现基本类似,同时入列和出列也十分简单,仅需要对数组进行操作即

浅谈单调队列:死海不是海,单调队列不是队列

1.滑动窗口最值问题 给定一个长度为n的序列a1,a2,-ai,-,an,将一个长为k的滑动窗口自序列最左端向右边滑动.例如:初始时,窗口内的子序列为a1,a2,-,ak:当窗口向右滑动一位,此时窗口内的子序列变为a2,a3,-,ak+1. 我们要解决的问题是,给定长度为n的序列以及滑动窗口的大小k,求每一个滑动窗口内的最小值和最大值. 以长度为5的序列1, 3, 4, 5, 7滑动窗口k=3为例说明: 第1个滑动窗口(1, 3, 4)的最小值.最大值分别为1和4: 第2个滑动窗口(3, 4,

队列的C++实现(数组)——创建-进队-出队-返回队首元素-清空队列栈-处理队列

队列的数组实现,从队尾进入,对头删除. 队列长度用标志变量size,它是独立于front和rear的一个变量.size == 0,队列为空.size == capacity,满队列. 一.结点声明 1 struct Node{ 2 int Capacity; 3 int Front; 4 int Rear; 5 int Size; 6 int *Array; 7 }; 8 typedef struct Node Queue; Capacity队列容量:Front,Rear为队列首元素和尾元素的数

循环队列的初始化、入队、出队等基本操作

循环队列的初始化.入队.出队等基本操作,实现代码如下: #include<iostream> using namespace std; #define TRUE 1 #define FALSE 0 //循环队列的类型定义 #define MAXSIZE 50//队列的最大长度 typedef struct { int element[MAXSIZE];//队列的元素空间 int front;//头指针指示器 int rear;//尾指针指示器 }SeqQueue; //循环队列初始化 void

顺序结构循环队列的基本操作(一)(进队,出队)待优化

#include<stdio.h>#define ElemType int#include<malloc.h>#define MAXSIZE 10typedef struct{ ElemType *data; int front,rear;}Queue;typedef struct BitNode{ ElemType data; struct Bitree *Lchild,*Rchild;}BitNode;Queue Init_queue(Queue Q){ Q.data=(Ele