環形隊列原理及基於C++的實現

環形隊列原理及基於C++的實現


一、環形隊列的作用

在嵌入式軟件中,環形隊列的地位是非常重要的。由於經常需要用到串口、SPI等通訊接口,爲了避免高速CPU等待低速通訊外設的情況出現,通常需要給通訊接口的數據發送和接收分配緩存,而這一緩存需要實現先入先出這一功能,而環形隊列正好擁有這一功能。

二、環形隊列的原理

環形隊列任然是基於數組實現的,但是爲了更加形象化的描述,我們用如下圖表示:
在這裏插入圖片描述

  1. 圖中有兩個指針(其實就是兩個變量,因爲在這裏有指示作用,所以這裏理解爲指針_writeIndex、_readIndex,一個指示隊頭,一個指示隊尾。
  2. _writeIndex和_readIndex互相追趕着,這個追趕過程就是隊列添加和刪除的過程,如果_writeIndex追到_readIndex說明隊列滿了(通常會留一個位置),如果_readIndex追到_writeIndex說明隊列爲空。
  3. 我們把它掰彎,用的是求餘,這樣這兩個值就不會跑出最大範圍,並且可以實現首位連接的效果,所以說對於循環隊列我們必須給定最大值MAXQSIZE。

三、環形隊列的軟件實現

#pragma once
#include <string.h>

template<typename T>
class RingQueue
{
public:
    // 設置存儲空間,及其大小。
    void setBuff(T *buff, unsigned int len);

    // 從尾部加入一個數據。
    void push(T d);

    // 從頭部彈出一個數據。
    T pop(void);

    // 從頭部彈出若干數據。
    unsigned int copyOut(T *buf, unsigned int len);

	// 從尾部加入若干數據。
	unsigned int copyIn(T *buf, unsigned int len);

    // 頭部數據。
    T head(bool &isok);

    // 頭部數據。
    T head();

    // 尾部數據。
    T tail(bool &isok);

    // 當前數據個數。
    unsigned int size(void);

    // 獲取指定位置的數據。
    T &at(int index);

    // 空/滿判斷。
    inline bool isEmpty(void);
    inline bool isFull(void);

    // 清空。
    void clear(void);

    // 構造與析構。
    RingQueue();
    virtual ~RingQueue();

private:
    T *_buff;
    unsigned int _len;
    unsigned int _writeIndex;
    unsigned int _readIndex;
};

/**************************************************************************************************
 * 功能: 設置存儲空間,及其大小。
 * 參數:
 * 		buff: 數據空間。
 * 		len:數據空間長度。
 *************************************************************************************************/
template<typename T>
void RingQueue<T>::setBuff(T *buff, unsigned int len)
{
    _buff = buff;
    _len = len;
    _writeIndex = 0;
    _readIndex = 0;
}

/**************************************************************************************************
 * 功能: 從尾部加入一個數據。
 * 參數:
 * 		d: 新數據。
 *************************************************************************************************/
template<typename T>
void RingQueue<T>::push(T d)
{
    if (isFull())
    {
        return;
    }

    _buff[_writeIndex] = d;
    _writeIndex = (_writeIndex + 1) % _len;
}

/**************************************************************************************************
 * 功能: 從頭部彈出一個數據。
 * 返回: 
 *      頭部數據。
 *************************************************************************************************/
template<typename T>
T RingQueue<T>::pop(void)
{
    if (isEmpty())
    {
        return 0;
    }

    T d = _buff[_readIndex];
    _readIndex = (_readIndex + 1) % _len;
    return d;
}

/**************************************************************************************************
 * 功能:從頭部彈出若干個數據
 * 參數:
 *      buf: 用來接收數據的緩存
 *      len: 需要彈出的數據個數
 * 返回:
 *      實際彈出數據個數。
 *************************************************************************************************/
template<typename T>
unsigned int RingQueue<T>::copyOut(T *buf, unsigned int len)
{
    if (isEmpty())
    {
        return 0;
    }
    if(len > size())
    {
        len = size();
    }
    if(_readIndex + len > _len) // 分兩段
    {
        memcpy(&buf[0], &_buff[_readIndex], (_len - _readIndex) * sizeof(T));
        memcpy(&buf[_len - _readIndex], &_buff[0], (len + _readIndex - _len) * sizeof(T));
    }
    else        // 一段
    {
        memcpy(&buf[0], &_buff[_readIndex], len * sizeof(T));
    }

    _readIndex = (_readIndex + len) % _len;
    return len;
}

/**************************************************************************************************
 * 功能:從尾部加入若干個數據
 * 參數:
 *      buf: 用來接收數據的緩存
 *      len: 需要彈出的數據個數
 * 返回:
 *      實際加入數據個數。
 *************************************************************************************************/
template<typename T>
unsigned int RingQueue<T>::copyIn(T *buf, unsigned int len)
{
	if(len > _len - size() - 1)
	{
		len = _len - size() - 1;
	}

	if(_writeIndex + len > _len) // 分兩段
    {
    	memcpy(&_buff[_writeIndex], &buf[0], (_len - _writeIndex) * sizeof(T));
		memcpy(&_buff[0], &buf[_len - _writeIndex], (len + _writeIndex - _len) * sizeof(T));
	}
	else // 一段
	{
		memcpy(&_buff[_writeIndex], &buf[0], len * sizeof(T));
	}
	_writeIndex = (_writeIndex + len) % _len;

	return len;
}

/**************************************************************************************************
 * 功能: 得到頭部數據。
 * 參數: 
 *      isOK: 獲取是否成功
 * 返回: 
 *      頭部數據。
 *************************************************************************************************/
template<typename T>
T RingQueue<T>::head(bool &isOK)
{
    if (isEmpty())
    {
        isOK = false;
        return 0;
    }

    isOK = true;
    return _buff[_readIndex];
}

/**************************************************************************************************
 * 功能: 得到頭部數據。
 * 返回: 
 *      頭部數據。
 *************************************************************************************************/
template<typename T>
T RingQueue<T>::head()
{
    return _buff[_readIndex];
}

/**************************************************************************************************
 * 功能: 得到尾部數據。
 * 參數: 
 *      isOK: 獲取是否成功
 * 返回: 
 *      尾部數據。
 *************************************************************************************************/
template<typename T>
T RingQueue<T>::tail(bool &isOK)
{
    if (isEmpty())
    {
        isOK = false;
        return 0;
    }

    isOK = true;
    return _buff[(_writeIndex - 1 + _len) % _len];
}

/**************************************************************************************************
 * 功能: 當前數據個數。
 * 返回: 
 *      數據個數。
 *************************************************************************************************/
template<typename T>
unsigned int RingQueue<T>::size(void)
{
    unsigned int wi = _writeIndex;
    unsigned int ri = _readIndex;
    return (wi >= ri) ? (wi - ri) : (_len - ri + wi);
}

/**************************************************************************************************
 * 功能: 獲取指定位置的數據。
 * 參數:
 *      index:數據位置。
 * 返回: 
 *      指定位置的數據。
 *************************************************************************************************/
template<typename T>
T &RingQueue<T>::at(int index)
{
    return _buff[(_readIndex + index) % _len];
}

/**************************************************************************************************
 * 功能: 是否空。
 * 返回:
 * 		true,空; false,非空。
 *************************************************************************************************/
template<typename T>
inline bool RingQueue<T>::isEmpty(void)
{
    return (_readIndex == _writeIndex);
}

/**************************************************************************************************
 * 功能: 是否滿。
 * 返回:
 * 		true,滿; false,非滿。
 *************************************************************************************************/
template<typename T>
inline bool RingQueue<T>::isFull(void)
{
    // 使用少存放一個數據的方式判斷滿。
    unsigned int wi = _writeIndex;
    unsigned int ri = _readIndex;
    return ((wi + 1) % _len == ri);
}

/**************************************************************************************************
 * 功能:清空。
 *************************************************************************************************/
template<typename T>
void RingQueue<T>::clear(void)
{
    _writeIndex = 0;
    _readIndex = 0;
}

/**************************************************************************************************
 * 功能:構造。
 *************************************************************************************************/
template<typename T>
RingQueue<T>::RingQueue()
{
    _buff = NULL;
    _len = 0;
    _writeIndex = 0;
    _readIndex = 0;
}

/**************************************************************************************************
 * 功能:析構。
 *************************************************************************************************/
template<typename T>
RingQueue<T>::~RingQueue()
{

}
發佈了31 篇原創文章 · 獲贊 8 · 訪問量 7149
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章