前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

队列

作者头像
青木
发布2018-08-15 15:18:56
4660
发布2018-08-15 15:18:56
举报

队列和栈一样,是一种特殊的线性表。跟栈不同的是,队列的插入和删除分别在线性表的两端进行,因此,队列是一个先进先出(FIFO)的线性表。插入元素的一端叫队尾(back或rear),删除元素的那一端成为队首(front)

队列是一种先进先出的线性表,而栈是一个后进先出(LIFO)的线性表。

还有一种队列是优先级队列,它的删除操作是按照元素的优先级顺序进行的。 C++标准模库STL的队列是一种用数组描述的队列数据结构,它是从STL的双端队列派生的。

队列在现实种的例子很多,比如:

  • 排队结账。先结完账的人先离开,后结完账的后离开。

下面是具体的代码实现:

代码语言:javascript
复制
/*
 * 测试函数
 * arrayQueue.cpp
*/
#include<iostream>
#include"myexceptions.h"
#include"arrayqueue.h"

using namespace std;

int main(void)
{
   arrayQueue<int> q(4);

   //在队列中添加一些元素
   q.push(1);
   cout <<"Queue rear is "<<q.back()<<endl;
   q.push(2);
   cout <<"Queue rear is "<<q.back()<<endl;
   q.push(3);
   cout <<"Queue rear is "<<q.back()<<endl;
   q.push(4);
   cout <<"Queue rear is "<<q.back()<<endl;


   cout <<"Queue should be 1234,front to rear"<<endl;

   if(q.empty())
       cout <<"The queue is empty"<<endl;
   else
       cout <<"The queue is not empty"<<endl;

   cout<<"The queue size is "<<q.size()<<endl;

   while(!q.empty())
   {
       cout <<"Queue front is"<<q.front()<<endl;
       q.pop();
       cout<<"Popped front element"<<endl;
   }

   try{q.pop();}
   catch(queueEmpty message)
   {
       cout<<"Last pop failed"<<endl;
       message.outputMessage();
   }


   arrayQueue<int> r(4);
   r.push(1);
   r.push(2);
   r.push(3);
   r.pop();
   r.pop();
   r.push(4);
   r.push(5);
   r.push(6);
   r.push(7);

   cout<<"Queue should be 34567,front to rear"<<endl;

   if(r.empty())
       cout<<"The queue is empty"<<endl;
   else
       cout<<"The queue is not empty"<<endl;

   cout<<"The queue size is "<<r.size()<<endl;

   while(!r.empty())
   {
       cout<<"Queue front is"<<r.front()<<endl;
       r.pop();
       cout<<"Popped front element"<<endl;
   }
    return 0;
}
代码语言:javascript
复制
/*
 * 队列抽象类定义
 * queue.h
*/
#ifndef QUEUE_H
#define QUEUE_H

using namespace std;

template<class T>
class queue
{
  public:
    virtual ~queue(){}//析构函数


    //判断队列是否为空
    virtual bool empty() const = 0;

    //队列中元素个数
    virtual int size() const = 0;

    //返回队首元素的引用
    virtual T& front() = 0;

    //返回队尾元素的引用
    virtual T& back() = 0;

    //出队
    virtual void pop() = 0;

    //入队
    virtual void push(const T& theElement) = 0;

};


#endif // QUEUE_H
代码语言:javascript
复制
/*
 * 用数组来存储队列元素
 * 我们这里的队列为循环队列
 * 之所以采用循环队列,是因为如果队列是直线的,队列进行多次增减元素操作之后,整个元素一直
 * 向前移动,队列后面会空出来很多空数组,浪费空间。
 * 为了节约存储空间,当然可以在每次元素操作后,对队列中的元素进行移位,但这样会增加时间复杂度。
 *
 * 如果将数组的首尾相连,变成循环数组,那么就不会存在这样的问题了。
 * 每次队列进行元素的增减,元素会在整个环中循环移动,除非某一刻,
 * 整个循环数组的空间已经被占满,这个时候才需要对数组进行扩充,否则,队列
 * 的元素增减操作可以一直不间断的进行,并且不会浪费空间,也不用像单链表一样,
 * 要对元素进行移动。
 * 这样队列的每次增减元素操作的时间复杂度为1,效率最高。
 * arrayQueue.h
*/
#ifndef ARRAYQUEUE_H
#define ARRAYQUEUE_H

#include"queue.h"
#include"myexceptions.h"
#include<sstream>

using namespace std;

template<class T>
class arrayQueue:public queue<T>
{
  public:
    arrayQueue(int initialCapacity = 10)
    {
        if(initialCapacity < 1)
        {
            ostringstream s;
            s<<"Initial capacity = "<<initialCapacity<<"Must be > 0";
            throw illeaglParameterValue(s.str());
        }
        arrayLength = initialCapacity;
        queue = new T[arrayLength];
        theFront = 0;
        theBack = 0;
    }

    //西沟函数
    ~arrayQueue(){delete [] queue;}

    //当队首等于队尾时,我们认为队空
    //这是人为设定的,否则难以判断什么情况下为队空
    bool empty() const
    {
        return theFront == theBack;
    }

    //计算队列中元素个数
    int size() const
    {
        //之所以这么算,画一个环形图就明白了
        //因为循环队列中,起初,theBack > theFront,则,队列中元素的个数就是
        //   theback - theFront
        //经过一系列的增减元素,可能变成theBack < theFront,这时队列中的元素个数应该为
        //      theBack - theFront + arrayLength
        //为了统一这两种计算方式,用一个表达式就可以概括这两种情况,如下
        // (theBack - theFront + arrayLength) % arrayLength
        return (theBack - theFront + arrayLength)%arrayLength;
    }

    //返回队首元素
    T& front()
    {
        if(theFront == theBack)
            throw queueEmpty();
        //因为是循环队列,所以每个操作都要进行取余操作
        //这样,元素在占满数组的时候,会从数组头重新开始存数
        return queue[(theFront + 1)%arrayLength];
    }

    //返回队尾元素
    T& back()
    {
        if(theFront == theBack)
            throw queueEmpty();
        return queue[theBack];
    }

    //元素出队,队首元素出队
    void pop()
    {
        if(theFront == theBack)
            throw queueEmpty();
        theFront = (theFront+1)%arrayLength;
        queue[theFront].~T();
    }

    //元素入队,队尾元素入队
    void push(const T& theElement)
    {
        //循环队列判断队满的条件是:theBack+1 == theFront
        //当队满的时候,就要扩充队容量
        if((theBack+1)%arrayLength == theFront)
        {
            T* newQueue = new T[2*arrayLength];

            //将旧数组的元素复制到新数组中去
            int start = (theFront+1)%arrayLength;
            if(start < 2)
                copy(queue+start,queue+start+arrayLength-1,newQueue);
            else
            {
                copy(queue+start,queue+arrayLength,newQueue);
                copy(queue,queue+theBack+1,newQueue + arrayLength - start);
            }

            theFront = 2 * arrayLength - 1;
            theBack = arrayLength - 2;
            arrayLength *= 2;
            queue = newQueue;
        }

        theBack = (theBack + 1)%arrayLength;
        queue[theBack] = theElement;
    }
private:
    int theFront;
    int theBack;
    int arrayLength;
    T *queue;
};
#endif // ARRAYQUEUE_H
代码语言:javascript
复制
/*
 * 异常处理类
 * myExceptions.h
*/
#ifndef MYEXCEPTIONS_H
#define MYEXCEPTIONS_H
#include<string>

using namespace std;

//参数值异常
class illeaglParameterValue
{
public:
    illeaglParameterValue(string theMessage =
            "Illegal parameter value")
    {
        message = theMessage;
    }
    void outputMessage()
    {
        cout <<message<<endl;
    }
private:
    string message;
};


//队列空异常
class queueEmpty
{
  public:
    queueEmpty(string theMessage =
            "Invalid operation on empty queue")
    {
        message = theMessage;
    }
    void outputMessage()
    {
        cout << message <<endl;
    }
private:
    string message;
};


#endif // MYEXCEPTIONS_H
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档