循環隊列是把順序隊列首尾相連,把存儲隊列元素的表從邏輯上看成一個環,成為循環隊列。
入隊時尾指針向前追趕頭指針;出隊時頭指針向前追趕尾指針。
定義一個循環隊列結構:
#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; }