Java数据结构和算法-队列

队列:
    
    1.概念

        队列同样是一种特殊的线性表,其插入和删除的操作分别在表的两端进行,队列的特点就是先进先出(First In First Out)。我们把向队列中插入元素的过程称为入队(Enqueue),删除元素的过程称为出队(Dequeue)并把允许入队的一端称为队尾,允许出的的一端称为队头,没有任何元素的队列则称为空队。

        按存储结构分为顺序队列和链式队列。

            public interface Queue<T> {

               int size();
               
               boolean isEmpty();

               boolean add(T data);

               boolean offer(T data);

               T peek();

               T element();

               T poll();

               T remove();

扫描二维码关注公众号,回复: 2446344 查看本文章

               void clearQueue();
            }


    2.顺序队列的设计与实现

        关于顺序队列(底层都是利用数组作为容器)的实现,我们将采用顺序循环队列的结构来实现,在给出实现方案前先来分析一下为什么不直接使用顺序表作为底层容器来实现。

        实际上采用顺序表实现队列时,入队操作直接执行顺序表尾部插入操作,其时间复杂度为O(1),出队操作直接执行顺序表头部删除操作,其时间复杂度为O(n),主要用于移动元素,效率低,既然如此,我们就把出队的时间复杂度降为O(1)即可,为此在顺序表中添加一个头指向下标front和尾指向下标,出队和入队时只要改变front、rear的下标指向取值即可,此时无需移动元素,因此出队的时间复杂度也就变为O(1)。


        缺点:1.虽然时间复杂度降低,但是空间浪费严重。

                   2.因为顺序表队列的存储单元没有重复利用机制,出现假溢出现象。


    解决方案:

         循环顺序队列:

             //其中front、rear的下标的取值范围是0~size-1,不会造成假溢出。
            front=(front+1)%size;//队头下标
            rear=(rear+1)%size;

            1.front为队头元素的下标,rear则指向下一个入队元素的下标。

            2.当front=rear时,我们约定队列为空。

            3.出队操作改变front下标指向,入队操作改变rear下标指向,size代表队列容量。

            4.约定队列满的条件为front=(rear+1)%size,注意此时队列中仍有一个空的位置,此处留一个空位主要用于避免与队列空的条件front=rear相同。

            5.队列内部的数组可扩容,并按照原来队列的次序复制元素数组 


            //入队的方法:
             public boolean add(T data) {
                 //判断是否满队
                 if (this.front==(this.rear+1)%this.elementData.length){
                     ensureCapacity(elementData.length*2+1);
                 }
                 //添加data
                 elementData[this.rear]=data;
                 //更新rear指向下一个空元素的位置
                 this.rear=(this.rear+1)%elementData.length;
                 size++;
                 return true;
             }

             //扩容方法的实现:
             public void ensureCapacity(int capacity) {
             //如果需要拓展的容量比现在数组的容量还小,则无需扩容
             if (capacity<size)
                 return;

             T[] old = elementData;
             elementData= (T[]) new Object[capacity];
             int j=0;
             //复制元素
             for (int i=this.front; i!=this.rear ; i=(i+1)%old.length) {
                 elementData[j++] = old[i];
             }
             //恢复front,rear指向
             this.front=0;
             this.rear=j;
             }

             //出队的方法:
             public T poll() {
                T temp=this.elementData[this.front];
                this.front=(this.front+1)%this.elementData.length;
                size--;
                return temp;
            }

    
    3.链式队列的设计与实现

        对于链式队列,将使用带头指针front和尾指针rear的单链表实现,front直接指向队头的第一个元素,rear指向队尾的最后一个元素。

    4.队列应用的简单举例

        1.模拟现实世界中的队列,如售票柜台的队列以及其他先到先服务的场景。

        2.计算客户在呼叫中心等待的时间。

        3.异步数据的传输(文件输入输出、管道、嵌套字)

        4.操作系统中的优先级任务执行。

        5.短信群体发送 应用的发布订阅模式。

    5.优先队列的设置与实现(双链表实现)


    原文链接:https://blog.csdn.net/javazejian/article/details/53375004

猜你喜欢

转载自blog.csdn.net/colin_qichao/article/details/81264669
今日推荐