2008-10-18 3 views
27

Как реализовать круговой список, который перезаписывает самую старую запись, когда она заполнена?Как реализовать круговой список (кольцевой буфер) в C?

Для небольшого фона, я хочу использовать круговой список в GWT; поэтому использование сторонней библиотеки не что я хочу.

ответ

40

Очень простая реализация, выраженная в C. Реализует очередь FIFO в стиле буферного буфера. Можно сделать более общим, создав структуру, содержащую размер очереди, данные очереди и индексы очереди (внутри и вне), которые будут переданы с данными для добавления или удаления из очереди. Эти же процедуры могут обрабатывать несколько очередей. Также обратите внимание, что это позволяет создавать очереди любого размера, хотя ускорения могут быть использованы, если вы используете полномочия 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 
} 
+1

Поправьте меня, если я ошибаюсь, но это не позволяет хранить только 99 записей? Выражение (in == (out-1 + SIZE)% SIZE) говорит, что если он один раньше. Но он еще не написан, поэтому 100-е место никогда не записывается. – 2010-09-27 04:20:45

+0

@ Jonathon - Это правильно, и, хотя это достаточно очевидно для экспертов, это нацелено на новичков, поэтому я изменил код, чтобы сделать его более явным. Спасибо за примечание! – 2010-10-09 16:07:52

+0

@AdamDavis. Этот код неверен. Если вы наблюдаете за буфером, он не только оставляет «отверстие», но и «просканирует» назад через буфер. Это послужило источником вдохновения для кода, который я опубликовал здесь, поэтому я хотел поблагодарить вас за публикацию этого кода с этой целью. http://stackoverflow.com/questions/827691/how-do-you-implement-a-circular-buffer-in-c/13888143#13888143 – RocketRoy 2012-12-29 01:36:36

1

Используйте связанный список. Поддерживайте отдельные указатели для головы и хвоста. Поп из головы списка, нажмите на хвост. Если вы хотите, чтобы он был круговым, просто убедитесь, что новый хвост всегда указывает на голову.

Я могу понять, почему вы, возможно, захотите реализовать FIFO, используя связанный список, но зачем делать его круговым списком?

1

Используйте массив и сохраните переменную P с первым доступным положением.

Увеличение P каждый раз, когда вы добавляете новый элемент.

Чтобы узнать эквивалентный индекс P в вашем массиве do (P% n), где n - размер вашего массива.

2

Если вы хотите круглый список с фиксированной длиной. Вы можете использовать (динамический) массив. Используйте две переменные для ведения домашнего хозяйства. Один для позиции следующего элемента, для подсчета количества элементов.

Путь: положить элемент на бесплатное место. переместите позицию (по модулю). Добавьте 1 к счету, если счет не равен длине списка. Получить: только если count> 0. переместите позицию влево (по модулю). Уменьшите счет.

1

Я использую это для своего микроконтроллера. Для простоты кода один байт будет незаполненным. Размер aka - 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; 
} 
0

Я не думаю, что очередь - лучший способ сделать кеш. Вы хотите, чтобы ваш кеш был очень быстрым! И выполнение линейного сканирования вашей очереди - это не выход, если вы не хотите, чтобы ваш кеш был очень маленьким, или ваша память действительно ограничена.

Предполагая, что вам не нужен очень маленький кеш или медленный кеш, использование связанного списка с хэш-картой значения для узла в связанном списке - хороший способ пойти. Вы всегда можете выселить голову, и всякий раз, когда к элементу обращаются, вы можете удалить его и поместить в начало списка. Для доступа вы можете напрямую получить его или проверить, находится ли он в кеше в O (1). Выделение элемента также O (1), и поэтому обновляется список.

Например, посмотрите ссылку LinkedHashMap в java.

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

0

Вот это элегантный способ создания динамически увеличения/уменьшения круговой очереди с помощью Java.

Я прокомментировал большую часть кода для удобства & быстрое понимание. Надеюсь, что это помогает :)

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

    } 

} 

Выход:

--dynamic круговой queue--

1 => Вместимость: 2

1 => 2 => Вместимость: 2

1 => 2 => 3 => Вместимость: 4

1 => 2 => 3 => 4 => Вместимость: 4

4 => 5 => Вместимость: 2

Смежные вопросы