C#环形队列的简单实现

1.消费者比生产者速度快,等待生产者写入;
2.生产者比消费者快,则最新数据覆盖最先写入数据;
3.实际运用时,根据需求修改缓冲区数据类型。

//环形存取缓冲区
public class RingBuffer
{
    //字段
    /// <summary>
    /// 内部缓冲区
    /// </summary>
    private readonly double[] _buffer;

    /// <summary>
    /// 内部缓冲区容量
    /// </summary>
    private readonly int _nSize;

    /// <summary>
    /// 出队指针(队头)
    /// </summary>
    private int _nHead;

    /// <summary>
    /// 入队指针(队尾)
    /// </summary>
    private int _nTail;

    //属性
    /// <summary>
    /// 获取环形队列包含元素数量
    /// </summary>
    public int Count
    {
        get
        {
            if (_nTail == _nHead) return 0;
            return _nTail > _nHead ? _nTail - _nHead : _nTail + _nSize - _nHead;
        }
    }

    /// <summary>
    /// 获取环形队列队头索引
    /// </summary>
    public int HeadIndex { get { return _nHead; } }

    /// <summary>
    /// 获取环形队列队尾索引
    /// </summary>
    public int TailIndex { get { return _nTail; } }

    //构造函数
    /// <summary>
    /// 设置缓冲区最大容量
    /// </summary>
    /// <param name="nMaxLen">缓冲区最大容量</param>
    public RingBuffer(int nMaxLen)
    {
        _nSize = nMaxLen;
        _nTail = 0;
        _nHead = 0;
        _buffer = new double[nMaxLen];
    }

    //方法
    /// <summary>
    /// 将对象添加到队列结尾处
    /// </summary>
    /// <param name="nData">入队数据</param>
    public void Enqueue(double nData)
    {
        lock (_buffer)
        {
            _buffer[_nTail] = nData;
            _nTail = (_nTail + 1) % _nSize;
            if (_nTail == _nHead) _nHead = (_nHead + 1) % _nSize;//队尾追着队头跑 
        }
    }

    /// <summary>
    /// 移除并返回队头数据
    /// </summary>
    public double Dequeue()
    {
        if (_nTail == _nHead) throw new InvalidOperationException("队列为空");//队列中无数据,抛出错误
        lock (_buffer)
        {
            double dDequeue = _buffer[_nHead];//获取队头数据
            _nHead = (_nHead + 1) % _nSize;
            return dDequeue;//返回队头数据 
        }
    }

    /// <summary>
    /// 清空缓冲区,但不释放缓冲区空间
    /// </summary>
    public void Clear()
    {
        lock (this)
        {
            _nTail = 0;
            _nHead = 0;
        }
    }

    /// <summary>
    /// 获取队头数据,但不移除数据
    /// </summary>
    public double Peek()
    {
        if (_nTail == _nHead) throw new InvalidOperationException("队列为空");//队列中无数据,抛出错误
        lock (_buffer)
        {
            return _buffer[_nHead];
        }
    }

    /// <summary>
    /// 获取队尾数据,但不移除数据
    /// </summary>
    public double Tail()
    {
        if (_nTail == _nHead) throw new InvalidOperationException("队列为空");//队列中无数据,抛出错误
        if (_nTail == 0) return _buffer[_nSize - 1];
        return _buffer[_nTail - 1];
    }

    /// <summary>
    /// 根据(逻辑)索引获取物理索引对应的数据
    /// </summary>
    /// <param name="nDataIndex">(逻辑)索引值</param>
    public double GetDataByIndex(int nDataIndex)
    {
        int pos = GetPosByIndex(nDataIndex);
        return GetDataByPos(pos);
    }

    /// <summary>
    /// 根据逻辑索引获取物理索引
    /// </summary>
    /// <param name="nIndex">逻辑索引</param>
    /// <returns>物理索引</returns>
    public int GetPosByIndex(int nIndex)
    {
        if (nIndex >= _nSize) throw new InvalidOperationException("非法索引");
        if (_nTail == _nHead) throw new InvalidOperationException("队列为空");//队列中无数据,抛出错误
        int pos = _nHead + nIndex;//逻辑索引获取物理索引
        if (pos >= _nSize) pos -= _nSize;//若获取到的物理索引值大于缓冲区最大值,需设置物理索引为正确索引值

        if (IsExistsThePos(pos)) return pos;
        throw new InvalidOperationException("指定索引处超出范围");
    }

    /// <summary>
    /// 获取缓冲区所对应物理索引的值
    /// </summary>
    /// <param name="nPos">物理索引</param>
    public double GetDataByPos(int nPos)
    {
        if (IsExistsThePos(nPos)) return _buffer[nPos];
        throw new InvalidOperationException("指定索引超出范围");
    }

    /// <summary>
    /// 判断物理索引是否存在
    /// </summary>
    /// <param name="nPos">物理索引</param>
    public bool IsExistsThePos(int nPos)
    {
        if (nPos >= _nSize || nPos < 0 || _nHead == _nTail) return false;

        //1.队尾大于队头,物理索引须位于队头和队尾之间
        if (_nTail > _nHead) return nPos >= _nHead && nPos < _nTail;

        //2.队尾小于队头,物理索引不能位于队头和队尾之间
        return nPos < _nTail || nPos >= _nHead;
    }

    /// <summary>
    /// 
    /// 获取缓冲区所有数据
    /// </summary>
    /// <returns>返回数据数组</returns>
    public double[] GetAllData()
    {
        if (_nTail == _nHead) return null; //队列中无数据,返回null

        lock (_buffer)
        {
            var tList = new List<double>();
            if (_nHead < _nTail)
            {
                //队头小于队尾时,从队头取到队尾
                for (int i = _nHead; i < _nTail; i++) tList.Add(_buffer[i]);
            }
            else
            {
                //队头大于队尾时,需分两步获取数据
                //1.从队头数据开始取数据,一直到队列中逻辑上最后一个元素
                for (int i = _nHead; i < _nSize; i++)
                    tList.Add(_buffer[i]);

                //2.从队列逻辑上第一个元素,取到队尾
                for (int i = 0; i < _nTail; i++)
                    tList.Add(_buffer[i]);
            }
            return tList.ToArray();
        }
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值