1. 程式人生 > >【c++】模擬實現迴圈佇列 三種方法(標識、浪費一個空間、計數器)

【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; // 計數器
};