上一章说到的数组模拟队列存在的问题,问题分析并优化
- 目前数组使用一次就不能用,没有达到复用的效果
- 将这个数组使用算法,改进成一个环形的队列
1.数组模拟环形队列
对前面的数组模拟队列的优化,充分利用数组。因此将数组看做是一个环形的。(通过去模的方式来实现即可)
分析说明:
- 尾索引的下一个为头索引时,表示队列满。即将队列容量空出一个作为约定,这个在做判断队列满的时候需要注意(rear+1)%maxsize==front 满
- rear==front 空
实现思路如下:
- front指针含义调整,front指向队列第一个元素。也就是array[front]就是队列的第一个元素。front初始值=0。
- rear变量的含义调整,rear指向队列的最后一个元素的后一个位置。因为希望空出一个空间作为约定。rear初始值=0。
- 当队列满时,条件是(rear + 1)% maxsize = front , 位满。(PS:rear +1是预留一个位置,不牺牲这个空间会导致无法判断队列空或者满,rear一直自增,也就是说rear是很有可能大于maxsieze的,比如maxsize=5,rear=10,因为rear被加到10,此时rear的实际位置是0。取模式保证党front为0时,rear+1取模为0与front相等)
- 当队列空是,条件是rear==front 。
- 有效的数据个数,(raer + maxsize - front)%maxsize。(为什么要取模,因为是环形同时有rear可能是最大的然后跑到最前面来;假如:rear=1,front=0,maxsize=10 再套入公式中 (1+10-0)%10=1 有效数据为1)
2.代码实现
public class CircleArrayQueue
{
//队列最大值
private int _maxSize;
//队列头部
private int _front;
//队列尾部
private int _rear;
//存储值的数组
private int[] _tempArray;
public CircleArrayQueue(int maxSize)
{
Console.WriteLine($"MaxSize : { maxSize }");
_maxSize = maxSize;
_tempArray = new int[_maxSize];
//front指向队列第一个元素
_front = 0;
//rear指向队列的最后一个元素的后一个位置
_rear = 0;
}
public bool IsFull()
{
return (_rear + 1) % _maxSize == _front;
}
public bool IsEmpty()
{
return _rear == _front;
}
/// <summary>
/// 有效数据个数
/// </summary>
/// <returns></returns>
public int Num()
{
return (_rear + _maxSize - _front) % _maxSize;
}
public void EnQueue(int val)
{
if (IsFull())
{
Console.WriteLine("队列已满,无法加入数据!");
return;
}
//直接插入数据
_tempArray[_rear] = val;
//_rear后移一位,这里必须考虑取模
_rear = (_rear + 1) % _maxSize;
}
public int DeQueue()
{
if (IsEmpty())
{
throw new Exception("队列是空的,无法取出数据!");
}
//这里需要分析出front是指向队列的第一个元素
//1.先把front对应的值保留到一个临时变量
//2.将front后移
//3.将临时保存的变量返回
var tempVal = _tempArray[_front];
_front = (_front + 1) % _maxSize;
return tempVal;
}
public void ShowAll()
{
if (IsEmpty())
{
Console.WriteLine("队列是空的!");
return;
}
Console.WriteLine("显示队列所有内容:");
for (int i = _front; i < _front +