队列本质上是一种特殊的线性表,它是在一端(队首)进行删除操作,而在另外一端(队尾)进行插入操作,它要遵循先进先出的规则。
队首(front) :允许进行删除的一端称为队首。
队尾(rear) :允许进行插入的一端称为队尾。
队列有两种数据存储方式:1、顺序存储结构(静态队列,用数组实现,地址是连续的)。2、链式存储结构(动态队列,用动态链表实现,地址是不连续的)。
一、队列的基本操作:
queue 模板类的定义在头文件中。
与stack 模板类很相似,queue 模板类也需要两个模板参数,一个是元素类型,一个容器类
型,元素类型是必要的,容器类型是可选的,默认为deque 类型。
定义queue 对象的示例代码如下:
queue q1;
queue q2;
queue 的基本操作有:
入队,如例:q.push(x); 将x 接到队列的末端。
出队,如例:q.pop(); 弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:q.front(),即最早被压入队列的元素。
访问队尾元素,如例:q.back(),即最后被压入队列的元素。
判断队列空,如例:q.empty(),当队列空时,返回true。
以下是queue最基本的用法:
#include <cstdlib>
#include <iostream>
#include <queue>
using namespace std;
int main()
{
int e,n,m;
queue<int> q1;
for(int i=0;i<10;i++)
q1.push(i);
if(!q1.empty())
cout<<"dui lie bu kong\n";
n=q1.size();
cout<<n<<endl;
m=q1.back();
cout<<m<<endl;
for(int j=0;j<n;j++)
{
e=q1.front();
cout<<e<<" ";
q1.pop();
}
cout<<endl;
if(q1.empty())
cout<<"dui lie bu kong\n";
system("PAUSE");
return 0;
}
顺序存储结构:这种结构事先要基本确定队列的大小,不支持动态分配存储空间,所以插入和删除元素比较省时,但是会造成空间的浪费。为了节省空间,这里引入了循环队列,本质上也是顺序存储结构。
链式存储结构:可以不需要事先知道队列的大小,支持动态和释放空间,但是插入和删除操作比较耗时,也称链队列。
建议:当事先基本上确定队列的大小,且插入和删除操作比较频繁时,优先考虑循环队列。。
1.循环队列实现:
头文件声明和定义放一块了,只实现了基本的操作,不是很完善,等看了源码再改。。
头文件:在Queue.h头文件中
#ifndef QUEUE_H
#define QUEUE_H
#include<cassert>
#include<iostream>
using namespace std;
template<typename T>
class Queue
{
public:
Queue(int maxsize = 10);
Queue(const Queue<T>& rhs);
Queue<T>& operator=(const Queue<T>& rhs);
~Queue();
public:
bool empty() const;
bool IsFull() const;
int size() const;
void push(const T& data);
void pop();
T& front();
T front() const;
T& back();
T back() const;
private:
T *array;
int Front;
int rear;
int capacity;
};
template<typename T>
Queue<T>::Queue(int maxsize) :Front(0), rear(0),capacity(maxsize)
{
array = new T[maxsize];
assert(array != NULL); //存储分配失败则退出;
}
template<typename T>
Queue<T>::Queue(const Queue<T>& rhs) :Front(rhs.Front), rear(rhs.rear),capacity(rhs.capacity)
{
array = new T[capacity];
for (int i = 0; i != (this->size()); i++)
array[i] = rhs.array[i];
}
template<typename T>
Queue<T>& Queue<T>::operator=(const Queue<T>& rhs)
{
if (this != &rhs)
{
delete[] array;
capacity = rhs.capacity;
Front = rhs.Front;
rear = rhs.rear;
array = new T[capacity];
for (int i = 0; i != (this->size()); i++)
array[i] = rhs.array[i];
}
return *this;
}
template<typename T>
Queue<T>::~Queue()
{
delete[] array;
}
template<typename T>
bool Queue<T>::empty() const
{
return Front == rear; //此处为循环队列,当front==rear时为空。
}
template<typename T>
bool Queue<T>::IsFull() const
{
return(rear + 1) % capacity == Front; //当(rear+1)%capacity==front为满,因为为满时差一个元素,但是可能rear>front,也可能rear<front.
}
template<typename T>
int Queue<T>::size() const
{
return (rear - Front + capacity) % capacity;
}
template<typename T>
void Queue<T>::push(const T& data)
{
if (!IsFull())
{
array[rear] = data;
rear = (rear + 1) % capacity;
}
else //当队列满了之后可进行扩容
{
T *newarray=new T[ 2*capacity ];
for (int i = 0; i != 2*capacity&&!this->empty(); i++)
{
newarray[i] =this-> front();
this->pop();
}
delete [ ] array;
array = newarray;
Front = 0;
array[rear] = data;
rear =this->rear+1;
capacity = 2*capacity;
}
}
template<typename T>
void Queue<T>::pop()
{
if (!empty())
{
//array[Front].~T(); //将队头元素析构掉
Front = (Front + 1) % capacity;
}
else
cout<<"empty queue!"<<endl;
}
template<typename T>
T& Queue<T>::front()
{
if (empty())
cerr << "Error, queue is empty!";
return array[Front];
}
template<typename T>
T Queue<T>::front() const
{
if (empty())
cerr << "Error, queue is empty!";
return array[Front];
}
template<typename T>
T& Queue<T>::back()
{
if (empty())
cerr << "Error, queue is empty!";
return array[rear-1]; //rear类似与尾后指针
}
template<typename T>
T Queue<T>::back() const
{
if (empty())
cerr << "Error, queue is empty!";
return array[rear-1];
}
#endif // QUEUE_H
测试代码:
网上找的代码:
#include<iostream>
#include"Queue.h"
using namespace std;
int main()
{
Queue<int> q(10); //声明队列
int n;
cin >> n;
for (int i = 0; i<n; i++)
q.push(i + 1);
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
if (!q.empty()) //此处需要判断此时队列是否为空
{
q.push(q.front());
q.pop();
}
}
cout << endl;
return 0;
}
2.链队列的实现:
头文件:
在Queue1.h头文件中
#ifndef QUEUE_H1
#define QUEUE_H1
/**********在队头删除节点,队尾添加节点*************/
#include<iostream>
using namespace std;
template<typename T>
class Queue
{
public:
Queue();
~Queue();
bool empty() const;
int size() const;
void clear();
void push(const T & node);
void pop();
T& front();
T front() const;
private: //也可以直接用来链表list直接构造
struct QueueNode
{
T data;
QueueNode* next;
QueueNode(const T& Newdata, QueueNode* nextnode=NULL) :data(Newdata), next(nextnode)
{ }
// QueueNode() = default;
};
QueueNode * Front; //队头指针
QueueNode * rear; // 队尾指针
int count;
};
//此处不设头节点
template<typename T>
Queue<T>::Queue() :Front (NULL), rear (NULL), count(0)
{}
template<typename T>
Queue<T>::~Queue()
{
clear();
}
template<typename T>
void Queue<T>::push(const T & node)
{
if(Front==NULL)
Front=rear=new QueueNode(node);
else
{
QueueNode * newqueuenode = new QueueNode(node);
rear->next = newqueuenode;
rear = newqueuenode;
}
count++;
}
template<typename T>
bool Queue<T>::empty() const
{
return Front==NULL;
}
template<typename T>
int Queue<T>::size() const
{
return count;
}
template<typename T>
void Queue<T>::clear()
{
while (Front)
{
QueueNode * FrontofQueue = Front;
Front = Front->next;
delete FrontofQueue;
}
count = 0;
}
template<typename T>
void Queue<T>::pop()
{
if (empty())
{
cerr << "Error, queue is empty!";
}
QueueNode * FrontofQueue = Front;
Front = Front->next;
delete FrontofQueue;
count--;
}
template<typename T>
T& Queue<T>::front()
{
if (empty())
{
cerr << "Error, queue is empty!";
}
return Front->data;
}
template<typename T>
T Queue<T>::front() const
{
if (empty())
{
cerr << "Error, queue is empty!";
}
return Front->data;
}
#endif // QUEUE_H1
测试代码:
#<iostream>
#include"Queue1.h"
using namespace std;
int main()
{
Queue<int> q; //声明队列
int n;
cin >> n;
for (int i = 0; i<n; i++)
q.push(i + 1);
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
if (!q.empty()) //此处需要判断此时队列是否为空
{
q.push(q.front());
q.pop();
}
}
cout << endl;
return 0;
}