转载请注明出处:http://blog.csdn.net/ecorefeng
作者:朱克锋
专用链表在这里是指该链表的实现和调用耦合在一起,只能被一个调用者使用,而不能单独在其他地方被重用。通用链表则相反,它具有通用性,可以在多处被重复使用。尽管通用链表相对专用链表来说有很多优越之处,不过草率地断定通用链表比专用链表好也是不公正的,因为它们都有自己的优点和适用范围。
专用链表的优点
性能更高。专用链表的实现和调用在一起,可以直接访问数据成员,省去了包装函数带来的性能开销,可以提高时间性能。专用链表无需实现完整的接口,只要满足自己的需要就行了,生成的代码更小,因此可以提高空间性能。
依赖更少。自己实现不用依赖于别人。有时候你要写一个规模不大的跨平台程序,比如想在展讯手机平台和MTK手机平台上运行,虽然有现存的库可用,但你又不想把整个库移植过去,那么实现一个专用链表是不错的选择。
实现简单。实现专用链表时,不需要考虑在各种复杂应用情况下的特殊要求,也不需要提供完整的接口,所以实现起来比通用链表更为简单。
通用链表的优点(从全局来看)
可靠性更高。通用链表的实现要复杂得多,复杂的东西意味着不可靠。但它是可以重复使用的,其存在的问题会随每一次重用而被发现和改正,慢慢地就形成一个可靠的函数库。
开发效率更高。通用链表的实现要复杂得多,复杂的东西也意味着更高的开发成本。同样因为它是可以重复使用的,开发成本会随每一次重用而降低,从整个项目来看,会大大提高开发效率。
注:这段话摘自《系统程序员成长计划》
接下来是对通用链表实现的说明:
先建立通用链表的存储结构:
typedef struct _DListNode
{
void *data;
struct _DListNode *prev;
struct _DListNode *next;
}DListNode;
typedef struct _DList
{
DListNode *head;
DListNode *current;
}DList;
接下来定义一个enum来存放程序中函数的返回值,可以不定义
typedef enum _Ret
{
RET_OK = 1,
RET_FAULT,
RET_OOM,
}Ret;
为了使程序更具通用性可以定义一个回调函数原型,用于回调
typedef void*(*VisitFunc)(void *ctx, void* data);
typedef void (*DesFunc)(DList *dlist, int index);
定义一个用于测试的宏
#define return_val_if_fail(p, val)/
if(!(p)){printf("%s:%d"#p" failed./n",__func__,__LINE__); return val;}
下面定义通用双向链表的基本操作,包括:
DList *dlist_create();
int dlist_len(DList *dlist);
DListNode *dlist_get(DList *dlist, int index);
Ret dlist_delete(DList *dlist, int index);
Ret dlist_add(DList *dlist, int index, void *data);
//void dlist_print(DList *dlist, void( *print_func)(void* data));
void *dlist_foreach(DList *dlist, VisitFunc visit_func, void *ctx);
Ret dlist_destroy(DList *dlist,DesFunc des_func, int index);
头文件基本定义结束,保存为dlist.h
为了优化一般会在头文件中定义选择编译的宏
#ifndef DLIST_H
#define DLIST_H
。。。
。。。
#endif /*DLIST_H*/
避免重复编译
完整头文件如