赞
踩
队列(queue)是只允许在一端进行插入操作,在另一端进行删除操作的线性表,允许插入(也称入队、进队)的一端称为队尾(queue-tail),允许删除(也称出队)的一端称为队头(queue-head)。
如图是一个有5个元素的队列,入队的顺序为a1,a2,a3,a4,a5,出队的顺序依然是a1,a2,a3,a4,a5,即最先入队者最先出队。所以队列中的元素除了具有线性关系外,还具有先进先出(first in first out)的特性。
队列的顺序存储结构称为顺序队列(sequential)。假设队列有n个元素,顺序队列把所有元素存储在数组的前n个单元。如果把队头元素放在数组中下标为0的一端,则入队操作相当于追加,不需要移动元素,其时间性能为O(1);但出队操作的时间性能为O(n),因为要保证剩下的n-1个元素仍然存储在数组的前n-1个单元,所有元素都要向前移动一个位置。
如果放款队列的所有元素必须存储在数组的前n个单元这一条件,就可以得到一种更为有效的存储方法,如上图最后一个结构所示。此时入队和出队操作的时间性能都是O(1),因为没有移动任何元素,但是队头和队尾都是活动的,因此需要设置队头、队尾两个位置变量front和rear,入队时rear加1,出队时front加1.并且约定:front指向队头元素的前一个位置,rear指向队尾元素的位置。
在顺序队列中,随着队列的插入和删除操作,整个队列向数组的高端移过去,从而产生了队列的“单向移动性”。当元素被插入到数组下标最大的位置之后,数组空间就用尽了,尽管此时数组的低端还有空闲空间,这种现象叫做假溢出(false overflow)。
解决假溢出的方法是将存储队列的数组看成是头尾相接的循环结构,即允许队列直接从数组中下标最大的位置延续到下标最小的位置。这可以通过取模操作来实现,设存储队列的数组长度为QueueSize,操作语句为rear = (rear + 1) % QueueSize。队列的这种头尾相接的顺序存储结构称为循环队列(circular queue)。
如下图(a)和图©所示,队列中只有一个元素,执行出队操作,则队头位置在循环意义下加1后与队尾位置相等,即队空的条件是front = rear。
如下图(a)和图©所示,数组中只有一个空闲单元,执行入队操作,则队尾位置在循环意义下加1后与队头位置相等,即队满的条件也是front = rear。
这样如何区分队空和队满的情况呢,可以浪费一个数组元素的空间,把图(a)和图©的情况视为队满,此时队尾位置和队头位置正好相差1,即队满的条件是 **(rear + 1) % QueueSize = front **
const int QueueSize = 100;
template <typename DataType>
class CirQueue{
public:
CirQueue(); //构造函数,初始化空队列
~CirQueue(); //析构函数
void EnQueue(DataType x); //入队操作,将元素x入队
DataType DeQueue(); //出队操作,将元素x出队
DataType GetHead(); //取队头元素,并不删除
int Empty(); //判断队列是否为空
private:
DataType data[QueueSize]; //存放队列元素的数组
int front, rear; //游标,队头指针和队尾指针
};
template <typename DataType> CirQueue<DataType>::CirQueue(){ //初始化一个空的循环队列只需将队头front和队尾rear同时指向数组的某一个位置,一般是数组的高端 rear = front = QueueSize - 1; } template <typename DataType> void CirQueue<DataType>::EnQueue(DataType x){ if((rear + 1) % QueueSize == front) throw "上溢"; rear = (rear + 1) % QueueSize; data[rear] = x; } template <typename DataType> DataType CirQueue<DataType>::DeQueue(){ if(rear == front) throw "下溢"; front = (front + 1) % QueueSize; return data[front]; } template <typename DataType> DataType CirQueue<DataType>::GetHead(){ if(rear == front) throw "下溢"; return data[(front + 1) % QueueSize]; } template <typename DataType> int CirQueue<DataType>::Empty(){ return front == rear; }
队列的连接存储结构称为链队列(linked queue),通常用单链表表示,其结点结构与单链表的结点结构相同。为了使空队列和非空队列的操作一致,链队列也加上头结点。根据队列的先进先出特性,为了操作上的方便,设置队头指针指向链队列的头结点,队尾指针指向终端节点。
template <typename DataType> struct Node{ DataType data; Node<DataType> *next; }; template <typename DataType> class LinkQueue{ public: LinkQueue(); //初始化空的链队列 ~LinkQueue(); //释放链队列的存储空间 void EnQueue(DataType x); //入队操作,将元素x入队 DataType DeQueue(); //出队操作,将队头元素出队 DataType GetHead(); //取链队列的队头元素 int Empty(); //判断链队列是否为空 private: Node<DataType> *front, *rear; //队头和队尾指针 };
template <typename DataType> LinkQueue<DataType>::LinkQueue(){ Node<DataType> *s = nullptr; s = new Node<DataType>; s->next = nullptr; front = rear = nullptr; } template <typename DataType> LinkQueue<DataType>::~LinkQueue(){ Node<DataType> *p; while(front!=nullptr){ p = front; front = front->next; delete p; } } template <typename DataType> void LinkQueue<DataType>::EnQueue(DataType x){ Node<DataType> *s = nullptr; s = new Node<DataType>; s->data = x; s->next = nullptr; rear->next = s; rear = s; } template <typename DataType> DataType LinkQueue<DataType>::DeQueue(){ DataType x; Node<DataType> *p = nullptr; if(rear == front) throw "下溢"; p = front->next; x = p->data; front->next = p->next; if(p->next == nullptr) rear = front; delete p; return x; } template <typename DataType> DataType LinkQueue<DataType>::GetHead(){ DataType x; Node<DataType> *p = nullptr; if(rear == front) throw "下溢"; p = front->next; x = p->data; return x; } template <typename DataType> int LinkQueue<DataType>::Empty(){ return front == rear; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。