什么是循环队列?
为充分利用向量空间,克服”假溢出“现象的方法:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。
假象成如图:
但实际上存储空间还是一段连续的空间。
空队列:
当有元素入队时:
元素出队:
元素继续入队时:
在这里吃瓜群众们可能有个疑问,队尾标记rear 是怎么就突然蹦到front的前面的?
观察我们可以发现当E入队时,rear = 5,
下一个将要入队的是F,那么按照假象的循环队列的话 rear应该变为0 ,也就是(rear+1)%容量,可以多计算几个值尝试,画图尝试一下,容易理解。
然后G入队时 rear+1 即可 。用一个对容量求余的方法,解决了 rear每次 向后推进的 改变。当然也可以判断入队时rear 是否等于容量 ,
当等于容量时,可以直接将rear置为0。
然后继续入队:
看到这里可能吃瓜群众又有问题了,队列空的时候是rear = front ,现在满的时候也是 rear = front,这怎么判断呢? 下面来介绍一下解决这个问题的三种方法。
①、增加一个标识flag ,初始的时置为false,每当有元素入队时让flag = true,每当有元素出队时,让flag = false,在触发rear = front 的上一个操作决定了是空还是满。
这样在判断空的时候 ,要判断 front == rear 和 flag 为假要同时成立,即( front == rear ) && !front 整体为真时,队列空。
( front == rear ) && front 时 队列满。
代码:
#include
#include
using namespace std;
// 循环队列 flag 方法
template
class Queue
{
public:
// 构造函数
Queue(const size_t capacity = 10)
:_front(0)
,_rear(0)
,_capacity(capacity)
,IsFull(false)
{
_capacity = _capacity >= 10 ? _capacity:10;
_array = new T[_capacity];
}
// 拷贝构造函数
Queue(const Queue& que)
:_front(que._front)
,_rear(que._rear)
,_capacity(que._capacity)
,IsFull(que.IsFull)
{
_array = new T[que._capacity];
if (Empty()) // (一) 空 不拷
{
return;
}
if(Full()) // (二) 满 都拷
{
for (size_t idx = 0; idx < _capacity; ++idx)
{
_array[idx] = que._array[idx];
}
return;
}
// (三 )不满 2 种情况
if(_front < _rear) // 1.队头 小于 队尾
{
for (size_t idx = _front; idx < _rear; ++idx)
{
_array[idx] = que._array[idx];
}
}
if (_front > _rear) // 2. 队头 大于 队尾
{
// 先拷贝0-rear 部分
for (size_t idx = 0; idx < _rear; ++idx)
{
_array[idx] = que._array[idx];
}
// 再拷贝 _front- _capacity 部分
for (size_t idx = _front; idx < _capacity; ++idx)
{
_array[idx] = que._array[idx];
}
}
}
// 赋值运算符重载
Queue& operator=(const Queue& que)
{
if (this != &que)
{
Queue temp_que(que);
std::swap(_array, temp_que._array);
_front = que._front;
_rear = que._rear;
_capacity = que._capacity;
IsFull = que.IsFull;
}
return *this;
}
// 元素个数
size_t Length()const
{
// 满的时候 rear 和 front 重合 特殊处理一下
if (Full())
{
return _capacity;
}
// 1. rear < front 左 + 右 0-rear front -capacity
// 2. rear > front rear-front
return (_rear + _capacity - _front)%_capacity;
}
// 队首
T& Front()
{
assert(!Empty());
return _array[_front];
}
const T& Front()const
{
assert(!Empty());
return _array[_front];
}
// 队尾
T& Back()
{
assert(!Empty());
return _array[(_rear-1 + _capacity)%_capacity];
}
const T& Back()const
{
assert(!Empty());
return _array[(_rear-1 + _capacity)%_capacity];
}
// 入队
void Push(const T& data)
{
assert(!Full());
IsFull = true;
_array[_rear] = data;
_rear = (_rear+1)%_capacity;
}
// 出队
void Pop()
{
assert(!Empty());
IsFull = false;
_front = (_front+1)%_capacity;
}
// 判满
bool Full()const
{
if ( (_front==_rear) && IsFull )
{
return true;
}
else
{
return false;
}
}
// 判空
bool Empty()const
{
if ( (_front==_rear) && (!IsFull) )
{
return true;
}
else
{
return false;
}
}
// 析构函数
~Queue()
{
if (_array != NULL)
{
delete[] _array;
_array = NULL;
_front = 0;
_rear = 0;
_capacity = 0;
}
}
private:
T* _array;
size_t _front; // 栈首
size_t _rear; // 栈尾
size_t _capacity; // 容量
bool IsFull; // 标记 用来判断栈满
};
int main()
{
// Queue q1;
// cout << q1.Length() << endl;
// cout << q1.Empty() << endl;
// cout << q1.Full() << endl;
// q1.Push(1);
// q1.Push(2);
// q1.Push(2);
// q1.Push(2);
// q1.Push(2);
// q1.Push(2);
// q1.Push(2);
// q1.Push(2);
// q1.Push(2);
// q1.Push(3);
// cout << q1.Front() << endl;
// cout << q1.Back() << endl;
// cout << q1.Length() << endl;
// cout << q1.Empty() << endl;
// cout << q1.Full() << endl;
Queue q2;
cout << q2.Length() << endl;
cout << q2.Empty() << endl;
cout << q2.Full() << endl;
q2.Push(1);
q2.Push(2);
q2.Push(3);
q2.Push(4);
cout << q2.Front() << endl;
cout << q2.Back() << endl;
cout << q2.Length() << endl;
cout << q2.Empty() << endl;
cout << q2.Full() << endl;
Queue q3;
q3 = q2;
q3.Pop();
q3.Pop();
q3.Pop();
q3.Pop();
cout << q3.Length() << endl;
cout << q3.Empty() << endl;
cout << q3.Full() << endl;
return 0;
}
②、浪费一个空间,当 front = rear 时为空, front = (rear + 1)%容量 未为满。
代码:
#include
#include
using namespace std;
// 循环队列 浪费一个空间
template
class Queue
{
public:
// 构造函数
Queue(const size_t capacity = 10)
:_front(0)
,_rear(0)
,_capacity(capacity)
{
_capacity = _capacity >= 10 ? _capacity:10;
_array = new T[_capacity];
}
// 拷贝构造函数
Queue(const Queue& que)
:_front(que._front)
,_rear(que._rear)
,_capacity(que._capacity)
{
_array = new T[que._capacity];
if (Empty()) // (一) 空 不拷
{
return;
}
if(Full()) // (二) 满 都拷
{
for (size_t idx = 0; idx < _capacity; ++idx)
{
_array[idx] = que._array[idx];
}
return;
}
// (三 )不满 2 种情况
if(_front < _rear) // 1.队头 小于 队尾
{
for (size_t idx = _front; idx < _rear; ++idx)
{
_array[idx] = que._array[idx];
}
}
if (_front > _rear) // 2. 队头 大于 队尾
{
// 先拷贝0-rear 部分
for (size_t idx = 0; idx < _rear; ++idx)
{
_array[idx] = que._array[idx];
}
// 再拷贝 _front- _capacity 部分
for (size_t idx = _front; idx < _capacity; ++idx)
{
_array[idx] = que._array[idx];
}
}
}
// 赋值运算符重载
Queue& operator=(const Queue& que)
{
if (this != &que)
{
Queue temp_que(que);
std::swap(_array, temp_que._array);
_front = que._front;
_rear = que._rear;
_capacity = que._capacity;
}
return *this;
}
// 元素个数
size_t Length()const
{
return (_rear + _capacity - _front)%_capacity;
}
// 队首
T& Front()
{
assert(!Empty());
return _array[_front];
}
const T& Front()const
{
assert(!Empty());
return _array[_front];
}
// 队尾
T& Back()
{
assert(!Empty());
return _array[(_rear-1 + _capacity)%_capacity];
}
const T& Back()const
{
assert(!Empty());
return _array[(_rear-1 + _capacity)%_capacity];
}
// 入队
void Push(const T& data)
{
assert(!Full());
_array[_rear] = data;
_rear = (_rear+1)%_capacity;
}
// 出队
void Pop()
{
assert(!Empty());
_front = (_front+1)%_capacity;
}
// 判满
bool Full()const
{
if ((_rear+1)%_capacity == _front)
{
return true;
}
else
{
return false;
}
}
// 判空
bool Empty()const
{
if ( _front == _rear )
{
return true;
}
else
{
return false;
}
}
// 析构函数
~Queue()
{
if (_array != NULL)
{
delete[] _array;
_array = NULL;
_front = 0;
_rear = 0;
_capacity = 0;
}
}
private:
T* _array;
size_t _front; // 栈首
size_t _rear; // 栈尾
size_t _capacity; // 容量
};
③、设置一个计数器Count ,当count = 0时,为空,count 等于容量时,队列满。代码与上面的方法差别不大,部分地方有修改。
#include
#include
using namespace std;
// 循环队列 Count 计数
template
class Queue
{
public:
// 构造函数
Queue(const size_t capacity = 10)
:_front(0)
,_rear(0)
,_capacity(capacity)
,_count(0)
{
_capacity = _capacity >= 10 ? _capacity:10;
_array = new T[_capacity];
}
// 拷贝构造函数
Queue(const Queue& que)
:_front(que._front)
,_rear(que._rear)
,_capacity(que._capacity)
,_count(que._count)
{
_array = new T[que._capacity];
if (Empty()) // (一) 空 不拷
{
return;
}
if(Full()) // (二) 满 都拷
{
for (size_t idx = 0; idx < _capacity; ++idx)
{
_array[idx] = que._array[idx];
}
return;
}
// (三 )不满 2 种情况
if(_front < _rear) // 1.队头 小于 队尾
{
for (size_t idx = _front; idx < _rear; ++idx)
{
_array[idx] = que._array[idx];
}
}
if (_front > _rear) // 2. 队头 大于 队尾
{
// 先拷贝0-rear 部分
for (size_t idx = 0; idx < _rear; ++idx)
{
_array[idx] = que._array[idx];
}
// 再拷贝 _front- _capacity 部分
for (size_t idx = _front; idx < _capacity; ++idx)
{
_array[idx] = que._array[idx];
}
}
}
// 赋值运算符重载
Queue& operator=(const Queue& que)
{
if (this != &que)
{
Queue temp_que(que);
std::swap(_array, temp_que._array);
_front = que._front;
_rear = que._rear;
_capacity = que._capacity;
_count = que._count;
}
return *this;
}
// 元素个数
size_t Length()const
{
return _count;
}
// 队首
T& Front()
{
assert(!Empty());
return _array[_front];
}
const T& Front()const
{
assert(!Empty());
return _array[_front];
}
// 队尾
T& Back()
{
assert(!Empty());
return _array[(_rear-1 + _capacity)%_capacity];
}
const T& Back()const
{
assert(!Empty());
return _array[(_rear-1 + _capacity)%_capacity];
}
// 入队
void Push(const T& data)
{
assert(!Full());
_count++;
_array[_rear] = data;
_rear = (_rear+1)%_capacity;
}
// 出队
void Pop()
{
assert(!Empty());
_count--;
_front = (_front+1)%_capacity;
}
// 判满
bool Full()const
{
if (_count == _capacity )
{
return true;
}
else
{
return false;
}
}
// 判空
bool Empty()const
{
if ( 0 == _count )
{
return true;
}
else
{
return false;
}
}
// 析构函数
~Queue()
{
if (_array != NULL)
{
delete[] _array;
_array = NULL;
_front = 0;
_rear = 0;
_capacity = 0;
_count = 0;
}
}
private:
T* _array;
size_t _front; // 栈首
size_t _rear; // 栈尾
size_t _capacity; // 容量
size_t _count; // 计数器
};