c#环形队列

上一章说到的数组模拟队列存在的问题,问题分析并优化

  • 目前数组使用一次就不能用,没有达到复用的效果
  • 将这个数组使用算法,改进成一个环形的队列

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 + Num(); i++)
        {
            Console.Write($"{ _tempArray[i % _maxSize] }\t");
        }
        Console.WriteLine();
    }

    public void PeekFirst()
    {
        if (IsEmpty())
        {
            Console.WriteLine("队列是空的,无法取出数据!");
            return;
        }

        Console.WriteLine($"查看第一个值:{ _tempArray[_front] }");
    }
}

代码调用

class Program
{
        static void Main(string[] args)
        {
            //MySparseArray sparseArray = new MySparseArray();
            //sparseArray.Print();    
        try
        {
            CircleArrayQueue queue = new CircleArrayQueue(4);
            queue.EnQueue(97);
            queue.EnQueue(98);
            queue.EnQueue(200);
            queue.EnQueue(1000);
            //查看第一个值
            queue.PeekFirst();
            //显示队列里所有的内容
            queue.ShowAll();
            //取出一个值
            Console.WriteLine($"取出一个值:{ queue.DeQueue() }");
            Console.WriteLine($"取出一个值:{ queue.DeQueue() }");
            Console.WriteLine($"取出一个值:{ queue.DeQueue() }");
            queue.PeekFirst();
            queue.EnQueue(200);
            queue.ShowAll();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        Console.Read();
    }
}

运行效果

 

posted @ 2022-02-06 21:46  justerzhu  阅读(130)  评论(0编辑  收藏  举报