Circular Queue

  最近在项目中,用于缓存数据的时候使用到linux下的循环队列(circular queue),要缓存的数据单元是一个结构体,这种数据结构使用起来很方便,linux下有许多宏可以使用。下面就详细介绍下这种队列的使用,本文参考了http://cpp.ezbty.org/import_doc/linux_manpage/queue.3.html的内容,在此表示感谢。

1.Introduce  

A circular queue is headed by a structure defined by the CIRCLEQ_HEAD macro. This structure contains a pair of pointers, one to the first element in the circular queue and the other to the last element in the circular queue. The elements are doubly linked so that an arbitrary element can be removed without traversing the queue. New elements can be added to the queue after an existing element, before an existing element, at the head of the queue, or at the end of the queue. A CIRCLEQ_HEAD structure is declared as follows:CIRCLEQ_HEAD(HEADNAME, TYPE) head;

#define	CIRCLEQ_HEAD(name, type)					\
struct name {								\
	struct type *cqh_first;		/* first element */		\
	struct type *cqh_last;		/* last element */		\
}

where HEADNAME is the name of the structure to be defined, and TYPE is the type of the elements to be linked into the circular queue. A pointer to the head of the circular queue can later be declared as:

struct HEADNAME *headp;

(The names head and headp are user selectable.)

2. Macro

使用下列宏需要添加#include <sys/queue.h>头文件。
The macro CIRCLEQ_ENTRY declares a structure that connects the elements in the circular queue.
The macro CIRCLEQ_INIT initializes the circular queue referenced by head.
The macro CIRCLEQ_INSERT_HEAD inserts the new element elm at the head of the circular queue.
The macro CIRCLEQ_INSERT_TAIL inserts the new element elm at the end of the circular queue.
The macro CIRCLEQ_INSERT_AFTER inserts the new element elm after the element listelm.
The macro CIRCLEQ_INSERT_BEFORE inserts the new element elm before the element listelm.
The macro CIRCLEQ_REMOVE removes the element elm from the circular queue.

3. Example:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/queue.h>

struct entry
{
    int oper;
    /*
    ..............
    可以加其他内容
    */
    CIRCLEQ_ENTRY(entry) entries;
};

/* 结构体变量申明 */
static CIRCLEQ_HEAD(circleq, entry) head;

int main(int argc, char **argv)
{
    struct entry *np, *n1, *n2;
    
    CIRCLEQ_INIT(&head);  

    n1 = (struct entry *)malloc(sizeof(struct entry));
    n1->oper = 0x01;
    CIRCLEQ_INSERT_HEAD(&head, n1, entries);

    /*
    * 注意:在进行插入元素时,不能再采用n1分配的内存空间,需要重新分配内存
    * 由于CIRCLEQ_INSERT_HEAD 插入队列是利用指针指向n1分配的内存,
    * 如果仍然使用n1,会导致一直循环,大家可以试验下,看结果就知道(表达不是很清楚哈)
    */
    n1 = (struct entry *)malloc(sizeof(struct entry));
    n1->oper = 0x02;
    CIRCLEQ_INSERT_HEAD(&head, n1, entries);
    printf("CIRCLEQ_INSERT_HEAD(0x02):");
    for (np = head.cqh_first; np != (struct entry *) &head; np = np->entries.cqe_next)
    {
        printf("%d ", np->oper);
    }
    printf("\n");

    /*
    * 大家可以看到下面三种插入队列的不同位置情况
    */
    n2 = (struct entry *)malloc(sizeof(struct entry));
    n2->oper = 0x03;
    CIRCLEQ_INSERT_TAIL(&head, n2, entries);
    printf("CIRCLEQ_INSERT_TAIL(0x03):");
    for (np = head.cqh_first; np != (struct entry *) &head; np = np->entries.cqe_next)
    {
        printf("%d ", np->oper);
    }
    printf("\n");

    n2 = (struct entry *)malloc(sizeof(struct entry));
    n2->oper = 0x04;
    CIRCLEQ_INSERT_AFTER(&head, n1, n2, entries);
    printf("CIRCLEQ_INSERT_AFTER(0x02 0x04):");
    for (np = head.cqh_first; np != (struct entry *) &head; np = np->entries.cqe_next)
    {
        printf("%d ", np->oper);
    }
    printf("\n");

    n2 = (struct entry *)malloc(sizeof(struct entry));
    n2->oper = 0x05;
    CIRCLEQ_INSERT_BEFORE(&head, n1, n2, entries);
    printf("CIRCLEQ_INSERT_BEFORE(0x05 0x02):");
    for (np = head.cqh_first; np != (struct entry *) &head; np = np->entries.cqe_next)
    {
        printf("%d ", np->oper);
    }
    printf("\n");

    /* 上面是正向遍历队列,下面这个是反向遍历队列 */
    printf("Reverse traversal:");
    //for (np = head.cqh_last; np != (struct entry *) &head; np = np->entries.cqe_prev)
    CIRCLEQ_FOREACH_REVERSE(np, &head, entries) // 功能同上for循环
    {
        printf("%d ", np->oper);
    }
    printf("\n");

    /* 删除n1(0x02)这个节点 */
    CIRCLEQ_REMOVE(&head, n1, entries);
    printf("CIRCLEQ_REMOVE(0x02):");
    //for (np = head.cqh_first; np != (struct entry *) &head; np = np->entries.cqe_next)
    CIRCLEQ_FOREACH(np, &head, entries) // 功能同上for循环
    {
        printf("%d ", np->oper);
    }
    printf("\n");

    /* 删除整个队列 */
    while (head.cqh_first != (void *)&head)
        CIRCLEQ_REMOVE(&head, head.cqh_first, entries);
    
    printf("CIRCLEQ_REMOVE ALL:");
    for (np = head.cqh_first; np != (struct entry *) &head; np = np->entries.cqe_next)
    {
        printf("%d ", np->oper);
    }
    printf("\n");
    
    return 0;
}
result:
CIRCLEQ_INSERT_HEAD(0x02):2 1 
CIRCLEQ_INSERT_TAIL(0x03):2 1 3 
CIRCLEQ_INSERT_AFTER(0x02 0x04):2 4 1 3 
CIRCLEQ_INSERT_BEFORE(0x05 0x02):5 2 4 1 3 
Reverse traversal:3 1 4 2 5 
CIRCLEQ_REMOVE(0x02):5 4 1 3 
CIRCLEQ_REMOVE ALL:

你可能感兴趣的:(数据结构,linux,struct,insert,n2,traversal)