利用组合实现循环队列

  最近在学习李先静老师的那本《系统程序员成长计划》,照着例子写了一个循环队列,利用单向循环链表实现,权当练习。

1. 单向循环链表

  我这里设计的只是一个单向循环链表,当然也可以设计为双向链表,效率应该也高点。只提供了需要用到的、最基本的接口给循环队列调用。要保持文头件的简洁,该给的都要给,不该让用户知道的一概不要加进去,否则会造成头文件组织混乱,给用户造成不必要的麻烦。链表的接口如下:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
struct _List;
typedef
struct _List List;

List
*list_create(DataDestroyFunc destroy_func, void *ctx);
Ret list_append(List
*thiz, void *data);
Ret list_delete_tail(List
*thiz);
Ret list_get_by_index(List
*thiz, size_t index, void **data);
Ret list_foreach(List
*thiz, DataVisitFunc visit, void *ctx);
Ret list_destroy(List
*thiz);
size_t list_length(List
*
thiz);

  其中,为了封装性,把struct _List的定义放到list.c文件下面,头文件只是给出了声明。

 

  在list.c里面有两个结构题,分别是链表和链表结点:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
typedef struct _listNode
{
struct _listNode * next;
void * data;
} ListNode;

struct _List
{
ListNode
* head;
ListNode
* tail;
size_t size;

DataDestroyFunc data_destroy_func;
void * data_destroy_ctx;
};

  链表结点无须在头文件中声明,因为用户只需要知道如何调用链表的操作,无须了解更多的细节。链表定义了两个指针,分别指向循环链表的开始和结尾,提供了链表的长度size,方便判断链表大小(是否为空);提供了链表结点销毁的函数: data_destroy_func,其中,DataDestroyFunc的声明在typedef.h里,这个头文件主要是定义了一些新的类型和相关的宏定义。

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
typedef enum _Ret
{
RET_OK,
RET_INVALID_PARAMS,
RET_FAIL
} Ret;

typedef
int ( * DataCompare)( void * ctx, void * data);
typedef
void ( * DataDestroyFunc)( void * ctx, void * data);
typedef
void ( * DataVisitFunc)( void * ctx, void * data);

#define and &&
#define or ||

#define return_if_fail(p) if (!(p)) \
{printf(
" %s:%d Warning: " #p " failed.\n " ,\
__func__, __LINE__);
return ; }
#define return_val_if_fail(p, ret) if (!(p)) \
{printf(
" %s:%d Warning: " #p " failed.\n " , \

  return_if_failed 和 return_val_if_failed 是glibc中判断参数是否有效的方法,只给出warning,然后返回。

 

  接下来,实现链表的接口,相对来简单点。其中,list_foreach是一个遍历链表的函数,第2个参数visit是一个函数指针,第3个参数是保存上下文的参数,这个参数是非常有必要给的,就算目前没用到,也可方便以后扩展。

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
static ListNode * list_node_create( void * data)
{
ListNode
* thiz = (ListNode * )malloc( sizeof ( struct _listNode) );
if (thiz != NULL)
{
thiz
-> next = NULL;
thiz
-> data = data;
}
return thiz;
}

List
* list_create(DataDestroyFunc destroy_func, void * ctx)
{
List
* thiz = (List * )malloc( sizeof ( struct _List) );
if (thiz != NULL)
{
thiz
-> head = NULL;
thiz
-> tail = NULL;
thiz
-> size = 0x00 ;
thiz
-> data_destroy_func = destroy_func;
thiz
-> data_destroy_ctx = ctx;
}
return thiz;
}

Ret list_append(List
* thiz, void * data)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);

ListNode
* newNode = list_node_create(data);
if (newNode == NULL)
{
return RET_FAIL;
}
if (thiz -> head == NULL)
{
thiz
-> head = thiz -> tail = newNode;
}
else
{
ListNode
* cursor = thiz -> tail;
cursor
-> next = newNode;
newNode
-> next = thiz -> head;
thiz
-> tail = newNode;
}
thiz
-> size ++ ;

return RET_OK;
}

Ret list_delete_tail(List
* thiz)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);

ListNode
* cursor = thiz -> head;

while ( (cursor -> next != thiz -> tail) and (cursor -> next != NULL) )
{
cursor
= cursor -> next;
}
if (thiz -> size > 2 )
{
cursor
-> next = thiz -> head;
SAFE_FREE(thiz
-> tail);
thiz
-> tail = cursor;
}
else
{
SAFE_FREE(thiz
-> tail);
thiz
-> tail = thiz -> head;
}
thiz
-> size -- ;

return RET_OK;
}

Ret list_get_by_index(List
* thiz, size_t index, void ** data)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);
return_val_if_fail( (index
>= 0 ) and (index < thiz -> size), RET_INVALID_PARAMS);

ListNode
* cursor = thiz -> head;
for (size_t i = 0 ; i < index; ++ i)
{
cursor
= cursor -> next;
}
* data = cursor -> data;

return RET_OK;
}

Ret list_foreach(List
* thiz, DataVisitFunc visit, void * ctx)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);
return_val_if_fail(visit
!= NULL, RET_INVALID_PARAMS);

ListNode
* cursor = thiz -> head;
for (size_t i = 0 ; i < thiz -> size; ++ i)
{
visit(ctx, cursor
-> data);
cursor
= cursor -> next;
}

return RET_OK;
}

Ret list_destroy(List
* thiz)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);

ListNode
* cursor = thiz -> head;
ListNode
* prev = NULL;
size_t size
= thiz -> size;

for (size_t i = 0 ; i < size; ++ i)
{
prev
= cursor;
cursor
= cursor -> next;
thiz
-> data_destroy_func(thiz -> data_destroy_ctx, prev);
thiz
-> size -- ;
}
SAFE_FREE(thiz);

return RET_OK;
}

size_t list_length(List
* thiz)
{
return_val_if_fail(thiz
!= NULL, - 1 );
return thiz -> size;
}

  实现了单向循环链表之后,可利用链表组合成循环队列了。队列的接口设计为:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
CQueue * cqueue_create(DataDestroyFunc data_destroy_func, void * ctx);
Ret cqueue_head(CQueue
* thiz, void ** data);
Ret cqueue_push(CQueue
* thiz, void * data);
Ret cqueue_pop(CQueue
* thiz);
Ret cqueue_foreach(CQueue
* thiz, DataVisitFunc visit, void * ctx);
size_t cqueue_length(CQueue
* thiz);
Ret cqueue_destroy(CQueue
* thiz);
循环队列定义很简单,就是给链表加一个壳而已:

 
  
struct _CQueue
{
List
* list;
};
好了,接下来就要组合链表的操作来实现循环队列了,代码很简单:)

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
CQueue * cqueue_create(DataDestroyFunc data_destroy_func, void * ctx)
{
CQueue
* thiz = (CQueue * )malloc( sizeof (CQueue) );
if (thiz != NULL)
{
thiz
-> list = list_create(data_destroy_func, ctx);
if (thiz -> list == NULL)
{
SAFE_FREE(thiz);
}
}
return thiz;
}

Ret cqueue_head(CQueue
* thiz, void ** data)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);

return list_get_by_index(thiz -> list, 0 , data);
}

Ret cqueue_push(CQueue
* thiz, void * data)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);

return list_append(thiz -> list, data);
}

Ret cqueue_pop(CQueue
* thiz)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);

return list_delete_tail(thiz -> list);
}

Ret cqueue_foreach(CQueue
* thiz, DataVisitFunc visit, void * ctx)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);
return_val_if_fail(visit
!= NULL, RET_INVALID_PARAMS);

return list_foreach(thiz -> list, visit, ctx);
}

size_t cqueue_length(CQueue
* thiz)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);

return list_length(thiz -> list);
}

Ret cqueue_destroy(CQueue
* thiz)
{
return_val_if_fail(thiz
!= NULL, RET_INVALID_PARAMS);

Ret ret
= list_destroy(thiz -> list);
if (ret != RET_OK)
{
return ret;
}

SAFE_FREE(thiz);
return RET_OK;
}
最后是编写简单的测试代码,验证是否正确:

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#define NUM 50
static void test_all( void )
{
size_t n
= NUM;
CQueue
* thiz = cqueue_create(data_destroy_func, NULL);

test_append(thiz, n);

printf(
" \n============ BEGIN OF PRINT ================\n " );
cqueue_foreach(thiz, test_print_int, NULL);
printf(
" \n============= END OF PRINT =================\n\n " );

for (size_t i = 0 ; i < n >> 1 ; ++ i)
{
cqueue_pop(thiz);
}
cqueue_destroy(thiz);
}

 

END

转载于:https://www.cnblogs.com/python_newbie/archive/2010/06/19/1760982.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值