队列和上篇提到的栈类似,本质上都是特殊的线性表,它是在一端(队头)进行删除操作,另一端(队尾)进行插入操作,遵守先进先出的规则。。
既然队列也是线性表,当然也有两种数据存储方式:
顺序存储结构:这种结构事先要基本确定队列的大小,不支持动态分配存储空间,所以插入和删除元素比较省时,但是会造成空间的浪费。
为了节省空间,这里引入了循环队列,本质上也是顺序存储结构。
链式存储结构:可以不需要事先知道队列的大小,支持动态和释放空间,但是插入和删除操作比较耗时,也称链队列。
建议:当事先基本上确定队列的大小,且插入和删除操作比较频繁时,优先考虑循环队列。。
关于顺序队列还有两句要说的:
顺序队列可以移动数据,亦可以移动头指针
第一种就是这样:这样的话一旦数据过于复杂,就需要大量挪动数据:
下来我们来看看第二种:也就是挪动队头
也就是这样,但是你会发现这样如果再插入数据,就会造成“假溢出的现象”。
循环队列其实和顺序队列差不多,就是一个环状的队列:
下面就是循环队列和链式队列的实现:
这是将声明和定义都放在了头文件里面:
#pragma once
#define QUEUE_H
#include<cassert>
#include <iostream>
using namespace std;
template<typename T>
class Queue
{
public:
Queue(int maxsize = 10);
Queue(const Queue<T>&x);
Queue<T>&operator = (const Queue<T>&x);
~Queue();
public:
bool Empty()const;
bool IsFull()const;
int Size()const;
void Push(const T&data);
void Pop();
T& front()
{
if (Empty())
cerr << "Error,Queue is Empty";
return array[_front];
}
T front()const
{
if (Empty())
cerr << "Error,Queue is Empty";
return array[_front];
}
T& back()
{
if (Empty())
cerr << "Error,Queue is Empty";
return array[_rear - 1];
}
T back()const
{
if (Empty())
cerr << "Error,Queue is Empty";
return array[_rear - 1];
}
private:
T* array;
int _front;
int _rear;
int _capacity;
};
#include"Queue.h"
template<typename T>
Queue<T>::Queue(int maxsize)
:_front(0)
, _rear(0)
, _capacity(maxsize)
{
array = new T[maxsize];
assert(array != nullptr);
}
template<typename T>
Queue<T>::Queue(const Queue<T>&x)
:_front(x._front)
, _rear(x._rear)
, _capacity(x._capacity)
{
array = new T[_capacity];
for (int i = 0;i != (this->Size());i++)
{
array[i] = x.array[i];
}
}
template<typename T>
Queue<T>&Queue<T>::operator = (const Queue<T>&x)
{
if (this != x);
{
delete[] array;
_capacity = x.capacity;
_front = x._front;
_rear = x._rear;
array = new T[capacity];
for (int i = 0;i != (this->Size());i++)
{
array[i] = x.array[i];
}
}
return *this;
}
template<typename T>
Queue<T>::~Queue()
{
delete[] array;
}
template<typename T>
bool Queue<T>::Empty()const
{
return _front == _rear;
}//判空
template<typename T>
bool Queue<T> ::IsFull()const
{
return (_rear + 1) % _capacity == _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())
{
_front = (_front + 1) % _capacity;
}
else
cout << "Queue is Empty" << endl;
}
下面就是测试代码:
#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;
}
之后再来实现一下链式队列:
链式队列和链表其实差不多,就是只能实现尾插
这个是头文件(定义和声明)
#pragma once
#include<iostream>
using namespace std;
template <typename T>
class LinkQueue
{
public:
LinkQueue();
~LinkQueue();
bool Empty()const;
int Size()const;
void Clear();
void Push(const T& node);
void Pop();
T& front();
T front()const;
private:
class QueueNode
{
public:
T _data;
QueueNode *_next;
QueueNode(const T& Newdata, QueueNode* nextnode = nullptr)
:_data(Newdata)
, _next(nextnode)
{}
};
QueueNode * _front;
QueueNode* _rear;
int count;
};
template<typename T>
LinkQueue<T>::LinkQueue()
:_front(nullptr)
, _rear(nullptr)
, count(0)
{}
template<typename T>
LinkQueue<T>::~LinkQueue()
{
Clear();
}
template<typename T>
void LinkQueue<T>::Push(const T &node)
{
if (_front == nullptr)
{
_front = _rear = new QueueNode(node);
}
else {
QueueNode *newqueuenode = new QueueNode(node);
_rear->_next = newqueuenode;
_rear = newqueuenode;
}
count++;
}
template<typename T>
int LinkQueue<T>::Size()const
{
return count;
}
template<typename T>
bool LinkQueue<T>::Empty()const
{
return _front == nullptr;
}
template<typename T>
void LinkQueue<T>::Clear()
{
while (_front)
{
QueueNode * frontofqueue = _front;
_front = _front->_next;
delete frontofqueue;
}
count = 0;
}
template<typename T>
void LinkQueue<T>::Pop()
{
if (Empty())
{
cerr << "LinkQueue is empty" << endl;
}
QueueNode *frontofqueue = _front;
_front = _front->_next;
delete frontofqueue;
count--;
}
template<typename T>
T& LinkQueue<T>::front()
{
if (Empty())
{
cerr << "LinkQueue is empty" << endl;
}
return _front->_data;
}
template<typename T>
T LinkQueue<T>::front()const
{
if (Empty())
{
cerr << "LinkQueue is empty" << endl;
}
return _front->_data;
}
下面是测试代码:
#include<iostream>
#include"LinkQueue.h"
using namespace std;
int main()
{
LinkQueue<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;
}