queue.h的链表使用

844 查看

在FreeBSD中有queue.h这样一个头文件(Linux也有),它定义了一系列的宏操作,实现了双向链表,双端队列和循环链表。

下面给出一些链表常用操作的例子:

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

struct element{
    int num;
    /*LIST_ENTRY 创建了一个匿名结构体,这个结构体有两个成员,
      分别为struct element* le_next;
           struct element** le_prev;
      即,elements的类型就是这个匿名的结构体,
      使得element成为双向链表中的节点
     */
    LIST_ENTRY(element) elements;
};
int main(void){
    /*LIST_HEAD 会自动构建一个名为listh的结构体,
      里面含有一个element指针 *lh_first
      这里的name一般没有什么用处,但是尽量注意有多个链表时,name不要相同造成冲突。
     */
    LIST_HEAD(listh,element) head; 
    struct element *n1,*np;
    //链表使用前,需要初始化
    LIST_INIT(&head);
    n1 = (struct element*)malloc(sizeof(struct element));
    n1->num = 1;
    //各种插入方式
    //插入到链表前端
    /*
       对于LIST_INSERT_HEAD为何需要用指针域作为参数,
       因为指针域的名字是用户自己定义的,函数内部并不知道,
       所以需要作为参数传入
    */
    LIST_INSERT_HEAD(&head,n1,elements);
    n1 = (struct element*)malloc(sizeof(struct element));
    n1->num = 2;
    //插入到某个节点之后,这里是插入到第一个节点之后
    LIST_INSERT_AFTER(LIST_FIRST(&head),n1,elements);    
    
    n1 = (struct element*)malloc(sizeof(struct element));
    n1->num=3;
    //插入到某个节点之前
    LIST_INSERT_BEFORE(LIST_FIRST(&head),n1,elements);
    
    //遍历链表
    //方法一
    for(np=LIST_FIRST(&head);np!=NULL;np=LIST_NEXT(np,elements)){
        printf("%d ",np->num);
    }
    //方法二(推荐)
    LIST_FOREACH(np,&head,elements){
        printf("%d ",np->num);
    }
    //方法三(最原始)
    for(np=(head).lh_first;np!=NULL;np=np->elements.le_next){
        printf("%d ",np->num);
    }    
    
    //删除,释放链表
    while(LIST_FIRST(&head)){
        struct element* tmp = LIST_FIRST(&head);
        LIST_REMOVE(tmp,elements);
        free(tmp);
    }
    return 0;
}