adlist.c文件中主要是一些双向链表的操作的实现。
//listCreate函数类似于一个list的构造函数
//直接通过zmalloc函数申请list大小的空间,并且将pre,next指针都置为NULL
//另外,dup,free,match函数指针也设置为NULL
list *listCreate(void)
{
struct list *list;
if ((list = zmalloc(sizeof(*list))) == NULL) //申请空间
return NULL; //申请失败的时候返回NULL
list->head = list->tail = NULL;
list->len = 0;
list->dup = NULL;
list->free = NULL;
list->match = NULL;
return list;
}
listEmpty函数作用是移除所有的元素,但是保留list本身
void listEmpty(list *list)
{
unsigned long len; //list长度
listNode *current, *next; //两个指针一个保存当前节点,一个指向next节点
current = list->head; //将current置为list的头结点
len = list->len; //len设置为list的len
while(len--) {
next = current->next;
if (list->free) list->free(current->value); //调用struct内部的free函数
zfree(current); //删除节点
current = next; //current 设置为next
}
list->head = list->tail = NULL; //头尾节点转为NULL
list->len = 0; //长度设置为0
}
//这个函数比较简单,先调用listEmpty函数,后直接zfree掉整个list
void listRelease(list *list)
{
listEmpty(list);
zfree(list);
}
listAddNodeHead函数作用是将个值为valus的node插入到list的头部
类似于STL中的push_front()函数
//将一个value插入list头部
list *listAddNodeHead(list *list, void *value)
{
listNode *node; //新的节点node
//为节点申请空间,如果申请失败的话直接返回NULL
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value; //node的value设置为value
//如果list为空,那么list的头指针和尾指针都为node,并且node的前向指针与后向指针都为NULL
if (list->len == 0) {
list->head = list->tail = node;
node->prev = node->next = NULL;
} else {
node->prev = NULL; //node的prev指针指向NULL
node->next = list->head; //node的next指针指向以前的头指针
list->head->prev = node; //head的prev指针指向node
list->head = node; //更新head
}
list->len++; //长度增加
return list;
}
与listAddNodeHead函数对应,是在list尾部插入一个值为value的节点,具体实现方式与listAddNodeHead也基本类似
list *listAddNodeTail(list *list, void *value)
{
//同样的申请空间
listNode *node;
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value;
//如果list为空,那么直接head和tail节点都是node
if (list->len == 0) {
list->head = list->tail = node;
node->prev = node->next = NULL;
} else {
//否则将tail节点指向node之后更新tail节点
node->prev = list->tail;
node->next = NULL;
list->tail->next = node;
list->tail = node;
}
list->len++;
return list;
}
listInsertNode函数作用主要是在指定节点之前或者之后插入一个新的节点,
这里引入了一个after变量,如果after变量为0,那么就是在指定节点之前插入,否则
就在指定节点之后插入一个新的节点
代码如下:
list *listInsertNode(list *list, listNode *old_node, void *value, int after) {
//node就是新节点,依旧是先为新节点分配内存
listNode *node;
if ((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value;
//如果afer不为零的话,那么就是在old_node之后插入新节点
if (after) {
node->prev = old_node; //node的prev指针指向old_node
node->next = old_node->next; //node的next指针指向old_node的下一个节点
if (list->tail == old_node) { //如果old_node之前是作为list的尾节点,那么此时更新一次尾节点
list->tail = node;
}
//如果after为0,那么就在old_node之前插入节点
} else {
node->next = old_node;
node->prev = old_node->prev;
if (list->head == old_node) {
list->head = node;
}
}
//这里的操作是将node和old_node连接起来
//例如,node插入到old_node之后,此时仅仅设置了node -> prev = old_node,还需要设置old_node -> next = node,所以就有了下述两个操作
if (node->prev != NULL) {
node->prev->next = node;
}
if (node->next != NULL) {
node->next->prev = node;
}
list->len++;
return list;
}
listDelNode是list中删除节点的函数
//操作就是基本的双向链表的删除操作
void listDelNode(list *list, listNode *node)
{
if (node->prev)
node->prev->next = node->next;
else
list->head = node->next;
if (node->next)
node->next->prev = node->prev;
else
list->tail = node->prev;
if (list->free) list->free(node->value);
zfree(node);
list->len--;
}
listGetIterator函数将根据类型返回一个迭代器
listIter *listGetIterator(list *list, int direction)
{
//声明一个迭代器并且为其分配内存
listIter *iter;
if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;
//根据direction初始化迭代器
if (direction == AL_START_HEAD)
iter->next = list->head;
else
iter->next = list->tail;
iter->direction = direction;
return iter;
}
释放迭代器操作,利用zfree释放迭代器
void listReleaseIterator(listIter *iter) {
zfree(iter);
}
重置迭代器
//将迭代器li重置为正向迭代器
void listRewind(list *list, listIter *li) {
li->next = list->head;
li->direction = AL_START_HEAD;
}
将迭代去重置为逆向迭代器
void listRewindTail(list *list, listIter *li) {
li->next = list->tail;
li->direction = AL_START_TAIL;
}
listNext函数的主要作用是根据返回迭代器指向的下一个元素
并且迭代器的指向将会发生移动
listNode *listNext(listIter *iter)
{
//得到iter指向的节点
listNode *current = iter->next;
//如果current不为NULL的话,迭代器将会根据方向发生移动
if (current != NULL) {
if (iter->direction == AL_START_HEAD)
iter->next = current->next;
else
iter->next = current->prev;
}
return current;
}
#### listDup
listDup的作用是复制整个list,如果内存溢出的话,将会返回
NULL。否则将会返回新list
list *listDup(list *orig)
{
//先声明一个list为copy,并且为其分配空间
list *copy;
listIter iter;
listNode *node;
if ((copy = listCreate()) == NULL)
return NULL;
//成员函数指针的复制
copy->dup = orig->dup;
copy->free = orig->free;
copy->match = orig->match;
//初始化迭代器,通过迭代器来遍历list,并且复制每一个节点
listRewind(orig, &iter);
while((node = listNext(&iter)) != NULL) {
void *value;
//如果存在节点复制函数,那么直接使用节点复制函数复制即可
if (copy->dup) {
value = copy->dup(node->value);
if (value == NULL) {
//复制失败的情况下,返回NULL
listRelease(copy);
return NULL;
}
} else
//如果没有节点复制函数的话,那么就直接赋值
value = node->value;
//加入尾部
if (listAddNodeTail(copy, value) == NULL) {
listRelease(copy);
return NULL;
}
}
return copy;
}
在list中搜索key值
listNode *listSearchKey(list *list, void *key)
{
listIter iter; //依旧是通过迭代器来遍历
listNode *node;
listRewind(list, &iter);
while((node = listNext(&iter)) != NULL) {
if (list->match) { //如果存在match函数,那么直接使用match函数
if (list->match(node->value, key)) {
return node;
}
} else {
//如果不存在match函数的话,直接对比既可
if (key == node->value) {
return node;
}
}
}
return NULL;
}
这里的index为0的情况下表示头结点,为1的情况下表示第二个节点以此类推
同理,在index为负数的情况下表示从尾部开始搜索,如果index为-1的情况下,表示tail节点。以此类推
listNode *listIndex(list *list, long index) {
listNode *n;
//如果index < 0,那么就是从后往前搜索。
if (index < 0) {
index = (-index)-1; //注意这里的-1操作,因为index = -1表示tail节点
n = list->tail;
while(index-- && n) n = n->prev;
} else {
n = list->head;
while(index-- && n) n = n->next;
}
return n;
}
listRotate的作用是将尾节点旋转到头部
void listRotate(list *list) {
listNode *tail = list->tail; //获取尾节点
if (listLength(list) <= 1) return; //如果长度小于等于1的话,无需操作
list->tail = tail->prev; //先更新尾节点
list->tail->next = NULL; //新的尾节点后置为NULL
list->head->prev = tail; //将tail插入头部
tail->prev = NULL;
tail->next = list->head;
list->head = tail; //更新head
}
listJoin函数作用是将两个list连接起来
//将o连接在l的尾部
void listJoin(list *l, list *o) {
if (o->head) //如果o链表不为空的话,直接将o->head连接在l->tail后面即可
o->head->prev = l->tail;
if (l->tail) //如果l的尾节点不为空,那么tail指向o -> head
l->tail->next = o->head;
else
//否则l为空,直接将o的head赋值给l-> head既可
l->head = o->head;
if (o->tail) l->tail = o->tail; //更新l -> tail
l->len += o->len; //更新长度
o->head = o->tail = NULL; //o链表置零(因为连接之后仅剩一条链表了)
o->len = 0;
}