1.队列概述
队列是一种先进先出(First In First Out(FIFO))的数据结构。
队列是限定只能在一端进行插入操作而在另一端进行删除操作的线性表。
可以进行插入操作的一端称为队列尾(rear)。
可以进行删除的一端称为队列头(front)。
删除操作又称为出队列操作。
2.顺序队列
顺序队列的定义及实现
•队列的顺序存储结构是用一组地址连续的存储空间,依次存放从队列头到队列尾的所有数据元素;
•使用队列头指针(front)和队列尾指针(rear)分别记录队列头和队列尾的位置。
•具有顺序存储结构的队列称为顺序队列。
•在顺序队列中,队列头指针始终指向队列头元素的位置,而队列尾指针指向队列尾元素的下一个元素位置。
•在顺序队列初始化的时候,通常将队列头指针front和队列尾指针rear初始化为0。
•一般情况下,当队列头指针和队列尾指针指向同一个位置时,顺序队列是空队列。
•当一个数据元素入队列时,先将入队列的数据元素添加到rear指向的位置,再对队列尾指针rear进行加1操作,使其后移一个位置,队列头指针front不变;
•当一个数据元素出队列时,队列头指针front后移一个位置,队列尾指针rear不变。
•解决顺序队列出现假溢出现象的一种有效途径是采用循环队列。
•循环队列就是将存放队列元素的存储空间首尾连接起来,构成一个顺序的环形结构。
•在循环队列中,0位置位于数组MaxSize-1之后,即,当队列头指针或队列尾指针等于MaxSize-1时,再向后移就是0位置。
•循环队列中指针front和指针rear的循环后移可以通过对指针用MaxSize进行取余运算来实现。
队列头指针front后移一个位置:front = ( front + 1 ) % MaxSize
队列尾指针rear后移一个位置: rear = ( rear + 1 ) % MaxSize
队列为空的判断条件为:front == rear
队列为满的判断条件为:front == (rear + 1 ) % MaxSize
顺序队列代码实现:
#ifndef _SEQQUEUE_H
#define _SEQQUEUE_H
#include<iostream>
using namespace std;
template<class T>
class SeqQueue
{
public:
SeqQueue(int msize=10):size(msize),front(0),rear(0)
{
ptr=new T[size];
if(ptr==NULL)
{
cout<<"创建对象失败!"<<endl;
exit(1);
}
}
~SeqQueue()
{
delete [] ptr;
}
void push(const T item);
T pop();
void print() const;
T getFront() const;
T getRear() const;
bool isEmpty() const
{
return front==rear;
}
void makeEmpty()
{
front=0;
rear=0;
}
int getSize() const
{
return size;
}
int getElementNum() const
{
return (size+rear-front)%size;
}
private:
int size;
T *ptr;
int front;
int rear;
};
template<class T>
void SeqQueue<T>::push(const T item)
{
//当现在的队列为满时,扩大队列容量为原来容量的2倍
if((rear+1)%size==front)
{
T *tem=new T[size*2];
int start=(front+1)%size;
if(start<2)
{
for(int i=start;i<=rear;i++)
{
tem[i-start]=ptr[i];
}
}
else
{
for(int i=start;i<=size-1;i++)
{
tem[i-start]=ptr[i];
}
for(int i=0;i<=rear;i++)
{
tem[size-start+i]=ptr[i];
}
}
front=2*size-1;
rear=size-2;
size*=2;
delete [] ptr;
ptr=tem;
}
rear=(rear+1)%size;
ptr[rear]=item;
}
template<class T>
T SeqQueue<T>::getFront() const
{
return ptr[front+1];
}
template<typename T>
T SeqQueue<T>::getRear() const
{
return ptr[rear];
}
template<typename T>
T SeqQueue<T>::pop()
{
if(isEmpty())
{
cout<<"The queue is empty!"<<endl;
exit(1);
}
front=(front+1)%size;
return ptr[front];
}
template<typename T>
void SeqQueue<T>::print() const
{
if(isEmpty())
{
cout<<"The queue is empty!"<<endl;
exit(1);
}
int start=(front+1)%size;
if(start<2)
{
cout<<"Front--->";
for(int i=start;i<=rear;i++)
{
cout<<ptr[i]<<"--->";
}
cout<<"Rear"<<endl<<endl;
}
else
{
cout<<"Front--->";
for(int i=start;i<=size-1;i++)
{
cout<<ptr[i]<<"--->";
}
for(int i=0;i<=rear;i++)
cout<<ptr[i]<<"--->";
cout<<endl<<endl;
}
}
#endif
3.链式队列
•队列的链式存储结构又称为链队列。
•链队列就是用一个链表来依次存放从队列头到队列尾的所有数据元素。
•由于在入队列和出队列过程中,队列头或队列尾的位置会发生改变,因此还需要使用两个指针来分别记录队列头和队列尾的当前位置。
•存放队列头地址的指针称为队列头指针,存放队列尾地址的指针称为队列尾指针。
两种形式的链栈:
QueueNode.h代码
#include<string>
template<typename Type> class LinkQueue;
template<typename Type> class QueueNode{
public:
friend class LinkQueue<Type>;
QueueNode(const Type item,QueueNode<Type> *next=NULL)
:m_data(item),m_pnext(next){}
private:
Type m_data;
QueueNode<Type> *m_pnext;
};
LinkQueue.h代码
#include<iostream>
#include "QueueNode.h"
using namespace std;
template<typename Type> class LinkQueue{
public:
LinkQueue():m_prear(NULL),m_pfront(NULL){}
~LinkQueue(){
MakeEmpty();
}
void Append(const Type item); //insert data
Type Delete(); //delete data
Type GetFront(); //get data
void MakeEmpty(); //make the queue empty
void Print(); //print the queue
bool IsEmpty() const{
return m_pfront==NULL;
}
private:
QueueNode<Type> *m_prear,*m_pfront;
};
template<typename Type> void LinkQueue<Type>::MakeEmpty(){
QueueNode<Type> *pdel;
while(m_pfront){
pdel=m_pfront;
m_pfront=m_pfront->m_pnext;
delete pdel;
}
}
template<typename Type> void LinkQueue<Type>::Append(const Type item){
if(m_pfront==NULL){
m_pfront=m_prear=new QueueNode<Type>(item);
}
else{
m_prear=m_prear->m_pnext=new QueueNode<Type>(item);
}
}
template<typename Type> Type LinkQueue<Type>::Delete(){
if(IsEmpty()){
cout<<"There is no element!"<<endl;
exit(1);
}
QueueNode<Type> *pdel=m_pfront;
Type temp=m_pfront->m_data;
m_pfront=m_pfront->m_pnext;
delete pdel;
return temp;
}
template<typename Type> Type LinkQueue<Type>::GetFront(){
if(IsEmpty()){
cout<<"There is no element!"<<endl;
exit(1);
}
return m_pfront->m_data;
}
template<typename Type> void LinkQueue<Type>::Print(){
QueueNode<Type> *pmove=m_pfront;
cout<<"front";
while(pmove){
cout<<"--->"<<pmove->m_data;
pmove=pmove->m_pnext;
}
cout<<"--->rear"<<endl<<endl<<endl;
}