【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)

什么是循环队列?

为充分利用向量空间,克服”假溢出“现象的方法:将向量空间想象为一个首尾相接的圆环,并称这种向量为循环向量。存储在其中的队列称为循环队列(Circular Queue)。

假象成如图:

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第1张图片

但实际上存储空间还是一段连续的空间。

空队列:

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第2张图片

当有元素入队时:

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第3张图片

元素出队:

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第4张图片

元素继续入队时:

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第5张图片

在这里吃瓜群众们可能有个疑问,队尾标记rear 是怎么就突然蹦到front的前面的?

观察我们可以发现当E入队时,rear = 5,

下一个将要入队的是F,那么按照假象的循环队列的话 rear应该变为0 ,也就是(rear+1)%容量,可以多计算几个值尝试,画图尝试一下,容易理解。

然后G入队时 rear+1 即可 。用一个对容量求余的方法,解决了 rear每次 向后推进的 改变。当然也可以判断入队时rear 是否等于容量 ,

当等于容量时,可以直接将rear置为0。

然后继续入队:

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第6张图片

看到这里可能吃瓜群众又有问题了,队列空的时候是rear = front  ,现在满的时候也是 rear = front,这怎么判断呢? 下面来介绍一下解决这个问题的三种方法。

①、增加一个标识flag ,初始的时置为false,每当有元素入队时让flag = true,每当有元素出队时,让flag = false,在触发rear = front 的上一个操作决定了是空还是满。

这样在判断空的时候 ,要判断 front == rear 和 flag 为假要同时成立,即( front == rear ) && !front 整体为真时,队列空。

( front == rear ) && front 时 队列满。

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第7张图片

代码:

#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;
}

要注意在拷贝构造函数中分为三种情况去拷贝

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第8张图片



②、浪费一个空间,当  front = rear 时为空, front = (rear + 1)%容量 未为满。

【c++】模拟实现循环队列 三种方法(标识、浪费一个空间、计数器)_第9张图片

代码:

#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; // 计数器
};


你可能感兴趣的:(模拟实现队列,c++模拟实现循环队列,c++,数据结构)