前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【redis6.0.6】redis源码慢慢学,慢慢看 -- 第五天:adlist

【redis6.0.6】redis源码慢慢学,慢慢看 -- 第五天:adlist

作者头像
看、未来
发布2020-09-10 15:57:50
6160
发布2020-09-10 15:57:50
举报

前言:

先附上人家的版权:

Copyright © 2009 Salvatore Sanfilippo This file is released under the BSD license, see the COPYING file

考试差不多考完了,我又回来了。

今天起,我们就进入到redis的数据结构模块。

其实吧,这些数据结构我们都写过的,不过看看大佬们写的,也是能收获很多东西的。

先来最基础的链表,它这个是双端链表。

第一次写,有点紧张,我也不知道要怎么排版,嗯,多包涵。

头文件

那就先来个头文件吧。

//结构体:
/*
listNode:节点结构体
listIter:迭代器结构体
list:链表结构体

我也不知道为啥要有这么多结构体,我平时吧,也就俩结构体,一个节点信息,一个数据信息,放这里看,就是那个listNode里面了
不急,看到后面的函数实现就知道了。

字面意思我就不注释了啊,看着乱糟糟
*/

typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;	//通用链表
} listNode;

typedef struct listIter {
    listNode *next;	//迭代器当前指向的节点,起了这么个好名字
    int direction;	//可以取以下两个值:AL_START_HEAD和AL_START_TAIL
} listIter;

typedef struct list {
    listNode *head;
    listNode *tail;

	//这种写法应该不陌生吧,总有人吹牛说用结构体实现类的功能,进去一看就是这个,我时间、流量都花了,就给我看这个?
    void *(*dup)(void *ptr);			//复制链表节点保存的值,dup和dup2陌生不?
    void (*free)(void *ptr);	
    int (*match)(void *ptr, void *key);	//比较链表节点所保存的节点值和另一个输入的值是否相等
    unsigned long len;
} list;

//函数宏
#define listLength(l) ((l)->len)	//返回链表l节点数量
#define listFirst(l) ((l)->head)	//后面都懂吧:懂得懂得
#define listLast(l) ((l)->tail)
#define listPrevNode(n) ((n)->prev)
#define listNextNode(n) ((n)->next)
#define listNodeValue(n) ((n)->value)

#define listSetDupMethod(l,m) ((l)->dup = (m))		//设置链表l的复制函数为m方法
#define listSetFreeMethod(l,m) ((l)->free = (m))	
#define listSetMatchMethod(l,m) ((l)->match = (m))	

#define listGetDupMethod(l) ((l)->dup)		//返回链表l的赋值函数
#define listGetFreeMethod(l) ((l)->free)
#define listGetMatchMethod(l) ((l)->match)

/* Prototypes */
list *listCreate(void);
void listRelease(list *list);
void listEmpty(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);	//在list中,根据after在old_node节点前后插入值为value的节点。
void listDelNode(list *list, listNode *node);
listIter *listGetIterator(list *list, int direction);	//为list创建一个迭代器iterator
listNode *listNext(listIter *iter);		//返回迭代器iter指向的当前节点并更新iter
void listReleaseIterator(listIter *iter);	
list *listDup(list *orig);	//拷贝表头为orig的链表并返回
listNode *listSearchKey(list *list, void *key);
listNode *listIndex(list *list, long index);	//返回下标为index的节点地址
void listRewind(list *list, listIter *li);		//将迭代器li重置为list的头结点并且设置为正向迭代
void listRewindTail(list *list, listIter *li);	//将迭代器li重置为list的尾结点并且设置为反向迭代
void listRotateTailToHead(list *list);			//将尾节点插到头结点
void listRotateHeadToTail(list *list);
void listJoin(list *l, list *o);		//把o接在l后面

/* Directions for iterators */
#define AL_START_HEAD 0     //正向迭代:从表头向表尾进行迭代
#define AL_START_TAIL 1     //反向迭代:从表尾到表头进行迭代

源文件

关于空间配置器的问题,在这里:【redis6.0.6】redis源码慢慢学,慢慢看 – 第二天:空间配置(zmalloc)

list *listCreate(void);

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

看这个没什么问题吧,大家都这么写。


void listEmpty(list *list);

清空链表,但是不删掉

void listEmpty(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); //如果设置了list结构的释放函数,则调用该函数释放节点值
        zfree(current);
        current = next;
    }
    list->head = list->tail = NULL;
    list->len = 0;
}

void listRelease(list *list);

想了想,还是“斩草除根”吧。

void listRelease(list *list)    //释放list表头和链表
{
	listEmpty(list);
    zfree(list);
}

list *listAddNodeHead(list *list, void *value);

list *listAddNodeHead(list *list, void *value)  //将value添加到list链表的头部
{
    listNode *node;

    if ((node = zmalloc(sizeof(*node))) == NULL)    //为新节点分配空间
        return NULL;
    node->value = value;    //设置node的value值

    if (list->len == 0) {   //将node头插到空链表
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {                //将node头插到非空链表
        node->prev = NULL;
        node->next = list->head;
        list->head->prev = node;
        list->head = node;
    }

    list->len++;    //链表元素计数器加1

    return list;
}

没什么好说的啊


list *listAddNodeTail(list *list, void *value);

list *listAddNodeTail(list *list, void *value)  //将value添加到list链表的尾部
{
    listNode *node;

    if ((node = zmalloc(sizeof(*node))) == NULL)    //为新节点分配空间
        return NULL;
    node->value = value;    //设置node的value值
    if (list->len == 0) {   //将node尾插到空链表
        list->head = list->tail = node;
        node->prev = node->next = NULL;
    } else {                //将node头插到非空链表
        node->prev = list->tail;
        node->next = NULL;
        list->tail->next = node;
        list->tail = node;
    }
    list->len++;    //更新链表节点计数器

    return list;
}

list *listInsertNode(list *list, listNode *old_node, void *value, int after);

list *listInsertNode(list *list, listNode *old_node, void *value, int after)    //在list中,根据after在old_node节点前后插入值为value的节点。
{
    listNode *node;

    if ((node = zmalloc(sizeof(*node))) == NULL) //为新节点分配空间
        return NULL;
    node->value = value;    //设置node的value值

    if (after) {    //after 非零,则将节点插入到old_node的后面
        node->prev = old_node;
        node->next = old_node->next;
        if (list->tail == old_node) {   //目标节点如果是链表的尾节点,更新list的tail指针
            list->tail = node;
        }
    } else {        //after 为零,则将节点插入到old_node的前面
        node->next = old_node;
        node->prev = old_node->prev;
        if (list->head == old_node) {   //如果节点如果是链表的头节点,更新list的head指针
            list->head = node;
        }
    }
    if (node->prev != NULL) {   //如果有,则更新node的前驱节点的指针
        node->prev->next = node;
    }
    if (node->next != NULL) {   //如果有,则更新node的后继节点的指针
        node->next->prev = node;
    }
    list->len++;    //更新链表节点计数器
    return list;
}

void listDelNode(list *list, listNode *node);

void listDelNode(list *list, listNode *node)    //从list删除node节点
{
    if (node->prev) //更新node的前驱节点的指针
        node->prev->next = node->next;
    else
        list->head = node->next;
    if (node->next) //更新node的后继节点的指针
        node->next->prev = node->prev;
    else
        list->tail = node->prev;

    if (list->free) list->free(node->value);    //如果设置了list结构的释放函数,则调用该函数释放节点值
    zfree(node);    //释放节点
    list->len--;    //更新链表节点计数器
}

咱也不知道该说点啥,咱自个儿也是这么写的。


listIter *listGetIterator(list *list, int direction);

listIter *listGetIterator(list *list, int direction)    //为list创建一个迭代器iterator
{
    listIter *iter;

    if ((iter = zmalloc(sizeof(*iter))) == NULL) return NULL;   //为迭代器申请空间
    if (direction == AL_START_HEAD)     //设置迭代指针的起始位置
        iter->next = list->head;
    else
        iter->next = list->tail;
    iter->direction = direction;        //设置迭代方向
    return iter;
}

listNode *listNext(listIter *iter);

listNode *listNext(listIter *iter)  //返回迭代器iter指向的当前节点并更新iter
{
    listNode *current = iter->next; //备份当前迭代器指向的节点

    if (current != NULL) {
        if (iter->direction == AL_START_HEAD)   //根据迭代方向更新迭代指针
            iter->next = current->next;
        else
            iter->next = current->prev;
    }
    return current;     //返回备份的当前节点地址
}

void listReleaseIterator(listIter *iter);

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

void listRewind(list *list, listIter *li);

void listRewind(list *list, listIter *li) {
    li->next = list->head;
    li->direction = AL_START_HEAD;
}

void listRewindTail(list *list, listIter *li);

void listRewindTail(list *list, listIter *li) {
    li->next = list->tail;
    li->direction = AL_START_TAIL;
}

list *listDup(list *orig); //拷贝表头为orig的链表并返回

内啥,看一下人家的注释吧,虽然是英文,但是不难看懂。

/* Duplicate the whole list. On out of memory NULL is returned.
 * On success a copy of the original list is returned.
 *
 * The 'Dup' method set with listSetDupMethod() function is used
 * to copy the node value. Otherwise the same pointer value of
 * the original node is used as value of the copied node.
 *
 * The original list both on success or error is never modified. */
list *listDup(list *orig)   //拷贝表头为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;
    //迭代整个orig的链表
    listRewind(orig, &iter);    //为orig定义一个迭代器并设置迭代方向
    while((node = listNext(&iter)) != NULL) {    //迭代器根据迭代方向不停迭代
        void *value;

        //复制节点值到新节点
        if (copy->dup) {
            value = copy->dup(node->value); //如果定义了list结构中的dup指针,则使用该方法拷贝节点值。
            if (value == NULL) {
                listRelease(copy);
                return NULL;
            }
        } else
            value = node->value;    //获得当前node的value值

        if (listAddNodeTail(copy, value) == NULL) { //将node节点尾插到copy表头的链表中
            listRelease(copy);
            return NULL;
        }
    }
    return copy;    //返回拷贝副本
}

改版之后,把迭代器变成了变量,不再是指针。


listNode *listSearchKey(list *list, void *key);

listNode *listSearchKey(list *list, void *key)  //在list中查找value为key的节点并返回
{
    listIter iter;
    listNode *node;

    listRewind(list, &iter);    //创建迭代器
    while((node = listNext(&iter)) != NULL) {        //迭代整个链表
        if (list->match) {                          //如果设置list结构中的match方法,则用该方法比较
            if (list->match(node->value, key)) {
                return node;
            }
        } else {
            if (key == node->value) {
                return node;
            }
        }
    }
    return NULL;
}

listNode *listIndex(list *list, long index);

listNode *listIndex(list *list, long index) {   //返回下标为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;
}

void listRotateTailToHead(list *list);

void listRotateTailToHead(list *list) {       //将尾节点插到头结点

    if (listLength(list) <= 1) return;  //只有一个节点或空链表直接返回

    listNode *tail = list->tail;
    
    /* Detach current tail */
    list->tail = tail->prev;        //取出尾节点,更新list的tail指针
    list->tail->next = NULL;
    /* Move it as head */
    list->head->prev = tail;        //将节点插到表头,更新list的head指针
    tail->prev = NULL;
    tail->next = list->head;
    list->head = tail;
}

void listRotateHeadToTail(list *list);

void listRotateHeadToTail(list *list) {
    if (listLength(list) <= 1) return;

    listNode *head = list->head;
    /* Detach current head */
    list->head = head->next;
    list->head->prev = NULL;
    /* Move it as tail */
    list->tail->next = head;
    head->next = NULL;
    head->prev = list->tail;
    list->tail = head;
}

void listJoin(list *l, list *o);

/* Add all the elements of the list 'o' at the end of the
 * list 'l'. The list 'other' remains empty but otherwise valid. */
void listJoin(list *l, list *o) {
    if (o->head)
        o->head->prev = l->tail;

    if (l->tail)
        l->tail->next = o->head;
    else
        l->head = o->head;

    if (o->tail) l->tail = o->tail;
    l->len += o->len;

    /* Setup other as an empty list. */
    o->head = o->tail = NULL;
    o->len = 0;
}

整体感觉

挺好,大家都可以写这个数据结构。

不过嘛,写的也不容易,咱分析的也不容易。

建议收藏,不然刷着刷着就可能找不到了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 头文件
  • 源文件
    • list *listCreate(void);
      • void listEmpty(list *list);
        • 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);
                • void listDelNode(list *list, listNode *node);
                  • listIter *listGetIterator(list *list, int direction);
                    • listNode *listNext(listIter *iter);
                      • void listReleaseIterator(listIter *iter);
                        • void listRewind(list *list, listIter *li);
                          • void listRewindTail(list *list, listIter *li);
                            • list *listDup(list *orig); //拷贝表头为orig的链表并返回
                              • listNode *listSearchKey(list *list, void *key);
                                • listNode *listIndex(list *list, long index);
                                  • void listRotateTailToHead(list *list);
                                    • void listRotateHeadToTail(list *list);
                                      • void listJoin(list *l, list *o);
                                      • 整体感觉
                                      相关产品与服务
                                      云数据库 Redis
                                      腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                                      领券
                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档