it-swarm.com.de

Wie implementiere ich eine zirkuläre Liste (Ringpuffer) in C?

Wie implementiere ich eine zirkuläre Liste, die den ältesten Eintrag überschreibt, wenn er voll ist? 

Für einen kleinen Hintergrund möchte ich eine zirkuläre Liste innerhalb von GWT verwenden. also mit einer 3rd Party lib ist nicht was ich will.

29
Miguel Ping

Eine sehr einfache Implementierung, ausgedrückt in C. Implementiert eine Warteschlange mit einem kreisförmigen Puffer FIFO. Könnte allgemeiner gestaltet werden, indem eine Struktur erstellt wird, die die Warteschlangengröße, Warteschlangendaten und Warteschlangenindizes (In und Out) enthält, die zusammen mit den Daten übergeben werden, die hinzugefügt oder aus der Warteschlange entfernt werden sollen. Dieselben Routinen könnten dann mehrere Warteschlangen verarbeiten. Beachten Sie auch, dass dies Warteschlangen von beliebiger Größe zulässt. Wenn Sie Potenzen von 2 verwenden und den Code weiter anpassen, können jedoch Beschleunigungen verwendet werden.

/* 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
}
42
Adam Davis

Wenn Sie eine Liste mit fester Länge wünschen. Sie können ein (dynamisches) Array verwenden. Verwenden Sie zwei Variablen für das Houskeeping. Eine für die Position des nächsten Elements, eine für die Anzahl der Elemente.

Put: Element auf freien Platz legen. Position verschieben (Modulo-Länge). Fügen Sie der Anzahl 1 hinzu, sofern die Anzahl nicht der Länge der Liste entspricht. Get: nur, wenn Anzahl> 0 ist. verschiebe die Position nach links (modulo length). Dekrementiere die Zählung.

2
Toon Krijthe

Verwenden Sie eine verknüpfte Liste. Behalten Sie separate Zeiger für Kopf und Schwanz bei. Pop vom Kopf der Liste, auf den Schwanz drücken. Wenn Sie es kreisförmig haben möchten, stellen Sie sicher, dass der neue Schwanz immer auf den Kopf zeigt.

Ich kann verstehen, warum Sie eine FIFO mithilfe einer verknüpften Liste implementieren möchten.

1
tvanfosson

Verwenden Sie ein Array und behalten Sie eine Variable P mit der ersten verfügbaren Position bei.

Erhöhen Sie P jedes Mal, wenn Sie ein neues Element hinzufügen.

Um den entsprechenden Index von P in Ihrem Array zu kennen, tun Sie (P% n), wobei n die Größe Ihres Arrays ist.

1
Lucia

Ich verwende dies für meinen Mikrocontroller . Zur Vereinfachung von Code wird ein Byte nicht gefüllt.

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; 
}
1
arapEST

Hier ist eine elegante Möglichkeit, eine dynamisch ansteigende/abnehmende Warteschlange mitJavazu erstellen. 

Ich habe den größten Teil des Codes zum leichteren und schnellen Verständnis kommentiert. Ich hoffe es hilft :)

    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);

    }

}

Ausgabe:

--dynamische kreisförmige Warteschlange--

1 => Kapazität: 2

1 => 2 => Kapazität: 2

1 => 2 => 3 => Kapazität: 4

1 => 2 => 3 => 4 => Kapazität: 4

4 => 5 => Kapazität: 2

0
Prateek Joshi

Ich glaube nicht, dass die Warteschlange der beste Weg ist, einen Cache zu erstellen. Sie möchten Ihr Cache sein, um wirklich schnell zu sein! Wenn Sie einen linearen Scan Ihrer Warteschlange durchführen, ist dies nicht der richtige Weg, es sei denn, Sie möchten, dass der Cache wirklich klein ist oder der Speicher wirklich begrenzt ist.

Angenommen, Sie möchten keinen sehr kleinen Cache oder einen langsamen Cache, ist die Verwendung einer verknüpften Liste mit einer Hash-Map des Werts zum Knoten in der verknüpften Liste ein guter Weg. Sie können den Kopf jederzeit entfernen, und wenn auf ein Element zugegriffen wird, können Sie es entfernen und an den Anfang der Liste setzen. Für den Zugriff können Sie es direkt abrufen oder überprüfen, ob es sich in O (1) im Cache befindet. Das Entfernen eines Elements ist auch O(1) und das Aktualisieren der Liste. 

Sehen Sie sich zum Beispiel LinkedHashMap in Java an.

http://docs.Oracle.com/javase/6/docs/api/Java/util/LinkedHashMap.html

0
Neo M Hacker