数据结构与算法《队列》

简介:
     队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头
     队列的数据元素又称为队列元素。在队列中插入一个队列元素称为入队,从队列中删除一个队列元素成为出队。因为队列只允许在一端插入,在另一端删除,所以只有最早进入队列的元素才能最先从队列中删除,故队列又称为先进先出(FIFO—first in first out)线性表。

顺序队列:
     建立顺序队列结构必须为其静态分配或动态申请一片连续的存储空间,并设置两个指针进行管理。一个是队头指针front,它指向队头元素;另一个是队尾指针rear,它指向下一个入队元素的存储位置,如下图所示:

                         数据结构与算法《队列》_第1张图片

     每次在队尾插入一个元素时,rear增1;每次在队头删除一个元素时,front增1。随着插入和删除操作的进行,队列元素的个数不断变化,队列所占的存储空间也在为队列结构所分配的连续空间中移动。当front=rear时,队列中没有任何元素,称为空队列。当rear增加到指向分配的连续空间之外时,队列无法再插入新元素,但这时往往还有大量可用空间未被占用,这些空间是已经出队的队列元素曾经占用过得存储单元

顺序队列中的溢出现象:
     (1)“下溢”:当队列为空时,做出队运算产生的溢出现象。“下溢”是正常现象,常用作程序控制转移的条件。
     (2)“真上溢”:当队列满时,做进栈运算产生空间溢出的现象。“真上溢”是一种出错状态,应设法避免。
     (3)“假上溢”:由于入队和出队操作中,头尾指针只增加不减小,致使被删元素的空间永远无法重新利用。当队列中实际的元素个数远远小于向量空间的规模时,并且尾指针已超越向量空间的上界而不能做入队操作。该现象称为”假上溢”现象。

循环队列:
     在实际使用队列时,为了使队列空间能重复使用(克服“假溢出”现象),往往对队列的使用方法稍加改进:无论插入或删除,一旦rear指针增1或front指针增1时超出了所分配的队列空间,就让它指向这片连续空间的起始位置。自己从MaxSize-1增1变到0,可用取余运算rear%MaxSize和front%MaxSize来实现。这实际上是把队列空间想象成一个环形空间,环形空间中的存储单元循环使用,用这种方法管理的队列也就称为循环队列。除了一些简单应用之外,真正实用的队列是循环队列。

  1. 如何判断循环队列是否为空?
    解决办法:当front=rear时,循环队列为空,如上图1所示。
  2. 如何判断循环队列是否为满?
         由于入队时尾指针向前追赶头指针,出队时头指针向前追赶尾指针,故队空和队满时头尾指针均相等。因此,我们无法通过front=rear来判断队列“空”还是“满”。
    解决办法一:增加一个参数,用来记录数组中当前元素的个数;
    解决办法二:少用一个存储空间,也就是循环队列的最后一个剩余存储空间不用,当(rear+1)%maxsiz=front时,队列满,见图5。
                                   数据结构与算法《队列》_第2张图片

数组循环队列C++实现:
longQueue.hxx

#include 
#include 

/*
    功能介绍:
                用动态分配数组实现循环队列。
    说    明: 
                (1)设有标识以区别队列是"空"还是"满";
                (2)少用一空间, 约定"队列头指针在队尾指针的下一位置"上作为队列为"满"状态的标志。
 */

template <typename T>
class MyQueue
{
    public:
        MyQueue(int n = 10);        // 构造函数, 默认初始化10个元素的循环队列
        ~MyQueue();            // 析构函数
        bool EnterQueue(T element); // 向队列插入元素
        bool DeleteQueue(T &element);   // 从队列弹出元素
        int QueueLength();      // 返回队列的长度
        bool getEmpty();        // 判断空
        bool getFull();         // 判断满
    private:
        T *base;            // 动态分配队列指针
        int front;          // 队头指针
        int rear;           // 队尾指针
        int maxsize;            // 最大队列长度(包括一个剩余空间的长度)
        bool isEmpty;           // 队列空标识,1:空,0:非空
        bool isFull;            // 队列满标识,1:满,0:非满
};

    template <typename T>
MyQueue::MyQueue(int n)
{
    assert(n > 0);
    base = (T*)new T[n + 1];
    assert(base != NULL);
    memset(base, 0x00, n);
    front = rear = 0;   // 队头和队尾指针分别指向第一个元素
    maxsize = n + 1;
    isEmpty = true;
    isFull = false;
}

    template <typename T>
MyQueue::~MyQueue()
{
    delete [] base;
}

    template <typename T>
bool MyQueue::EnterQueue(T element)      // 入队
{
    if ( (rear + 1) % maxsize == front ) {  // 判断队列是否满
        return false;
    }
    else {
        base[rear] = element;
        rear = (rear + 1) % maxsize;        // 移动队尾指针
        if ( (rear + 1) % maxsize == front ) {  // 入队后判断队列是否为满
            isFull = true;
        }
        isEmpty = false;
        return true;
    }
}

    template <typename T>
bool MyQueue::DeleteQueue(T &element)    // 出队
{
    if (front == rear) {    // 判断队列是否为空
        return false;
    }
    else {
        element = base[front];
        front = (front + 1) % maxsize;
        if (front == rear) {    // 判断队列是否为空
            isEmpty = true;
        }
        isFull = false;
        return true;
    }
}
    template <typename T>
int MyQueue::QueueLength()
{
    return (rear - front + maxsize) % maxsize;
}

    template <typename T>
bool MyQueue::getEmpty()
{
    return isEmpty;
}

    template <typename T>
bool MyQueue::getFull()
{
    return isFull;
}

main.cpp

#include 
#include "longQueue.hxx"

using namespace std;

int main(int argc, char **argv)
{
        MyQueue<int> my(10);    // 定义具有10个元素的循环队列

    int i;
        for (i = 0; i < 7; ++i) {   // 入队若干个元素
                my.EnterQueue(i + 1);
        }

        cout << "+++++ 队列长度:" << my.QueueLength() << " +++++" << endl;

        int element;
        for (i = 0; i < 2; ++i) {   // 从队列中弹出若干元素
                my.DeleteQueue(element);
        cout << "----- 第" << i + 1 << "个出队元素为:" << element << " -----" << endl;
        }

        cout << "+++++ 队列长度:" << my.QueueLength() << " +++++" << endl;

    if ( !my.getEmpty() && !my.getFull() )
        cout << "队列既不空,也不满!" << endl;

    return 0;
}

你可能感兴趣的:(数据结构与算法,数据结构,算法,队列,循环队列,顺序队列)