1. 程式人生 > >queue.h之tailq.h尾佇列理解使用

queue.h之tailq.h尾佇列理解使用

一、連線、組織方式

如圖:
  • 每個entry有兩個關鍵元素:tqe_next(簡稱為next)、tqe_prev(簡稱為prev)。next指向下個entry的地址,prev指向上個entry的next的地址。
next容易理解。對於prev,說白了prev的值就是上個 entry的next的地址。這樣說可能還有點模糊,再換種說法prev的值為上個entry的地址加上next的偏移量。 畫個圖理解下: 所以,可以通過prev的值,改變上一個entry的next值(插入、刪除),當然也可以獲得、改變上一個entry的prev值(獲得上上個entry的next。。。)。因此可以通過prev向先遍歷、向後遍歷,也可以通過next向前遍歷,向後遍歷。注意:next和prev是地址相鄰的,屬於一個不可變的結構體。 一個尾佇列的連線結構如圖所示:

二、使用步驟

1、定義佇列類

這裡可以用物件化的思想去理解尾佇列。 1、定義entry,加入data
struct tail_ql_entry 
{
	TAILQ_ENTRY(tail_ql_entry) next;
	int data;
};
2、定義head,定義佇列類
TAILQ_HEAD(tail_list,tail_ql_entry);

2、例項化一個佇列(物件化)

struct tail_list list1;
當然想例項化多少個都行,以後tail_list就相當於一個自定義資料型別(佇列、連結串列)。

3、操作物件

例如在佇列頭插入一個entry
	struct tail_ql_entry * elm1 = malloc(sizeof(struct tail_ql_entry));
	elm1->data = 0;
	TAILQ_INSERT_HEAD(&list1,elm1,next);
其他的方法見queue.h。

三、例項

1、程式碼

#include 
#include 

#include 

struct tail_ql_entry 
{
	TAILQ_ENTRY(tail_ql_entry) next;
	int data;
};

TAILQ_HEAD(tail_list,tail_ql_entry);

struct tail_list list1;

int main()
{

	TAILQ_INIT(&list1);
	printf("list1 is empty? %s.\n",TAILQ_EMPTY(&list1)? "YES":"NO");

	struct tail_ql_entry * elm1 = malloc(sizeof(struct tail_ql_entry));
	elm1->data = 0;
	TAILQ_INSERT_HEAD(&list1,elm1,next);

	struct tail_ql_entry * elm2 = malloc(sizeof(struct tail_ql_entry));
	elm2->data = 1;
	TAILQ_INSERT_AFTER(&list1,elm1,elm2,next);

	struct tail_ql_entry *var = NULL;
	TAILQ_FOREACH(var,&list1,next)
	{
		printf("foreach:%d\n",var->data);
	}

	TAILQ_FOREACH_REVERSE(var,&list1,tail_list,next)
	{
		printf("foreach_reverse:%d\n",var->data);
	}

	printf("elm1 next=%d\n",TAILQ_NEXT(elm1,next)->data);

	printf("elm2 pre=%d\n",TAILQ_PREV(elm2,tail_list,next)->data);

	printf("list1 is empty? %s.\n",TAILQ_EMPTY(&list1)? "YES":"NO");

	TAILQ_REMOVE(&list1,elm1,next);
	free(elm1);
	TAILQ_REMOVE(&list1,elm2,next);
	free(elm2);
	
	printf("list1 is empty? %s.\n",TAILQ_EMPTY(&list1)? "YES":"NO");
	
	return 0;
	
	

2、執行結果

如圖: