您的位置:首页 > 数据库 > Redis

(redis)adlist.h/adlist.c理解

2014-01-12 16:57 369 查看
版权最终解释权归Leonjhan所有,要引述麻烦添加下作者博客leonjhan,thanks~



/********************************** Part1:adlist.h *****************************************/

#ifndef __ADLIST_H__
#define __ADLIST_H__


1.1 定义了一个双向的链表的节点listNode

typedef struct listNode{
struct listNode *prev;      //前序节点
struct listNode *next;      //后继节点
void *value;       //节点值(注意采用的数据类型)
}listNode;

1.2 定义链表的迭代器

typedef struct listIter{
listNode *next;    //下一个节点
int direction;    //方向
}listIter;


1.3 定义一个链表

typedef struct list{
listNode *head;   //头节点
listNode *tail;   //尾节点
unsigned long len;    //节点个数
void *(*dup)(void *ptr); //复制ptr内容函数
void (*free)(void *ptr);  //释放ptr值函数
int (*match)(void *ptr,void *key); //匹配ptr和key内容的函数
}list;


1.4 定义一些宏

#define listLength(l)    ((l)->len)    //返回链表的节点数
#define listFirst(l)     ((l)->head)   //返回链表的头节点
#define listLast(l)      ((l)->tail)   //返回链表的尾节点
#define listPrevNode(n)  ((n)->prev)   //返回节点n的前继节点
#define listNextNode(n)  ((n)->next)   //返回节点n的后继节点
#define listNodeValue(n) ((n)->value)  //返回节点n的值

//采用list中的处理方法设置外部调用的方法
#define listSetDupMethod(l,m) ((l)->dup = (m))      //设置复制方法
#define listSetFreeMethod(l,m) ((l)->free = (m))    //设置释放方法
#define listSetMatchMethod(l,m) ((l)->match = (m))  //设置匹配方法
#define listGetDupMethod(l) ((l)->dup)       //得到复制方法
#define listGetFree(l) ((l)->free)           //得到释放方法
#define listGetMatchMethod(l) ((l)->match)   //得到匹配方法

1.5 定义一些函数处理原型

list *listCreate(void);    //创造一个双向链表
void listRelease(list *list);  //释放链表
list *listAddNodeHead(list *list, void *value);  //给链表添加一个头节点
list *listAddNodeTail(list *list, void *value);  //给链表添加一个尾节点
list *listInsertNode(list *list, listNode *old_node, void *value, int after); //给旧节点按照after的设置向前向后添加一个节点
void listDelNode(list *list, listNode *node);      //删除节点
listIter *listGetIterator(list *list, int direction);   //得到链表的迭代器
listNode *listNext(listIter *iter);          //返回链表下一个节点
void listReleaseIterator(listIter *iter);    //释放链表迭代器
list *listDup(list *orig);   //复制一个双向链表
listNode *listSearchKey(list *list, void *key);  //搜索节点的值
listNode *listIndex(list *list, long index);    //返回索引对应的节点
void listRewind(list *list, listIter *li);      //将迭代器指针重新设置为链表头节点
void listRewindTail(list *list, listIter *li);  //将迭代器指针重新设置为链表尾节点
void listRotate(list *list);     //将尾节点取出插入到头节点(旋转的链表)

1.6 常量定义(设置迭代器方向)

#define AL_START_HEAD 0
#define AL_START_TAIL 1


接下来讲述下源文件的具体实现(这里主要挑一些代表性性质的代码讲述,大家可跟帖一起讨论下...)

/********************************** Part2:adlist.c *****************************************/

#include <stdlib.h>

#include "adlist.h"

#include "zmalloc.h" //作者自己实现的内存分配方式

//链表初始化释放操作................................................................................

2.1 链表的创建(内部一些数据的初始化)

list *listCreate(void)
{
struct list *list;
if((list = zmalloc(sizeof(*list))) == NULL)
return NULL;
list->head = list->tail = NULL;
list->len = 0;
list->dup = NULL;
list->free = NULL;
list->match = NULL;
}


2.2 链表的释放

void listRelease(list *list)
{
unsigned long len;
listNode *current,*next;

current = list->head;
len = list->len;
while(len--){
next = current->next;
//先用自带的方法释放节点的值,然后再释放当前这个节点
if(list->free)  list->free(current->value);
zfree(current);
current = next;
}
zfree(list);
}


//链表中节点操作..............................................................................

2.3 新建一个值为value的节点,并且置为链表的头节点

list *listAddNodeHead(list *list,void *value)
{
listNode *node;
if((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value;

//考虑加入新节点链表为空的情况
if(list->len == 0){
list->head = list->tail = node;
node ->prev = node->next = NULL;
}else{
node->prev = NULL;
node->next = list->head;
list->head->prev = node;
list->head = node;
}
list->len++;
return list;
}


2.4 新建一个值为value的节点,并且置为链表的尾节点

list *listAddNodeTail(list *list,void *value)
{
listNode *node;
if((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value;
if(list->len == 0){
list->head = list->tail = node;
node->prev = node ->next = NULL;
}else{
node->prev = list->tail;    //注意加入一个新节点,先把这个节点设置好,然后再更改原来链表中需要改动的节点值
node->next = NULL;
list->tail->next = node;
list->tail = node;
}
list->len++;
return list;
}


2.5 向以前的old_node节点插入值为value的节点(插入方向根据after决定)

list *listInsertNode(list *list,listNode *old_node,void *value,int after)
{
listNode *node;
if((node = zmalloc(sizeof(*node))) == NULL)
return NULL;
node->value = value;

//after>0指示:插入到旧节点之后
if(after){
node->prev = old_node;
node->next = old_node->next;
//注意特殊情况:当前在尾节点之后插入一个节点
if(list->tail == old_node){
list->tail = node;
}
}else{
node->prev = old_node->prev;
node->next = old_node;
//注意特殊情况:当前在头节点之前插入一个节点
if(list->head == old_node){
list->head = node;
}
}

//更新当前插入节点的前继和后继节点的指针
if(node->prev != NULL){
node->prev->next = node;
}
if(node->next != NULL){
node->next->prev = node;
}

list->len++;
return list;
}

2.6 删除一个特定的节点

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--;
}


//迭代器操作(很精辟)..............................................................................

2.7 返回给定链表的一个迭代器,direction指定迭代的方向

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 = direciton;
return iter;
}
2.8 释放指定的迭代器

void listReleaseIterator(listIter *iter)
{
zfree(iter);
}


2.9 将迭代器重置到表头

void listRewind(list *list,listIter *li)
{
li->next = list->head;   //这里是next指向表头
li->direction = AL_START_HEAD;
}


2.10 将迭代器重置到表尾

void listRewindTail(list *list,listIter *li)
{
li->next = list->tail;       //注意这里是next指向表尾
li->direciton = AL_START_TAIL;
}


2.11 返回迭代器取得的一个节点值

listNode *listNext(listIter *iter)
{
//后面的操作都是针对iter的next指针进行操作的
listNode *current = iter->next;
if(current != NULL){
if(iter->direction == AL_START_HEAD)
iter->next = current->next;
else
iter->next = current->prev;
}
return current;
}


//整个链表的处理过程..............................................................................

2.12 复制整个链表,成功时返回列表的副本,否则返回NULL

list *listDup(list *orig)
{
list *copy;
listIter *iter;
listNode *node;
//创建一个空的链表
if((copy == listCreate()) == NULL)
return NULL;
//给链表赋予对应的数值
copy->dup = orig->dup;
copy->free = orig->free;
copy->match = orig->match;

iter = listGetIterator(orig,AL_START_HEAD);
while((node = listNext(iter)) != NULL){
void *value;
//如果存在自定义的赋值方法,就采用自定义的方法
if(copy->dup){
value = copy->dup(node->value);
if(value == NULL){
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
}else
value = node->value;
//将新加入的节点放到链表的末尾
if(listAddNodeTail(copy,value) == NULL){
listRelease(copy);
listReleaseIterator(iter);
return NULL;
}
}
listReleaseIterator(iter);

return copy;
}
2.13 在链表中查找和key匹配的节点

listNode *listSearchKey(list *list,void *key)
{
listIter *iter;
listNode *node;

iter = listGetIterator(list,AL_START_HEAD);
while((node = listNext(iter)) != NULL){
//使用自定义的匹配器进行匹配
if(list->match){
if(list->match(node->value,key) != NULL){
listReleaseIterator(iter);
return node;
}
}else{
if(key == node->value){
listReleaseIterator(iter);
return node;
}
}
}

//前面代码没有返回(也就是没找到)
listReleaseIterator(iter);
return NULL;
}

2.14 根据给定的索引,返回列表中对应的节点;正数:从0~开始,表头开始移动,负数:从-1~开始,表尾开始移动

listNode *listIndex(list *list,long index)
{
listNode *n;
if(index < 0){
index = (-index)-1;
n = list->tail;
while(index-- && n)  n= n->prev;
}else{
n = list->head;
while(index-- && n)  n = n->next;
}
return n;
}


2.15 将链表尾节点取出插入到头节点的前面

void listRotate(list *list)
{
listNode *tail = list->tail;
//如果链表少于1个元素,直接返回
if(listLength(list) <= 1) return;

//取出之前的尾节点
list->tail = tail->prev;
list->tail->next = NULL;
//将它插入到头节点前面
list->head->prev = tail;
tail->prev = NULL;
tail->next = list->head;
list->head = tail;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: