【c++】模擬實現迴圈佇列 三種方法(標識、浪費一個空間、計數器)
什麼是迴圈佇列?
為充分利用向量空間,克服”假溢位“現象的方法:將向量空間想象為一個首尾相接的圓環,並稱這種向量為迴圈向量。儲存在其中的佇列稱為迴圈佇列(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 <cassert> #include <iostream> using namespace std; // 迴圈佇列 flag 方法 template<typename T> 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<T>& 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<T>& operator=(const Queue<T>& que) { if (this != &que) { Queue<T> 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<int> 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<int> 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<int> 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 <cassert>
#include <iostream>
using namespace std;
// 迴圈佇列 浪費一個空間
template<typename T>
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<T>& 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<T>& operator=(const Queue<T>& que)
{
if (this != &que)
{
Queue<T> 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 <cassert>
#include <iostream>
using namespace std;
// 迴圈佇列 Count 計數
template<typename T>
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<T>& 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<T>& operator=(const Queue<T>& que)
{
if (this != &que)
{
Queue<T> 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; // 計數器
};