2008-10-18 14 views

Respuesta

40

Una implementación muy simple, expresada en C. Implementa una cola FIFO de estilo de búfer circular. Podría hacerse más genérico al crear una estructura que contenga el tamaño de la cola, los datos de la cola y los índices de la cola (entrada y salida), que se pasarán con los datos para agregar o eliminar de la cola. Estas mismas rutinas podrían manejar varias colas. También tenga en cuenta que esto permite colas de cualquier tamaño, aunque se pueden usar aceleraciones si usa potencias de 2 y personaliza el código más.

/* 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 
} 
+1

corrígeme si me equivoco, pero no esta permiten guardar sólo 99 entradas? La expresión (en == (out-1 + SIZE)% SIZE) dice si in es uno antes de out. Pero aún no se ha escrito, por lo que el lugar 100 no se escribe nunca. –

+0

@Jonathon - Eso es correcto, y si bien es lo suficientemente obvio para los expertos, esto está dirigido a principiantes, por lo que he modificado el código para hacerlo más explícito. Gracias por la nota! –

+0

@AdamDavis. Este código no es correcto Si miras el buffer, no solo deja un "agujero", el agujero "se arrastra" hacia atrás a través del buffer. Sirvió de inspiración para el código que publiqué aquí, así que quería agradecerle por publicar este código con ese fin. http://stackoverflow.com/questions/827691/how-do-you-implement-a-circular-buffer-in-c/13888143#13888143 – RocketRoy

1

Utilice una lista vinculada. Mantenga punteros separados para la cabeza y la cola. Pop del encabezado de la lista, empuja hacia la cola. Si quieres que sea circular, solo asegúrate de que la nueva cola siempre apunte a la cabeza.

Entiendo por qué es posible que desee implementar un FIFO utilizando una lista vinculada, pero ¿por qué hacer que sea una lista circular?

1

Utilice una matriz y mantenga una variable P con la primera posición disponible.

Aumente P cada vez que agregue un nuevo elemento.

Para saber el índice equivalente de P en su matriz haga (P% n) donde n es el tamaño de su matriz.

2

Si desea una lista circular de longitud fija. Puede usar una matriz (dinámica). Use dos variables para mantenimiento del hogar. Uno para la posición del siguiente elemento, uno para contar la cantidad de elementos.

Poner: poner el elemento en el lugar libre. mover la posición (longitud del módulo). Agregue 1 a la cuenta a menos que count sea igual a la longitud de la lista. Obtener: solo si cuenta> 0. mover la posición a la izquierda (longitud del módulo). Disminuir el conteo.

1

Estoy usando esto para mi microcontrolador. Para la simplicidad del código, un byte no se completará. Tamaño Aka - 1 es la capacidad total en realidad.

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; 
} 
+0

Hola, olvidaste agregar struct fifo_t en tu código ... :) – MrHetii

+0

Creo que puedes derivarlo de la función createFifoToHeap(). Donde 'fifo-> buffer = buffer; fifo-> cabeza = 0; fifo-> cola = 0; fifo-> tamaño = tamaño; ' el búfer es byte_t, la cabeza y la cola uint32_t y el tamaño es size_t – arapEST

0

No creo que la cola sea la mejor manera de hacer un caché. ¡Quieres ser tu caché para ser realmente rápido! Y hacer un escaneo lineal de su cola no es el camino a seguir a menos que desee que su caché sea realmente pequeña o su memoria sea realmente limitada.

Suponiendo que no quiere un caché muy pequeño o un caché lento, usar una lista vinculada con un mapa hash de valor al nodo en la lista vinculada es una buena forma de hacerlo. Siempre puede desalojar el encabezado, y cada vez que se accede a un elemento, puede eliminarlo y ponerlo en el encabezado de la lista. Para acceder puede obtenerlo directamente o verificar si está en la memoria caché en O (1). Expulsar un elemento también es O (1) y también está actualizando la lista.

Por ejemplo, mira LinkedHashMap en java.

http://docs.oracle.com/javase/6/docs/api/java/util/LinkedHashMap.html

+0

Si está utilizando esto como un verdadero FIFO y no necesita acceso aleatorio, creo que un búfer circular será más rápido que una lista vinculada en casi todos los casos.No hay necesidad de asignar/desasignar memoria, y desalojar un elemento en el frente es tan simple como incrementar/decrementar un índice. –

+0

@BenHershey tienes razón. No creo que esa fue la pregunta a la que respondí. Al mirar mi respuesta, parece que estaba respondiendo detalles de la implementación de un caché, no una verdadera cola FIFO. Tal vez la pregunta cambió, o lo leí mal cuando respondí. –

+0

Ok, tiene sentido. Solo quería aclarar a las personas que leerán en el futuro y que podrían confundirse. ;) –

0

Aquí está una manera elegante para crear dinámicamente aumentar/disminuir la cola circular usando java.

He comentado la mayor parte del código para & comprensión rápida. Espero que ayude :)

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

    } 

} 

Salida:

--dynamic queue-- circular

1 => Capacidad: 2

1 => 2 => Capacidad: 2

1 => 2 => 3 => Capacidad: 4

1 => 2 => 3 => 4 => Capacidad: 4

4 => 5 => Capacidad: 2

Cuestiones relacionadas