list.h
这个list.h其实是linux内核中链表实现的精简版(只需要一个头文件),linux提供的这套接口更像是构造list的零部件。用户可以选择直接用它定制化自己的 list型数据结构,甚至可以实现一个更为 高层次的、通用的 list接口(如下面的clist)
#ifndef _LIST_H_
#define _LIST_H_
#ifdef __cplusplus
extern "C"
{
#endif
struct list_node
{
struct list_node *next;
struct list_node *prev;
};
/**
* ListNodeToItem - get the struct for this entry
* @node: the &struct list_node pointer.
* @container: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define ListNodeToItem(node, container, member) \
(container *) (((char*) (node)) - ((unsigned long) &((container *)0)->member))
#define ListDeclare(name) \
struct list_node name = { \
.next = &name, \
.prev = &name, \
}
/**
* ListForEach - iterate over a list
* @node: the &struct list_node to use as a loop cursor.
* @list: the head for your list.
*/
#define ListForEach(node, list) \
for (node = (list)->next; node != (list); node = node->next)
/**
* ListForEachReverse - iterate over a list backwards
* @node: the &struct list_node to use as a loop cursor.
* @list: the head for your list.
*/
#define ListForEachReverse(node, list) \
for (node = (list)->prev; node != (list); node = node->prev)
/**
* ListForEachSafe - iterate over a list safe against removal of list entry
* @node: the &struct list_node to use as a loop cursor.
* @n: another &struct list_node to use as temporary storage
* @list: the head for your list.
*/
#define ListForEachSafe(node, n, list) \
for (node = (list)->next, n = node->next; \
node != (list); \
node = n, n = node->next)
static inline void ListInit(struct list_node *node)
{
node->next = node;
node->prev = node;
}
/**
* ListAddTail - add a new entry
* @head: list head to add it before
* @item: new entry to be added
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void ListAddTail(struct list_node *head, struct list_node *item)
{
item->next = head;
item->prev = head->prev;
head->prev->next = item;
head->prev = item;
}
/**
* ListAddHead - add a new entry
* @head: list head to add it after
* @item: new entry to be added
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void ListAddHead(struct list_node *head, struct list_node *item)
{
item->next = head->next;
item->prev = head;
head->next->prev = item;
head->next = item;
}
/**
* ListAppend - let list2(head2) append to the tail of list1(head1)
*/
static inline void ListAppend(struct list_node *head1, struct list_node *head2)
{
head2->prev->next = head1;
head2->next->prev = head1->prev;
head1->prev->next = head2->next;
head1->prev = head2->prev;
head2->prev = head2;
head2->next = head2;
}
static inline void ListReverse(struct list_node *head)
{
struct list_node *pNode = head;
struct list_node *pTmp = NULL;
while(pNode->next != head)
{
//store the next node
pTmp = pNode->next;
//swap
//pTmp = pNode->next;
pNode->next = pNode->prev;
pNode->prev = pTmp;
pNode = pTmp;
}
//last swap
pTmp = pNode->next;
pNode->next = pNode->prev;
pNode->prev = pTmp;
}
/*
* ZX_ListRemove - delete a list entry
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void ListRemove(struct list_node *item)
{
item->next->prev = item->prev;
item->prev->next = item->next;
}
#define ListIsEmpty(list) ((list) == (list)->next)
#define ListHead(list) ((list)->next)
#define ListTail(list) ((list)->prev)
#ifdef __cplusplus
}
#endif
#endif //LIST_H_
直接使用 list.h
在头文件中,定义一个node,一个manager
//自己实现的一个stack(queue也是可以实现的)
typedef struct {
pthread_mutex_t lock; //这里应该有一个mutex lock的,但是写的时候忘记加了
unsigned int u32StackSize;
struct zxlist_node listNode;
}FRAME_UI_STACK_MGR; //stack manager结构体
typedef struct {
UI_FRAME_S *pUIFrame;
struct zxlist_node listNode;
}FRAME_UI_STACK_NODE;
在.c文件中,
static FRAME_UI_STACK_MGR gstFrameUIStack = {
.lock = PTHREAD_MUTEX_INITIALIZER,
};
static int frameUIStackInit() {
gstFrameUIStack.u32StackSize = 0;
ZX_ListInit(&gstFrameUIStack.listNode);
return 0;
}
static int frameUIStackDeinit() {//descroy the stack
zxlist_node *pListNode = NULL;
FRAME_UI_STACK_NODE *pStackNode = NULL;
while(!ZX_ListEmpty(&gstFrameUIStack.listNode)) {
pListNode = ZX_ListTail(&gstFrameUIStack.listNode);
pStackNode = ZX_ListNodeToItem(pListNode, FRAME_UI_STACK_NODE, listNode);
ZX_ListRemove(pListNode);
free(pStackNode);
}
gstFrameUIStack.u32StackSize = 0;
return 0;
}
static int frameUIStackPush(UI_FRAME_S *pUIFrame) {
if(pUIFrame == NULL) {
printf("frameUIStackPush error: invalid param\n");
return -1;
}
FRAME_UI_STACK_NODE *pUINode = (FRAME_UI_STACK_NODE *)malloc(sizeof(FRAME_UI_STACK_NODE));
if(pUINode == NULL) {
printf("frameUIStackPush add node error: no more availiable mem\n");
return -1;
}
pUINode->pUIFrame = pUIFrame;
ZX_ListAddTail(&gstFrameUIStack.listNode,&(pUINode->listNode)); //add to tail
gstFrameUIStack.u32StackSize++;
return 0;
}
static int frameUIStackTop(UI_FRAME_S **ppUIFrame) {
if(ppUIFrame == NULL) {
printf("frameUIStackTop error: invalid param\n");
return -1;
}
if(gstFrameUIStack.u32StackSize == 0) {
if(ZX_ListEmpty(&gstFrameUIStack.listNode)) {//confirm
printf("frameUIStackTop stack is empty!\n");
*ppUIFrame = NULL;
return 0;
} else {
printf("frameUIStackTop error!\n");
*ppUIFrame = NULL;
return -1;
}
}
zxlist_node *pListNode = ZX_ListTail(&gstFrameUIStack.listNode); //just get the tail
FRAME_UI_STACK_NODE *pStackNode = ZX_ListNodeToItem(pListNode, FRAME_UI_STACK_NODE, listNode);
*ppUIFrame = pStackNode->pUIFrame;
return 0;
}
static int frameUIStackPop(UI_FRAME_S **ppUIFrame) {
if(gstFrameUIStack.u32StackSize == 0) {
if(ZX_ListEmpty(&gstFrameUIStack.listNode)){
printf("frameUIStackPop stack is empty!\n");
*ppUIFrame = NULL;
return 0;
} else {
printf("frameUIStackPop error!\n");
*ppUIFrame = NULL;
return -1;
}
}
zxlist_node *pListNode = ZX_ListTail(&gstFrameUIStack.listNode); //get the tail
FRAME_UI_STACK_NODE *pStackNode = ZX_ListNodeToItem(pListNode, FRAME_UI_STACK_NODE, listNode);
if(ppUIFrame != NULL) {//if param is null, just discard top element
*ppUIFrame = pStackNode->pUIFrame;
}
ZX_ListRemove(pListNode); //remove the tail
free(pStackNode);
gstFrameUIStack.u32StackSize--;
return 0;
}
数组实现的stack和queue比链表效率更高一点
- 数组实现的stack应该很简单
- 数组实现的queue分为两种:
- 使用环形队列,效率高,但需要考虑wrap的情况 (RingBuf)
- 不用环形队列,使用memmove,效率有折损但简单(bufQueue)
list、stack、fifo(即queue)都属于线性结构,stack和fifo可以看作阉割版的list
cList.c,这是在学习了《c 接口与实现》第7章 后弄的一个类 lisp 链表 的实现
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "cList.h"
//将一个数据push到list的head
clist List_push(clist list, void *x)
{
unsigned int flag=0;
clist listTmp = NULL;
clistNode *pNodeTmp = NULL;
if(!list)
{ //new malloc a list manager node and init
listTmp = (clist)malloc(sizeof(struct clistManager));
if(!listTmp)
goto FAIL_1;
ListInit(&listTmp->listNode);
listTmp->u32ListSize = 0;
flag = 1;
}
else
listTmp = list;
//new list node and init
pNodeTmp = (clistNode *)malloc(sizeof(clistNode));
if(!pNodeTmp)
goto FAIL_2;
ListInit(&pNodeTmp->listNode);
pNodeTmp->data = x;
//add list node to clist manager(header)
ListAddHead(&listTmp->listNode, &pNodeTmp->listNode);
listTmp->u32ListSize++;
return listTmp;
FAIL_2:
if(flag)
free(listTmp);
FAIL_1:
return NULL;
}
//构造一个list,应该以NULL或者其他为false的值结尾
clist List_list(void *x, ...)
{
va_list ap;
va_start(ap, x);
clist listTmp = NULL;
clistNode *pNodeTmp = NULL;
struct list_node *plistNode = NULL;
//new malloc a list manager node and init
listTmp = (clist)malloc(sizeof(struct clistManager));
if(!listTmp)
goto FAIL_1;
ListInit(&listTmp->listNode);
listTmp->u32ListSize = 0;
for ( ; x; x = va_arg(ap, void *))
{
//new list node and init
pNodeTmp = (clistNode *)malloc(sizeof(clistNode));
if(!pNodeTmp) // TODO: this may cause memleak
goto FAIL_2;
ListInit(&pNodeTmp->listNode);
pNodeTmp->data = x;
ListAddTail(&listTmp->listNode, &pNodeTmp->listNode);
listTmp->u32ListSize++;
}
va_end(ap);
return listTmp;
FAIL_2:
List_free(&listTmp);
FAIL_1:
return NULL;
}
clist List_append(clist list, clist tail)
{
if(!list)
return tail;
if(tail)
{
ListAppend(&list->listNode, &tail->listNode);
list->u32ListSize += tail->u32ListSize;
tail->u32ListSize = 0;
}
return list;
}
clist List_copy(clist list)
{
clist listTmp = NULL;
clistNode *pNodeTmpSrc = NULL;
clistNode *pNodeTmpDst = NULL;
if(list)
{
//new malloc a list manager node and init
listTmp = (clist)malloc(sizeof(struct clistManager));
if(!listTmp)
goto FAIL_1;
ListInit(&listTmp->listNode);
listTmp->u32ListSize = 0;
struct list_node *plistNode = NULL;
ListForEach(plistNode,&list->listNode)
{
pNodeTmpSrc = ListNodeToItem(plistNode, clistNode, listNode);
//new list node and init
pNodeTmpDst = (clistNode *)malloc(sizeof(clistNode));
if(!pNodeTmpDst)
goto FAIL_2;
ListInit(&pNodeTmpDst->listNode);
pNodeTmpDst->data = pNodeTmpSrc->data;
//insert
ListAddTail(&listTmp->listNode, &pNodeTmpDst->listNode);
listTmp->u32ListSize++;
}
}
return listTmp;
FAIL_2:
List_free(&listTmp);
FAIL_1:
return NULL;
}
clist List_pop(clist list, void **x)
{
struct list_node *plistNode = NULL;
clistNode *pNodeTmp = NULL;
if (list && !ListIsEmpty(&list->listNode))
{
plistNode = ListHead(&list->listNode);
pNodeTmp = ListNodeToItem(plistNode, clistNode, listNode);
if (x)
*x = pNodeTmp->data;
ListRemove(plistNode);
free(pNodeTmp);
list->u32ListSize--;
}
return list;
}
//NOTE :param list and returned list both reversed!
clist List_reverse(clist list)
{
if(list)
ListReverse(&list->listNode);
return list;
}
int List_length(clist list)
{
int n=0;
if(list)
n = list->u32ListSize;
return n;
}
void List_free(clist *plist)
{
struct list_node *plistNode = NULL;
clistNode *pNodeTmp = NULL;
clist list = NULL;
if (plist)
{
list = *plist;
if(list)
{
while(!ListIsEmpty(&list->listNode))
{
plistNode = ListHead(&list->listNode);
pNodeTmp = ListNodeToItem(plistNode, clistNode, listNode);
ListRemove(plistNode);
free(pNodeTmp);
list->u32ListSize--;
}
free(list);
}
*plist = NULL;
}
}
void List_map(clist list, void apply(void **x,int index, void *cl), void *cl)
{
struct list_node *plistNode = NULL;
clistNode *pNodeTmp = NULL;
int i=0;
if(apply && list)
{
ListForEach(plistNode,&list->listNode)
{
//apply 使用的是指向 first 的指针,因此可能改变 first 指针的指向
pNodeTmp = ListNodeToItem(plistNode, clistNode, listNode);
apply(&pNodeTmp->data,i++,cl); //
}
}
}
void **List_toArray(clist list, void *end)
{
int i=0, n;
struct list_node *plistNode = NULL;
clistNode *pNodeTmp = NULL;
void **array = NULL;
if(list)
{
n = list->u32ListSize;
array = (void **)malloc((n + 1)*sizeof (void *));
if(!array)
return NULL;
ListForEach(plistNode,&list->listNode)
{
pNodeTmp = ListNodeToItem(plistNode, clistNode, listNode);
array[i++] = pNodeTmp->data;
}
array[i] = end;
}
return array;
}
//cList.h
#ifndef _COMMON_LIST_H
#define _COMMON_LIST_H
#include "list.h"
typedef struct clistManager{
struct list_node listNode;
unsigned int u32ListSize;
} *clist;
typedef struct {
struct list_node listNode;
void *data;
} clistNode;
clist List_push(clist list, void *x);
clist List_list(void *x, ...);
clist List_append(clist list, clist tail);
clist List_copy(clist list);
clist List_pop(clist list, void **x);
clist List_reverse(clist list);
int List_length(clist list);
void List_free(clist *plist);
void List_map(clist list, void apply(void **x,int index, void *cl), void *cl);
void **List_toArray(clist list, void *end);
#endif