sys/queue.h

概述

        sys/queue.h是LINUX/UNIX系統下面的一個標準頭文件,用一系列的數據結構定義了一隊列。包括singly-lined list, list, simple queue(Singly-linked Tail queue), tail queue, circle queue五種。

        引用此頭文件對這五種數據結構的描述:

A singly-linked list is headed by a single forward pointer. The elements are singly linked for minimum space and pointer manipulation overhead at the expense of O(n) removal for arbitrary elements. New elements can be added to the list after an existing element or at the head of the list.  Elements being removed from the head of the list should use the explicit macro for this purpose for optimum efficiency. A singly-linked list may only be traversed in the forward direction.  Singly-linked lists are ideal for applications with large datasets and few or no removals or for implementing a LIFO queue. 

A list is headed by a single forward pointer (or an array of forward pointers for a hash table header). The elements are doubly linked 
so that an arbitrary element can be removed without a need to traverse the list. New elements can be added to the list before 
or after an existing element or at the head of the list. A list may only be traversed in the forward direction. 

A simple queue is headed by a pair of pointers, one the head of the list and the other to the tail of the list. The elements are singly linked to save space, so elements can only be removed from the head of the list. New elements can be added to the list after an existing element, at the head of the list, or at the end of the list. A simple queue may only be traversed in the forward direction. 

A tail queue is headed by a pair of pointers, one to the head of the list and the other to the tail of the list. The elements are doubly linked so that an arbitrary element can be removed without a need to traverse the list. New elements can be added to the list before or after an existing element, at the head of the list, or at the end of the list. A tail queue may be traversed in either direction. 

A circle queue is headed by a pair of pointers, one to the head of the list and the other to the tail of the list. The elements are doubly linked so that an arbitrary element can be removed without a need to traverse the list. New elements can be added to the list before or after an existing element, at the head of the list, or at the end of the list. A circle queue may be traversed in either direction, but has a more complex end of list detection.

        簡單來說,即是單鏈表,雙鏈表,單鏈隊列,雙向隊列(尾隊列)和雙向循環隊列。

        雖然這是LINUX/UNIX裏面的文件,但此文件本身沒有用到LINUX/UNIX的系統特性,因而可以跨平臺使用。queue.h下載

        下面對各數據結構簡單描述之。

單鏈表(singly-linked list)

        singly-linked list就是一單鏈表。

        singly-linked list相關的定義:

宏定義 說明
SLIST_HEAD(name, type) 定義表頭結點。 
name: 表頭結點名。 
type: 結點類型。
SLIST_HEAD_INITIALIZER(head) 初始化頭結點。 
head: 表頭結點。
SLIST_ENTRY(type) 定義鏈表的鏈域。 
type: 結點類型。

        singly-linked list函數:

宏定義 說明
SLIST_INIT(head) 初始化頭結點。 
head: 表頭結點。
SLIST_INSERT_AFTER(slistelm, elm, field) 將結點elm插入到結點slistelm後面。 
slistelm:鏈表中某結點。 
elm:要插入的結點。 
field:鏈表中鏈域的名稱。
SLIST_INSERT_HEAD(head, elm, field) 將結點elm插入到頭結點head後面。 
head: 表頭結點。 
elm:要插入的結點。 
field:鏈表中鏈域的名稱。
SLIST_REMOVE_HEAD(head, field) 移除將表頭結點下面一個結點。 
head: 表頭結點。 
field:鏈表中鏈域的名稱。
SLIST_REMOVE(head, elm, type, field) 移除將elm結點,elm結點一定要是鏈表中一結點。 
head: 表頭結點。 
elm:某結點。 
type: 結點類型。 
field:鏈表中鏈域的名稱。
SLIST_FOREACH(var, head, field) 遍歷鏈表,相當於for循環。 
var: 結點類型的變量名稱。 
head: 表頭結點。 
field:鏈表中鏈域的名稱。

        singly-linked list 訪問方法:

宏定義 說明
SLIST_EMPTY(head) 判斷鏈表是否爲空。 
head: 表頭結點。
SLIST_FIRST(head) 訪問鏈表裏的第一個元素。 
head: 表頭結點。
SLIST_NEXT(elm, field) 訪問elm結點後一個元素。 
elm:某結點。 
field:鏈表中鏈域的名稱。

        簡單例子:

struct SListItem
{
    int data;
    SLIST_ENTRY(SListItem) entry;
};
/*
 struct SListItem
 {
    int data;
    struct {
        struct SListItem* sle_next;
    } entry;
 }
 */
void slist_demo()
{
    struct SListItem* item = NULL;
    SLIST_HEAD(SListHead, SListItem) shead;
    /*
     struct SListHead {
         struct SListItem* slh_first;
     } shead;
     */
    SLIST_INIT(&shead);

    item = (struct SListItem*)malloc(sizeof(struct SListItem));
    item->data = 1;

    SLIST_INSERT_HEAD(&shead, item, entry);
    /*
     item->entry.sle_next = (&shead)->slh_first;
     (&shead)->slh_first = item;
     */

    item = (struct SListItem*)malloc(sizeof(struct SListItem));
    item->data = 2;

    SLIST_INSERT_HEAD(&shead, item, entry);
    /*
     item->entry.sle_next = (&shead)->slh_first;
     (&shead)->slh_first = item;
     */

    SLIST_FOREACH(item, &shead, entry){
        printf("%d ", item->data);
    }
    /*
     for(item = (&shead)->slh_first; item; item = item->entry.sle_next){
        ...
     }
     */
    printf("\n");

    while(!SLIST_EMPTY(&shead)){
        item = SLIST_FIRST(&shead);
        printf("remove %d\n", item->data);
        SLIST_REMOVE(&shead, item, SListItem, entry);
        free(item);
    }
    /*
     while(!((&shead)->slh_first == NULL)){
         item = (&shead)->slh_first;
         ...
         (&shead)->slh_first = (&shead)->slh_first->entry.sle_next;
         ...
     }
     */
}
/*結果
2 1
remove 2
remove 1
*/

雙向鏈表(list)

        list就是雙向鏈表,不過鏈域有點古怪,指向前一個結點是指針的指針。

        list 相關定義

宏定義 說明
LIST_HEAD(name, type) 定義表頭結點。 
name: 表頭結點名。 
type: 結點類型。
LIST_HEAD_INITIALIZER(head) 初始化頭結點。 
head: 表頭結點。
LIST_ENTRY(type) 定義鏈表的鏈域。 
type: 結點類型。

        list函數

宏定義 說明
LIST_INIT(head) 初始化頭結點。 
head: 表頭結點。
LIST_INSERT_AFTER(listelm, elm, field) 將結點elm插入到結點listelm後面。 
listelm:鏈表中某結點。 
elm:要插入的結點。 
field:鏈表中鏈域的名稱。
LIST_INSERT_BEFORE(listelm, elm, field) 將結點elm插入到結點listelm前面。 
listelm:鏈表中某結點。 
elm:要插入的結點。 
field:鏈表中鏈域的名稱。
LIST_INSERT_HEAD(head, elm, field) 將結點elm插入到頭結點head後面。 
head: 表頭結點。 
elm:要插入的結點。 
field:鏈表中鏈域的名稱。
LIST_REMOVE(elm, field) 移除將elm結點。 
elm:某結點。 
field:鏈表中鏈域的名稱。
LIST_FOREACH(var, head, field) 遍歷鏈表,相當於for循環。 
var: 結點類型的變量名稱。 
head: 表頭結點。 
field:鏈表中鏈域的名稱。

        list訪問方法

宏定義 說明
LIST_EMPTY(head) 判斷鏈表是否爲空。 
head: 表頭結點。
LIST_FIRST(head) 訪問鏈表裏的第一個元素。 
head: 表頭結點。
LIST_NEXT(elm, field) 訪問elm結點後一個元素。 
elm:某結點。 
field:鏈表中鏈域的名稱。

        注意,因爲list是雙向鏈表,但在訪問方法裏沒有寫出訪問前一個元素的宏。因而可以這樣寫一個,參數含義和LIST_NEXT一樣:

#define LIST_PRE(elm, field) \
(((elm)->field.le_pre) != &elm ? *((elm)->field.le_pre) : NULL)

        簡單例子:

struct ListItem
{
    int data;
    LIST_ENTRY(ListItem) entry;
};
/*
struct ListItem
{
    int data;
    struct{
        struct ListItem* le_next;
        struct ListItem** le_prev;
    } entry;
};
*/
void list_demo()
{
    struct ListItem* item = NULL;
    
    LIST_HEAD(ListHead, ListItem) lhead;
    /*
    struct ListHead {
        struct ListItem* lh_first;
    } lhead;
    */
    LIST_INIT(&lhead);
    /*
    do{
         (&lhead)->lh_first = NULL;
    }while(0);
    */

    item = (struct ListItem*)malloc(sizeof(struct ListItem));
    item->data = 1;

    LIST_INSERT_HEAD(&lhead, item, entry);
    
    item = (struct ListItem*)malloc(sizeof(struct ListItem));
    item->data = 2;
    
    LIST_INSERT_HEAD(&lhead, item, entry);
    /*
    do{
        if(((item)->entry.le_next = (&lhead)->lh_first) != NULL)
            (&lhead)->lh_first->entry.le_pre = &(elm)->entry.le_next;
        (&lhead)->lh_first = (item);
        (item)->entry.le_prev = &(&lhead)->lh_first;
    }while(0);
    */
    LIST_FOREACH(item, &lhead, entry){
        printf("%d ", item->data);
    }
    /*
    for ((item) = ((&lhead)->lh_first);
        (item);
        (item) = ((item)->entry.le_next)){
        ...
    }    
    */
    printf("\n");

    while(!LIST_EMPTY(&lhead)){
        item = LIST_FIRST(&lhead);
        printf("remove %d\n", item->data);
        LIST_REMOVE(item, entry);
        free(item);
    }
    /*
    while(!((&lhead)->lh_first == NULL)){
        item = ((&lhead)->lh_first);
        ...
        do{
          if ((item)->entry.le_next != NULL)                \
            (item)->entry.le_next->entry.le_prev =             \
                (item)->entry.le_prev;                \
          *(item)->entry.le_prev = (item)->entry.le_next;            \
        } while (0);
        ...
    }
    */
}
/*
結果
2 1
remove 2
remove 1
*/

簡單隊列(simple queue)

        簡單來說,就是表對有兩個鏈域,分別指向頭和尾。

        simple queue 定義(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
SIMPLEQ_HEAD(name, type)  
SIMPLEQ_HEAD_INITIALIZER(head)  
SIMPLEQ_ENTRY(type)  

        simple queue函數(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
SIMPLEQ_INIT(head)  
SIMPLEQ_INSERT_HEAD(head, elm, field)  
SIMPLEQ_INSERT_TAIL(head, elm, field)  
SIMPLEQ_INSERT_AFTER(head, listelm, elm, field)  
SIMPLEQ_REMOVE_HEAD(head, field)  
SIMPLEQ_REMOVE(head, elm, type, field)  
SIMPLEQ_FOREACH(var, head, field)  

        simple queue方法(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
SIMPLEQ_EMPTY(head)  
SIMPLEQ_FIRST(head)  
SIMPLEQ_NEXT(elm, field)  

        簡單例子:

        用法與list用法類似,不再重複。

單鏈尾隊列(singled-linked tail queue)

        這個和Simple queue是一樣的,參考simple queue

        singled-linked tail queue定義(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
STAILQ_HEAD(name, type)  
STAILQ_HEAD_INITIALIZER(head)  
STAILQ_ENTRY(type)  

       tail queue 函數(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
STAILQ_INIT(head)  
STAILQ_INSERT_HEAD(head, elm, field)  
STAILQ_INSERT_TAIL(head, elm, field)  
STAILQ_INSERT_AFTER(head, listelm, elm, field)  
STAILQ_REMOVE_HEAD(head, field)  
STAILQ_REMOVE(head, elm, type, field)  
STAILQ_FOREACH(var, head, field)  

        tail queue方法(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
STAILQ_EMPTY(head)  
STAILQ_FIRST(head)  
STAILQ_NEXT(elm, field)  

        簡單例子:

        用法與list用法類似,不再重複。

循環隊列(circle queue)

        循環隊列。

        circle queue定義(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
LIST_HEAD(name, type)  
LIST_HEAD_INITIALIZER(head)  
LIST_ENTRY(type)  

        circle queue函數(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
LIST_INIT(head)  
LIST_INSERT_AFTER(listelm, elm, field)  
LIST_INSERT_BEFORE(listelm, elm, field)  
LIST_INSERT_HEAD(head, elm, field)  
LIST_REMOVE(elm, field)  
LIST_FOREACH(var, head, field)  

        circle queue訪問方法(具體說明不再寫,可以參考list的,或者就直接展開宏)

宏定義 說明
LIST_EMPTY(head)  
LIST_FIRST(head)  
LIST_NEXT(elm, field)  

        簡單例子

        用法與list用法類似,不再重複。

小結

        雖然這是linux/unix實現的經過長時間考驗的成熟的數據結構,但是如果不是很熟悉的話,第一次用起來還是感覺挺不習慣的。但是好在各個數據結構的定義和方法都非常類似,接口比較統一,如果用多的了,熟悉了,感覺就不錯了。

文章轉自<http://www.cnblogs.com/imlgc/archive/2012/05/02/2479654.html>


發佈了8 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章