循環隊列FIFO原理及C實現


循環隊列是把順序隊列首尾相連,把存儲隊列元素的表從邏輯上看成一個環,成為循環隊列。

 

入隊時尾指針向前追趕頭指針;出隊時頭指針向前追趕尾指針。

定義一個循環隊列結構

#define FIFO_HEAD(name, type)                                                \
        struct name {                                                        \
                struct type *fifo;                                        \
                int front, tail, capacity;                                \
        }

front表示首元素索引

struct type *fifo表示該隊列中的元素指針,可以指向任意結構體指針

tail表示最后一個元素索引

capacity表示隊列的長度

循環隊列初始化:

分配一個連續的空間存儲隊列元素。

 

#define FIFO_INIT(head, _capacity) do {                                        \
        (head)->fifo = malloc(sizeof(*(head)->fifo) * _capacity);        \
        (head)->front = (head)->tail = -1;                                \
        (head)->capacity = _capacity;                                        \
} while (0)

循環隊列銷毀:

#define FIFO_EXIT(head) do {                                                \
        (head)->front = (head)->tail = -1;                                \
        (head)->capacity = 0;                                                \
        if ((head)->fifo)                                                \
                free((head)->fifo);                                        \
} while (0)

隊列空判斷: 

#define FIFO_EMPTY(head)    ((head)->front == -1)

①隊列初始化時,隊列是空的,會讓front為-1

②出隊列時,font++, 當font追上tail表示空了,則可以重新設置起始點,令front = tail = -1

綜合①②所以可以用-1判斷

隊列滿判斷:

#define FIFO_FULL(head)     (((head)->front == ((head)->tail + 1)%(head)->capacity))

①當front=0時,那么tail到達capacity-1表示FIFO full.

 

②否則,tail追上front后(front = tail + 1)表示FIFO full.

 

入隊列:

入隊列就是尾元素的索引++,也就是tail++,讓新元素放進隊列的尾部。

#define FIFO_PUSH(head, elm) do {                                        \
        if (FIFO_EMPTY(head))                                                \
                (head)->front = (head)->tail = 0;                        \
        else                                                                \
                (head)->tail = ((head)->tail == (head)->capacity - 1)        \
                        ? 0 : (head)->tail + 1;                        \
        (head)->fifo[(head)->tail] = elm;                                \
} while (0)

如果隊列是空的,則第一個元素入隊列,front和tail索引都指向第一個元素,front = tail = 0;

 

其他情況入隊,讓tail++

 

 

 

出隊列:

出隊列就是讓font對應的元素丟出去,font++。

#define FIFO_POP(head, pelm) do {                                        \
        *(pelm) = (head)->fifo[(head)->front];                                \
        if ((head)->front == (head)->tail)                                \
                (head)->front = (head)->tail = -1;                        \
        else                                                                \
                (head)->front = ((head)->front == (head)->capacity - 1)        \
                        ? 0 : (head)->front + 1;                \
} while (0)

當front追上tail后,表示隊列空了,重新設置起始點,需要將front = tail = -1 

 

其他情況出隊,丟出front元素,讓front++

 

隊列總元素個數:

#define FIFO_CAPACITY(head) ((head)->capacity)

隊列有效元素個數:

#define FIFO_SIZE(head)     (FIFO_EMPTY(head) ? \
        0 : ((((head)->tail + (head)->capacity - (head)->front) % (head)->capacity) + 1))

 用tail - front就表示有效元素個數,不過由於循環FIFO,可能tail<front,這個時候就需要取余運算,如下圖。

 

循環隊列遍歷:

#define FIFO_FOREACH(var, head, idx) \
  for (idx = (head)->front, var = (head)->fifo[idx]; \
    idx < (head)->front + FIFO_SIZE(head); \
    var = (head)->fifo[++idx % (head)->capacity])

獲取隊列尾元素:

#define FIFO_GET_TAIL(head, pelm) (*(pelm) = (head)->fifo[(head)->tail])

獲取隊列頭元素:

#define FIFO_GET_FRONT(head, pelm) (*(pelm) = (head)->fifo[(head)->front])

測試:

#include "fifo.h"
#include <stdio.h>

struct person{
        int age;
        int id;
        char name[20];
};
 
FIFO_HEAD(person_q, person*);
/*
        struct person_q {                                                        \
                struct person* *fifo;                                        \
                int front, tail, capacity;                                \
        }
*/
struct person_q person1_queue;
struct person_q person2_queue;

int main(void)
{
        FIFO_INIT(&person1_queue, 1);
        FIFO_INIT(&person2_queue, 5);

        if (FIFO_CAPACITY(&person1_queue) != 1) {
                printf( "FIFO_CAPACITY 1 NG.\n");
                return -1;
        }

        if (FIFO_CAPACITY(&person2_queue) != 5) {
                printf( "FIFO_CAPACITY 2 NG.\n");
                return -1;
        }
 
        if (FIFO_SIZE(&person1_queue) != 0) {
                printf( "FIFO_SIZE 1 NG.\n");
                return -1;
        }
 
        if (FIFO_SIZE(&person2_queue) != 0) {
                printf( "FIFO_SIZE 2 NG.\n");
                return -1;
        }

        if (!FIFO_EMPTY(&person1_queue)) {
                printf( "FIFO_EMPTY 1 NG.\n");
                return -1;
        }
 
        if (!FIFO_EMPTY(&person2_queue)) {
                printf( "FIFO_EMPTY 2 NG.\n");
                return -1;
        }
 
        struct person *person_a = malloc(sizeof(*person_a));
        person_a->age = 20;
        person_a->id = 1001;
        FIFO_PUSH(&person1_queue, person_a);//把person_a這個結構體指針元素丟進FIFO,
        //后面對它pop出來又能拿到它,所以不用擔心地址弄丟導致無法釋放.
 
        if (!FIFO_FULL(&person1_queue)) {
                printf( "FIFO_FULL 1 NG.\n");
                return -1;
        }
 
        person_a = malloc(sizeof(*person_a));
        person_a->age = 30;
        person_a->id = 1002;
        FIFO_PUSH(&person2_queue, person_a);

        if (FIFO_FULL(&person2_queue)) {
                printf( "FIFO_FULL 2 NG.\n");
                return -1;
        }

        if (FIFO_SIZE(&person1_queue) != 1) {
                printf( "FIFO_SIZE 3 NG.\n");
                return -1;
        }

        if (FIFO_SIZE(&person2_queue) != 1) {
                printf( "FIFO_SIZE 4 NG.\n");
                return -1;
        }

        FIFO_POP(&person1_queue, &person_a);
        if (person_a->age != 20) {
                printf( "FIFO_POP content NG.\n");
                return -1;
        }
        free(person_a);

        if (FIFO_SIZE(&person1_queue) != 0) {
                printf( "FIFO_SIZE 5 NG.\n");
                return -1;
        }
 
        person_a = malloc(sizeof(*person_a));
        person_a->age = 40;
        person_a->id = 1003;
        FIFO_PUSH(&person2_queue, person_a);

        FIFO_GET_FRONT(&person2_queue, &person_a);
        if (person_a->age != 30) {
                printf( "FIFO_GET_FRONT NG.\n");
                return -1;
        }
 
        FIFO_GET_TAIL(&person2_queue, &person_a);
        if (person_a->age != 40) {
                printf( "FIFO_GET_TAIL NG.\n");
                return -1;
        }
 
        FIFO_POP(&person2_queue, &person_a);
        if (person_a->age != 30) {
                printf( "FIFO_POP content NG.\n");
                return -1;
        }
        free(person_a);

        if (FIFO_SIZE(&person2_queue) != 1) {
                printf( "FIFO_SIZE 6 NG.\n");
                return -1;
        }

        FIFO_POP(&person2_queue, &person_a);
        if (person_a->age != 40) {
                printf( "FIFO_POP content NG.\n");
                return -1;
        }
        free(person_a);
 
        if (FIFO_SIZE(&person2_queue) != 0) {
                printf( "FIFO_SIZE 7 NG.\n");
                return -1;
        }
 
        struct person *person_arr[5];
        int i=0;

        while (!FIFO_FULL(&person2_queue))
        {
                person_arr[i] = malloc(sizeof(*person_arr[0]));
                person_arr[i]->age = i;
                person_arr[i]->id = 1000 + i;
                FIFO_PUSH(&person2_queue, person_arr[i]);
                i++;
        }

        while (!FIFO_EMPTY(&person2_queue))
        {
                FIFO_POP(&person2_queue, &person_a);
                printf( "age:%d, id:%d.\n", person_a->age, person_a->id);
                free(person_a);
        }

        FIFO_EXIT(&person1_queue);
        FIFO_EXIT(&person2_queue);
        return 0;
}
View Code


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM