Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C中实现循环列表(环形缓冲区)?_C_Queue - Fatal编程技术网

如何在C中实现循环列表(环形缓冲区)?

如何在C中实现循环列表(环形缓冲区)?,c,queue,C,Queue,如何实现循环列表,在最旧条目已满时覆盖该条目 作为一个小背景,我想在GWT中使用一个循环列表;因此,使用第三方库不是我想要的。使用链接列表。为头部和尾部保留单独的指针。从列表的顶部弹出,推到尾部。如果你想要它是圆形的,只要确保新的尾巴总是指向头部 我可以理解为什么您可能希望使用链表实现FIFO,但为什么要将其设置为循环列表?使用数组并将变量p保留在第一个可用位置 每次添加新元素时增加p 要知道数组中p的等效索引,请执行(p%n),其中n是数组的大小。一个非常简单的实现,用C表示。实现了一个循环缓

如何实现循环列表,在最旧条目已满时覆盖该条目


作为一个小背景,我想在GWT中使用一个循环列表;因此,使用第三方库不是我想要的。

使用链接列表。为头部和尾部保留单独的指针。从列表的顶部弹出,推到尾部。如果你想要它是圆形的,只要确保新的尾巴总是指向头部


我可以理解为什么您可能希望使用链表实现FIFO,但为什么要将其设置为循环列表?

使用数组并将变量p保留在第一个可用位置

每次添加新元素时增加p


要知道数组中p的等效索引,请执行(p%n),其中n是数组的大小。

一个非常简单的实现,用C表示。实现了一个循环缓冲区样式的FIFO队列。可以通过创建一个包含队列大小、队列数据和队列索引(in和out)的结构使其更通用,这些索引将与要添加或从队列中删除的数据一起传入。这些相同的例程可以处理多个队列。还请注意,这允许任何大小的队列,但如果使用2的幂并进一步自定义代码,则可以使用加速

/* Very simple queue
 * These are FIFO queues which discard the new data when full.
 *
 * Queue is empty when in == out.
 * If in != out, then 
 *  - items are placed into in before incrementing in
 *  - items are removed from out before incrementing out
 * Queue is full when in == (out-1 + QUEUE_SIZE) % QUEUE_SIZE;
 *
 * The queue will hold QUEUE_ELEMENTS number of items before the
 * calls to QueuePut fail.
 */

/* Queue structure */
#define QUEUE_ELEMENTS 100
#define QUEUE_SIZE (QUEUE_ELEMENTS + 1)
int Queue[QUEUE_SIZE];
int QueueIn, QueueOut;

void QueueInit(void)
{
    QueueIn = QueueOut = 0;
}

int QueuePut(int new)
{
    if(QueueIn == (( QueueOut - 1 + QUEUE_SIZE) % QUEUE_SIZE))
    {
        return -1; /* Queue Full*/
    }

    Queue[QueueIn] = new;

    QueueIn = (QueueIn + 1) % QUEUE_SIZE;

    return 0; // No errors
}

int QueueGet(int *old)
{
    if(QueueIn == QueueOut)
    {
        return -1; /* Queue Empty - nothing to get*/
    }

    *old = Queue[QueueOut];

    QueueOut = (QueueOut + 1) % QUEUE_SIZE;

    return 0; // No errors
}

如果您想要固定长度的循环列表。可以使用(动态)数组。在houskeeping中使用两个变量。一个用于下一个元素的位置,一个用于计算元素的数量

放置:将元素放置在自由位置。移动位置(模长度)。除非计数等于列表的长度,否则将计数加1。
获取:仅当计数>0时。向左移动位置(模长度)。减少计数。

我将其用于我的微控制器。 为简化代码,将不填充一个字节。 Aka size-1实际上是满容量

fifo_t* createFifoToHeap(size_t size)
{
    byte_t* buffer = (byte_t*)malloc(size);

    if (buffer == NULL)
        return NULL;

    fifo_t* fifo = (fifo_t*)malloc(sizeof(fifo_t));

    if (fifo == NULL)
    {
       free(buffer);
       return NULL;
    }

    fifo->buffer = buffer;
    fifo->head = 0;
    fifo->tail = 0;
    fifo->size = size;

    return fifo;
}

#define CHECK_FIFO_NULL(fifo) MAC_FUNC(if (fifo == NULL) return 0;)

size_t fifoPushByte(fifo_t* fifo, byte_t byte)
{
    CHECK_FIFO_NULL(fifo);

    if (fifoIsFull(fifo) == true)
       return 0;

    fifo->buffer[fifo->head] = byte;

    fifo->head++;
    if (fifo->head == fifo->size)
       fifo->head = 0;

    return 1;
}

size_t fifoPushBytes(fifo_t* fifo, byte_t* bytes, size_t count)
{
    CHECK_FIFO_NULL(fifo);

    for (uint32_t i = 0; i < count; i++)
    {
        if (fifoPushByte(fifo, bytes[i]) == 0)
            return i;
    }

    return count;
}

size_t fifoPopByte(fifo_t* fifo, byte_t* byte)
{
    CHECK_FIFO_NULL(fifo);

    if (fifoIsEmpty(fifo) == true)
        return 0;

    *byte = fifo->buffer[fifo->tail];

    fifo->tail++;
    if (fifo->tail == fifo->size)
        fifo->tail = 0;

    return 1;
}

size_t fifoPopBytes(fifo_t* fifo, byte_t* bytes, size_t count)
{
    CHECK_FIFO_NULL(fifo);

    for (uint32_t i = 0; i < count; i++)
    {
        if (fifoPopByte(fifo, bytes + i) == 0)
            return i;
    }

    return count;
}

bool fifoIsFull(fifo_t* fifo)
{
    if ((fifo->head == (fifo->size - 1) && fifo->tail == 0) || (fifo->head == (fifo->tail - 1)))
        return true;
    else
        return false;
}

bool fifoIsEmpty(fifo_t* fifo)
{
    if (fifo->head == fifo->tail)
        return true;
    else
        return false;
}

size_t fifoBytesFilled(fifo_t* fifo)
{
    if (fifo->head == fifo->tail)
        return 0;
    else if ((fifo->head == (fifo->size - 1) && fifo->tail == 0) || (fifo->head == (fifo->tail - 1)))
        return fifo->size;
    else if (fifo->head < fifo->tail)
        return (fifo->head) + (fifo->size - fifo->tail);
    else
        return fifo->head - fifo->tail; 
}
fifo\u t*创建fifotoheap(大小)
{
字节t*缓冲区=(字节t*)malloc(大小);
if(buffer==NULL)
返回NULL;
fifo_t*fifo=(fifo_t*)malloc(sizeof(fifo_t));
如果(fifo==NULL)
{
自由(缓冲);
返回NULL;
}
先进先出->缓冲区=缓冲区;
fifo->head=0;
fifo->tail=0;
先进先出->大小=大小;
返回fifo;
}
#定义CHECK_FIFO_NULL(FIFO)MAC_FUNC(如果(FIFO==NULL)返回0;)
大小为fifo字节(fifo字节*fifo字节)
{
检查\u FIFO\u NULL(FIFO);
如果(fifo满(fifo)=真)
返回0;
fifo->缓冲区[fifo->磁头]=字节;
fifo->head++;
如果(fifo->head==fifo->size)
fifo->head=0;
返回1;
}
大小\u t fifoupshbytes(fifo\u t*fifo,字节\u t*bytes,大小\u t计数)
{
检查\u FIFO\u NULL(FIFO);
对于(uint32_t i=0;i缓冲区[先进先出->尾部];
fifo->tail++;
如果(fifo->tail==fifo->size)
fifo->tail=0;
返回1;
}
大小\u t五字节(fifo\u t*fifo,字节\u t*bytes,大小\u t计数)
{
检查\u FIFO\u NULL(FIFO);
对于(uint32_t i=0;ihead==(fifo->size-1)和&fifo->tail==0)| |(fifo->head==(fifo->tail-1)))
返回true;
其他的
返回false;
}
bool fifoIsEmpty(fifo\u t*fifo)
{
如果(fifo->head==fifo->tail)
返回true;
其他的
返回false;
}
填充的大小为五字节(fifo*fifo)
{
如果(fifo->head==fifo->tail)
返回0;
否则如果((fifo->head==(fifo->size-1)和&fifo->tail==0)| |(fifo->head==(fifo->tail-1)))
返回fifo->大小;
否则如果(先进先出->头部<先进先出->尾部)
返回(fifo->head)+(fifo->size-fifo->tail);
其他的
返回fifo->head-fifo->tail;
}

我认为队列不是创建缓存的最佳方式。你想成为你的高速缓存,真的很快!除非您希望缓存非常小或者内存非常有限,否则对队列进行线性扫描是不可取的

假设您不需要非常小的缓存或缓慢的缓存,那么使用带有值到链接列表中节点的哈希映射的链接列表是一个好方法。您始终可以逐出头部,并且无论何时访问某个元素,都可以将其删除并将其放在列表的头部。对于访问,您可以直接获取它或检查它是否在O(1)中的缓存中。逐出元素也是O(1),更新列表也是如此

例如,看看java中的LinkedHashMap


这里是一种使用java创建动态增加/减少循环队列的优雅方法

为了便于快速理解,我对大部分代码进行了注释。希望有帮助:)

公共类循环队列演示{
公共静态void main(字符串[]args)引发异常{
CircularQueue=新的CircularQueue(2);
/*动态增加/减少循环队列*/
System.out.println(“--动态循环队列--”);
排队。排队(1);
queue.display();
排队。排队(2);
queue.display();
排队。排队(3);
queue.display();
排队。排队(4);
queue.display();
queue.deQueue();
queue.deQueue();
排队。排队(5);
queue.deQueue();
queue.display();
}
}
类循环队列{
私有int[]队列;
公共国际阵线;
公共内部后勤;
私人int能力;
公共循环队列(int cap){
正面=-1;
后部=-1;
容量=上限;
队列=新的整数[容量];
}
公共布尔值为空(){
返回(后==-1);
}
公共布尔值isFull(){
如果((前==0和&后==容量-1)| |(前==后+1))
R
    public class CircularQueueDemo {
    public static void main(String[] args) throws Exception {

        CircularQueue queue = new CircularQueue(2);
        /* dynamically increasing/decreasing circular queue */
        System.out.println("--dynamic circular queue--");
        queue.enQueue(1);
        queue.display();
        queue.enQueue(2);
        queue.display();
        queue.enQueue(3);
        queue.display();
        queue.enQueue(4);
        queue.display();
        queue.deQueue();
        queue.deQueue();
        queue.enQueue(5);
        queue.deQueue();    
        queue.display();

    }
}

class CircularQueue {
    private int[] queue;
    public int front;
    public int rear;
    private int capacity;

    public CircularQueue(int cap) {
        front = -1;
        rear = -1;
        capacity = cap;
        queue = new int[capacity];
    }

    public boolean isEmpty() {
        return (rear == -1);
    }

    public boolean isFull() {
        if ((front == 0 && rear == capacity - 1) || (front == rear + 1))
            return true;
        else
            return false;
    }

    public void enQueue(int data) { 
        if (isFull()) {            //if queue is full then expand it dynamically   
            reSize();                    
            enQueue(data);
        } else {                                 //else add the data to the queue
            if (rear == -1)                      //if queue is empty
                rear = front = 0;
            else if (rear == capacity)          //else if rear reached the end of array then place rear to start (circular array)
                rear = 0;
            else
                rear++;                         //else just incement the rear 
            queue[rear] = data;                 //add the data to rear position
        }
    }

    public void reSize() {
        int new_capacity = 2 * capacity;                  //create new array of double the prev size
        int[] new_array = new int[new_capacity];          

        int prev_size = getSize();                        //get prev no of elements present
        int i = 0;                                        //place index to starting of new array

        while (prev_size >= 0) {                          //while elements are present in prev queue
            if (i == 0) {                                 //if i==0 place the first element to the array
                new_array[i] = queue[front++];
            } else if (front == capacity) {               //else if front reached the end of array then place rear to start (circular array) 
                front = 0;
                new_array[i] = queue[front++];
            } else                                        //else just increment the array
                new_array[i] = queue[front++];
            prev_size--;                                  //keep decreasing no of element as you add the elements to the new array
            i++;                                          //increase the index of new array
        }
        front = 0;                                        //assign front to 0
        rear = i-1;                                       //assign rear to the last index of added element
        capacity=new_capacity;                            //assign the new capacity
        queue=new_array;                                  //now queue will point to new array (bigger circular array)
    }

    public int getSize() {
        return (capacity - front + rear) % capacity;                  //formula to get no of elements present in circular queue
    }

    public int deQueue() throws Exception {
        if (isEmpty())                                       //if queue is empty
            throw new Exception("Queue is empty");
        else {
            int item = queue[front];                        //get item from front
            if (front == rear)                              //if only one element
                front = rear = -1;
            else if (front == capacity)                     //front reached the end of array then place rear to start (circular array)
                front = 0;
            else
                front++;                                    //increment front by one
            decreaseSize();                                 //check if size of the queue can be reduced to half
            return item;                                    //return item from front
        }

    }

    public void decreaseSize(){                           //function to decrement size of circular array dynamically
        int prev_size = getSize();
        if(prev_size<capacity/2){                         //if size is less than half of the capacity
            int[] new_array=new int[capacity/2];          //create new array of half of its size
            int index=front;                              //get front index
            int i=0;                                      //place an index to starting of new array (half the size)
            while(prev_size>=0){                          //while no of elements are present in the queue
                if(i==0)                                  //if index==0 place the first element
                    new_array[i]=queue[front++];
                else if(front==capacity){                 //front reached the end of array then place rear to start (circular array)      
                    front=0;
                    new_array[i]=queue[front++];
                }
                else
                    new_array[i]=queue[front++];         //else just add the element present in index of front
                prev_size--;                             //decrease the no of elements after putting to new array 
                i++;                                     //increase the index of i
            }
            front=0;                                     //assign front to 0
            rear=i-1;                                    //assign rear to index of last element present in new array(queue)
            capacity=capacity/2;                         //assign new capacity (half the size of prev)
            queue=new_array;                             //now queue will point to new array (or new queue)
        }
    }

    public void display() {                           //function to display queue
        int size = getSize();
        int index = front;

        while (size >= 0) {
            if (isEmpty())
                System.out.println("Empty queue");
            else if (index == capacity)
                index = 0;
            System.out.print(queue[index++] + "=>");
            size--;
        }
        System.out.println("  Capacity: "+capacity);

    }

}
#include <iostream>
#include <string>

using namespace std;

class E: public std::exception {

    const char *_msg;
    E(){}; //no default constructor

public:

    explicit E(const char *msg) throw(): _msg(msg) {};
    const char * what() const throw() {return(_msg);};

};

const int min_size = 2;
const int max_size = 1000;

template<typename T>
class Fifo{

    int _head;
    int _tail;
    int _size;

    T* _storage;

public:

    explicit Fifo(int size = min_size);
    ~Fifo(){ delete [] _storage;};

    bool is_full() const{
        return(((_head+1)%_size) == _tail);
    };
    bool is_empty() const{
        return(_head == _tail);
    };

    void add_item(const T& item);
    const T& get_item();

};

template<typename T>
Fifo<T>::Fifo(int size): _size(size){
    
    if (size < min_size) throw E("Cannot create Fifo less than 2\n");

    _head = _tail = 0;

    try{

        _storage = new T[_size];
    }
    catch (std::bad_alloc &ba)
    {
        char e_string[500];
        sprintf(e_string, "Cannot allocate memory (%s)\n", ba.what());
        throw E(e_string);
    }

    printf("Constructing Fifo of size %d\n", _size);

}

template <typename T>
void Fifo<T>::add_item(const T& item)
{
    if (this->is_full()) throw E("Fifo is full.\n");

    _storage[_head] = item;

    _head = (_head + 1)%_size;
}

template <typename T>
const T& Fifo<T>::get_item()
{
    if (this->is_empty()) throw E("Fifo is empty.\n");

    int temp = _tail; //save the current tail

    _tail = (_tail+1)%_size; //update tail

    return(_storage[temp]);
}

int main()
{
    Fifo<int> my_fifo(3);

    for (int i = 1, item; i < 50; i++)
    {
        my_fifo.add_item(i);
        my_fifo.add_item(i*10);
        item = my_fifo.get_item();
        printf("Item: %d\n", item);
        item = my_fifo.get_item();
        printf("Item: %d\n", item);
    }


    return 0;
}