Circular queue(CIRCLEQ)

Circular queueはTail queueとほぼ同じですが、最後のエレメントの次エレメントを示すポインタがNULL出なく、ヘッダを指し示している所が違います。

Circular queueの構造
Circular queueの構造

CIRCLEQ 構造体の定義

CIRCLEQ構造を使用するには、まずCIRCLEQ形式のデータ構造を定義る必要があります。

CIRCLEQ_ENTRY(type)

CIRCLEQ_ENTRYは、CIRCLEQ形式のデータ構造を定義します。各エレメントに数字が1つだけ入っているCIRCLEQ構造、CircleQを定義してみると、下記のようになります。

struct CircleQ {
    CIRCLEQ_ENTRY(CircleQ) cqueue_ptr;
                int32_t data;
};	

この構造体内にあるCIRCLEQへのポインタを作成するマクロであり、展開されると次のようになります。

struct CircleQ {
    struct {
        struct TailQ *tqe_next;
        struct TailQ **tqe_prev;
    } cqueue_ptr;
                int32_t data;
};	

これは定義だけで、まだ実体は無いことに注意してください。

CIRCLEQ_HEAD(name, type)

CIRCLEQ_HEADは、エレメントの先頭アドレスが入る構造体を定義します。

CIRCLEQ_HEAD(CircleQHead, CircleQ);	

これは、展開されると次のようになります。

struct CircleQHead {
    struct TailQ *tqh_first;
    struct TailQ **tqh_last;
};	

これも定義だけで、まだ実体は無いことに注意してください。

CIRCLEQ 構造体の初期化

CIRCLEQ_HEAD_INITIALIZER(head)

CIRCLEQ_HEAD_INITIALIZERは、CIRCLEQ_HEADを初期化します。次のように使用します。

// CIRCLEQヘッダの実体を定義
struct CircleQHead cqueue_head = CIRCLEQ_HEAD_INITIALIZER(&cqueue_head);	

CIRCLEQ_INIT(head)

CIRCLEQ_INITは、CIRCLEQを初期化します。次のように使用します。

if(!(CIRCLEQ_EMPTY(&cqueue_head)))         // CIRCLEQが空であるかチェック
    CIRCLEQ_INIT(&cqueue_head);            // CIRCLEQの初期化	

CIRCLEQ Access Methods

CIRCLEQ_FIRST(head)

CIRCLEQ_FIRSTは、CIRCLEQの先頭エレメントのポインタを返します。

arithmetic = CIRCLEQ_FIRST(&cqueue_head); // 先頭elementを取得	

CIRCLEQ_LAST(head)

CIRCLEQ_LASTは、CIRCLEQの最終のエレメントを返します。

arithmetic = CIRCLEQ_LAST(&cqueue_head); // 最後のelementを取得	

CIRCLEQ_END(head)

CIRCLEQ_ENDは、NULLを返します。

CIRCLEQ_NEXT(elm, field)

CIRCLEQ_NEXTは、エレメント(elm)に連結されている次エレメントのポインタを返します。

arithmetic_next = CIRCLEQ_NEXT(arithmetic,cqueue_ptr); // arithmeticの次elementを取得	

CIRCLEQ_PREV(elm, field)

CIRCLEQ_PREVは、指定エレメント(elm)に連結されている、直前のエレメントを返します。

arithmetic_prev = CIRCLEQ_PREV(arithmetic,cqueue_ptr); // arithmeticの前elementを取得	

CIRCLEQ_EMPTY(head)

CIRCLEQ_EMPTYは、CIRCLEQが空であるか調べます。

CIRCLEQ Insert Methods

CIRCLEQ_INSERT_HEAD(head, elm, field)

CIRCLEQ_INSERT_HEADは、新しいエレメント(elm)をCIRCLEQ(head)の先頭に追加します。

CIRCLEQ_INSERT_HEAD(&cqueue_head, &number[1], cqueue_ptr); // 1を先頭に挿入  (1)	

CIRCLEQ_INSERT_TAIL(head, elm, field)

CIRCLEQ_INSERT_TAILは、新しいエレメント(elm)をCIRCLEQ(head)の一番最後に追加します。

CIRCLEQ_INSERT_TAIL(&cqueue_head,&number[3],cqueue_ptr); // 3を最後に挿入  (1 3)	

結果は次のようになります。

CIRCLEQ_INSERT_TAILの結果
CIRCLEQ_INSERT_TAILの結果

CIRCLEQ_INSERT_AFTER(head, listelm, elm, field)

CIRCLEQ_INSERT_AFTERは、指定したエレメント(listelm)の後に、新しいエレメント(elm)を追加します。

CIRCLEQ_INSERT_AFTER(&cqueue_head,&number[0],&number[2],cqueue_ptr); // 1の後に2を挿入 (1 2 3)	

結果は次のようになります。

CIRCLEQ_INSERT_AFTERの結果
CIRCLEQ_INSERT_AFTERの結果

CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field)

CIRCLEQ_INSERT_BEFOREは、指定したエレメント(listelm)の前に、新しいエレメント(elm)を追加します。

CIRCLEQ_INSERT_BEFORE(&cqueue_head,&number[1],&number[4],cqueue_ptr); // 1の前に4を挿入 (4 1 2 3)	
CIRCLEQ_INSERT_BEFOREの結果
CIRCLEQ_INSERT_BEFOREの結果

結果は次のようになります。

CIRCLEQ_REPLACE(head, elm, elm2, field)

CIRCLEQ_REPLACEは、エレメント(elm)を、新しいエレメント(elm2)に置換えます。

CIRCLEQ_REPLACE(&cqueue_head,&number[4],&number[0],cqueue_ptr); // 4を0にReplace  (0 1 2 3)	

コンパイルエラーが出てしまいます,なんかバグってる気がする。

CIRCLEQ Loop Methods

CIRCLEQ_FOREACH(var, head, field)

CIRCLEQ_FOREACHは、headに格納されたエレメントを最初から終りまでループして、varにポインタを返します。

// データの最初から終わりまでループ
CIRCLEQ_FOREACH(arithmetic,&cqueue_head,cqueue_ptr){
   printf("%d\n",arithmetic->data);
}	

結果は、下記のようになります。

0
1
2
3
      

CIRCLEQ_FOREACH_REVERSE(var, head, headname, field)

CIRCLEQ_FOREACH_REVERSEは、headに格納されたエレメントを最後から最初まで逆にループして、varにポインタを返します。

// データの最後から最初までループ
CIRCLEQ_FOREACH_REVERSE(arithmetic,&cqueue_head,CircleQHead,cqueue_ptr){
   printf("%d\n",arithmetic->data);
}	

結果は、下記のようになります。

3
2
1
0
      

CIRCLEQ Remove Methods

CIRCLEQ_REMOVE(head, elm, field)

CIRCLEQ_REMOVEは、CIRCLEQ(head)の先頭エレメントを削除します。

// データが空になるまで削除します
while (CIRCLEQ_FIRST(&cqueue_head))
    CIRCLEQ_REMOVE_HEAD(&cqueue_head,cqueue_ptr);	

CIRCLEQデータの操作sample

CIRCLEQデータの操作sampleです。

Last modified: Thu Jan 24 18:32:09 2008 JST