今天我们来讲使用纯粹的C语言来实现这个通用的slist, 同时有不像前面使用C语言宏的那样暴露我们的实现细节, 将这个slist的具体实现细节给隐藏起来。
在slist的接口头文件里面我们只是声明了struct ds_slist这个结构, 而并没有真正的给出它的具体定义, 我们将它的具体定义隐藏在了具体的实现文件里面。同时我们还定义了一个该slist需要使用到的元素相关操作的接口结构。
struct ds_slist_oper {
_ds_alloc_func _alloc;
_ds_free_func _free;
};
使用上面的结构我们可以让客户自行定制器需要的元素申请以及释放的相应操作, 以实现其相应的具体内容的拷贝。如果客户不指定元素的对应操作的话, 则使用系统所默认的操作, 也就是我们这里面的直接保存指针值。
下面我们先给出这个slist的相关操作接口的声明吧:
struct ds_slist;
typedef void** ds_slist_iter;
extern struct ds_slist* ds_slistNew(struct ds_slist_oper dso);
extern void ds_slistFree(struct ds_slist** self);
extern void ds_slistClear(struct ds_slist* self);
extern int ds_slistEmpty(struct ds_slist* self);
extern size_t ds_slistSize(struct ds_slist* self);
extern int ds_slistPush_back(struct ds_slist* self, void* elem);
extern int ds_slistPush_front(struct ds_slist* self, void* elem);
extern int ds_slistPop_front(struct ds_slist* self);
extern ds_slist_iter ds_slistBegin(struct ds_slist* self);
extern ds_slist_iter ds_slistEnd(struct ds_slist* self);
extern ds_slist_iter ds_slistNext(ds_slist_iter it);
extern void* ds_slistFront(struct ds_slist* self);
extern void* ds_slistBack(struct ds_slist* self);
extern int ds_slistPrint(struct ds_slist* self, _ds_elem_func func);
如果各位同学看我前面讲到的通用stack的实现的话, 看到这里相信已经很清楚该通用slist的具体实现细节了吧。所谓大道同源, 一理通而百理通就是这个道理吧。
首先给出具体的ds_slist这个主要结构的定义:
struct ds_slist {
size_t _size;
struct _slist_node* _head;
struct _slist_node* _tail;
_ds_alloc_func _alloc;
_ds_free_func _free;
};
学习过数据结构的同学相信对该结构应该是很清楚明了的吧, 这里出现了另外一个陌生的结构struct _slist_node, 说陌生也不陌生, 大家一看就知道这个是slist的节点结构吧, 下面先给出其定义:
struct _slist_node {
void* _data;
struct _slist_node* _next;
};
我们使用结构当中的_data来保存客户需要存进slist的具体数据或者只是一个简单的指针地址。
在slist的相应操作接口当中我们在多处会用到创建一个新的slist节点结构, 并且对其进行赋元素值的操作, 为了不多处重新写相同的代码以防代码出现坏的味道, 我们这里先创建一个函数来专职做这件事。
static inline struct _slist_node*
_slist_new_node(struct ds_slist* _p, void* _x) {
struct _slist_node* node = NULL;
size_t size = sizeof(struct _slist_node);
if (NULL == _p) return NULL;
node = (struct _slist_node*)DS_Malloc(size);
if (NULL != node)
node->_data = _p->_alloc(_x);
return node;
}
以后需要使用到创建一个新的slist节点结构就可以直接使用该接口了, 而不必每一次都重复做相同的操作。
到这里我想大家对实现这个通用的slist应该有一个比较清晰的理解了吧, 我个人认为, 思想或者说是方法才是我们在软件开发过程中最重要的东西, 具体的代码只不过是将我们的思想表达出来的一个东东罢了。
好了, 讲到这里, 我们还是附上该通用slist的具体实现代码吧, 或许代码中存在这样那样的错误等, 希望大家原谅, 我也不是要来重新造轮子毕竟STL已经是这个世界上最好的了。写这些只是为了更了解其具体的实现原理, 就当做是一次数据结构的复习吧。
struct ds_slist* ds_slistNew(struct ds_slist_oper dso) {
struct ds_slist* self = NULL;
size_t size = sizeof(struct ds_slist);
self = (struct ds_slist*)DS_Malloc(size);
if (NULL != self) {
self->_alloc = NULL != dso._alloc ? dso._alloc : _alloc_def;
self->_free = NULL != dso._free ? dso._free : _free_def;
}
return self;
}
void ds_slistFree(struct ds_slist** self) {
ds_slistClear(*self);
DS_Free(*self);
}
void ds_slistClear(struct ds_slist* self) {
struct _slist_node* node = NULL;
if (NULL == self) return;
while (NULL != self->_head) {
node = self->_head;
self->_head = self->_head->_next;
self->_free(node->_data);
DS_Free(node);
}
self->_size = 0;
}
int ds_slistEmpty(struct ds_slist* self) {
return (NULL != self ? NULL == self->_head : 0);
}
size_t ds_slistSize(struct ds_slist* self) {
return (NULL != self ? self->_size : 0);
}
int ds_slistPush_back(struct ds_slist* self, void* elem) {
struct _slist_node* node = _slist_new_node(self, elem);
if (NULL == self || NULL == node) return -1;
if (NULL == self->_head || NULL == self->_tail)
self->_head = self->_tail = node;
self->_tail->_next = node;
self->_tail = node;
self->_size++;
return 0;
}
int ds_slistPush_front(struct ds_slist* self, void* elem) {
struct _slist_node* node = _slist_new_node(self, elem);
if (NULL == self || NULL == node) return -1;
node->_next = self->_head;
self->_head = node;
self->_size++;
return 0;
}
int ds_slistPop_front(struct ds_slist* self) {
struct _slist_node* node = NULL;
if (NULL == self) return -1;
if (NULL != self->_head) {
node = self->_head;
self->_head = self->_head->_next;
self->_free(node->_data);
DS_Free(node);
self->_size--;
}
return 0;
}
ds_slist_iter ds_slistBegin(struct ds_slist* self) {
return (NULL != self ? (ds_slist_iter)self->_head : NULL);
}
ds_slist_iter ds_slistEnd(struct ds_slist* self) {
return NULL;
}
ds_slist_iter ds_slistNext(ds_slist_iter it) {
struct _slist_node* It = (struct _slist_node*)it;
return (NULL != It ? (ds_slist_iter)It->_next : NULL);
}
void* ds_slistFront(struct ds_slist* self) {
struct _slist_node* node = NULL;
if (NULL == self) return NULL;
node = self->_head;
return (NULL != node ? (ds_slist_iter)node->_data : NULL);
}
void* ds_slistBack(struct ds_slist* self) {
struct _slist_node* node = NULL;
if (NULL == self) return NULL;
node = self->_tail;
return (NULL != node ? (ds_slist_iter)node->_data : NULL);
}
int ds_slistPrint(struct ds_slist* self, _ds_elem_func func) {
struct _slist_node* node = NULL;
if (NULL == self) return -1;
node = self->_head;
while (NULL != node) {
if (NULL != func)
func(node->_data);
else
_elem_def(node->_data);
node = node->_next;
}
return 0;
}
好了, 今天就到这里吧, 希望对正在寻找相同问题的解决方案的同学有所帮助吧。胡言胡语不知说了些什么, 希望高手不吝赐教!谢谢!
下次我们开始讲解通用queue的实现方法和细节吧!