C#实现队列及环形队列(数组)

队列(Queue)

介绍

队列是一种有序列表,只允许对队尾(rear)进行删除操作,对队首(front)进行删除操作,即先入先出(FIFO)。

实现队列需要的内部元素

元素含义
maxSize代表能够存储的数据的个数
front指向队首
rear指向队尾
array[]用于存储数据
void Enqueue(int n)将元素n入队
int Dequeue()将队尾元素出队,同时元素个数-1
int Peek()返回队尾元素,元素个数不变
bool IsFull()队列已满返回true,未满返回false
bool IsEmpty()队列为空返回true,不为空返回false

数组模拟一般队列

内部元素含义

元素含义
maxSize代表能够存储的数据的个数
front指向数组内第一个元素的前一位置
rear指向数组内最后一个元素的位置
array[]用于存储数据
void Enqueue(int n)将元素n入队
int Dequeue()将队尾元素出队,同时元素个数-1
int Peek()返回队尾元素,元素个数不变
bool IsFull()队列已满返回true,未满返回false
bool IsEmpty()队列为空返回true,不为空返回false

分析思路

入队

1.判断队列是否已满,如果已满则直接返回
2.如果未满则将元素加入队列,并将rear向后移

出队

1.判断队列是否为空,如果为空抛出异常
2.如果不为空则返回下标为 front+1 的元素,并将front后移

Peek

1.判断队列是否为空,如果为空抛出异常
2.如果不为空则返回下标为 front+1 的元素

IsFull

rear == maxSize-1 时返回true

IsEmpty

rear == front 时返回true

图解

在这里插入图片描述

代码实现

    class ArrayQueue
    {
        private int _maxSize;    //最大容量
        private int _front;      //队列头  指向队列头的前一个位置
        private int _rear;       //队列尾  指向队列尾的数据
        private int[] _arr;      //用于存放数据的数组

        public ArrayQueue(int maxSize)
        {
            this._maxSize = maxSize;
            this._front = -1;
            this._rear = -1;
            _arr = new int[_maxSize];
        }

        //判断是否已满
        public bool IsFull()
        {
            return _rear == _maxSize - 1;
        }

        //判断队列是否为空
        public bool IsEmpty()
        {
            return _rear == _front;
        }

        //入队
        public void Enqueue(int n)
        {
            //判断队列是否已满
            if (IsFull())
            {
                Console.WriteLine("队列已满,不能增加数据");
                return;
            }
            _arr[++_rear] = n;
        }

        //出队
        public int Dequeue()
        {
            //判断队列是否为空
            if (IsEmpty())
            {
                throw new Exception("队列为空");
            }
            return _arr[++_front];
        }

        //显示头数据
        public int Peek()
        {
            //判断是否为空
            if (IsEmpty())
            {
                throw new Exception("队列为空");
            }
            return _arr[_front + 1];
        }

    }

总结

在这里插入图片描述

可以看出,当rear到达数组的最后一个位置,而front指向数组中间位置时,front之前的空间就是浪费的 (如上图),而此种方法实现的队列做不到数组空间的复用

虽然在数组的前半部分仍然有未被利用的空间,但是当想要继续往队列中添加元素时就会产生数组越界的错误,也被称作“假溢出”。

因而出现了环形队列

环形队列

什么是环形队列

为了达到数组空间的复用,或者说是为了解决“假溢出”的问题,我们把队列的头部和尾部相连接,而这种头尾相接,可以看作是一个“环”的队列就是环形队列。

图解

假设这样一个场景,先将队列存满,然后两次出队,然后再向队列中添加两个元素,可以得到这样一个结果
rear == front == 1 如图所示
在这里插入图片描述
当队列为空和队列已满时 rear 都等于 front,此时判断队列是空队列还是满队列的方法有两种

1.设置一个标记变量,当 front == rear 且 flag == false 时队列为空,当 front == rear 且 flag == true 时队列为满。
2. 当队列为空时 front == rear, 当队列为满时修改其条件,保留一个空置空间。也就是说队列满的时候数组中还有一个空闲的空间,此时就认为队列时满的。

下面介绍第二种解决方案

内部元素含义

元素含义
maxSize代表能够存储的数据的个数+1
front指向数组内第一个元素
rear指向数组内最后一个元素后一位置
array[]用于存储数据
void Enqueue(int n)将元素n入队
int Dequeue()将队尾元素出队,同时元素个数-1
int Peek()返回队尾元素,元素个数不变
bool IsFull()队列已满返回true,未满返回false
bool IsEmpty()队列为空返回true,不为空返回false
int GetSize()获取数组中有效值的个数

分析思路

入队

1.判断队列是否已满,如果已满则直接返回
2.如果未满则将元素加入队列,并将rear向“后移”

后移代码

_rear = (_rear + 1) % _maxSize;		//通过取模来达到 “循环” 的目的
出队

1.判断队列是否为空,如果为空抛出异常
2.如果不为空则返回下标为 front 的元素,并将front后移

后移代码

_front = (_front + 1) % _maxSize;	//通过取模来达到 “循环” 的目的
Peek

1.判断队列是否为空,如果为空抛出异常
2.如果不为空则返回下标为 front 的元素

IsFull

当 (rear+1) % maxSize == front 时队列已满(返回 true)

IsEmpty

rear == front 时返回true

GetSize

当 rear > front 时,有效元素的个数为 rear - front
而当 rear < front 时,此时可以将数组看成两段,第一段是 front 到 maxSize,第二段是 rear - 0 ,数组中有效元素的个数是 rear - front + maxSize

综上可得,队列中有效元素的个数为
(rear - front + maxSize) % maxSize

代码实现

    class CircleQueue
    {
        private int _maxSize;    //最大容量
        private int _front;      //队列头  指向第一个元素
        private int _rear;       //队列尾  指向最后一个元素的后一位置
        private int[] _arr;      //用于存放数据的数组

        public CircleQueue(int maxSize)
        {
            this._maxSize = maxSize;
            _arr = new int[_maxSize];
            _front = 0;
            _rear = 0;
        }

        //判断是否已满
        public bool IsFull()
        {
            return ((_rear + 1) % _maxSize) == _front;
        }

        //判断队列是否为空
        public bool IsEmpty()
        {
            return _rear == _front;
        }

        //添加数据
        public void Enqueue(int n)
        {
            //判断队列是否已满
            if (IsFull())
            {
                Console.WriteLine("队列已满,不能增加数据");
                return;
            }

            //此时rear指向的是最后一个元素的后一位置,因此可以直接添加
            _arr[_rear] = n;
            //将 rear 后移
            _rear = (_rear + 1) % _maxSize;
        }

        //出队
        public int Dequeue()
        {
            //判断队列是否为空
            if (IsEmpty())
            {
                throw new Exception("队列为空");
            }

            //此时front 指向第一个元素
            int val = _arr[_front];

            //将front后移
            _front = (_front + 1) % _maxSize;
            return val;
        }

        //求出当前队列有效数据的个数
        private int GetSize()
        {
            return (_rear + _maxSize - _front) % _maxSize;
        }

        //显示头数据
        public int Peek()
        {
            //判断是否为空
            if (IsEmpty())
            {
                throw new Exception("队列为空");
            }
            return _arr[_front];
        }

    }

两种队列内部元素的对比

元素环形队列顺序存储结构队列
maxSize实际能够存储的元素个数为maxSize-1代表能够存储的数据的个数
front指向数组内第一个元素指向数组内第一个元素的前一位置
rear指向数组内最后一个元素后一位置指向数组内最后一个元素
bool IsFull()(rear+1) % maxSize == frontrear == maxSize -1
bool IsEmpty()rear == frontrear == front
int GetSize()(rear - front + maxSize) % maxSizerear - front
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值