redis源码-----链表

Posted king哥Java架构

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了redis源码-----链表相关的知识,希望对你有一定的参考价值。

链表提供了高效的节点重排能力,以及顺序性节点访问方式,并且可以通过增删节点来灵活的调整链表的长度。redis使用的C语言中并没有内置这种数据结构,redis构建了自己的链表实现。当一个列表键包含了数量比较多的元素,又或者列表中包含的元素都是比较长的字符串时候,redis就会使用链表作为列表键的底层实现。

节点的结构

typedef struct listNode {
  struct listNode *prev; 
  struct listNode *next;
  void *value; } listNode;

多个listNode通过prev和next两个指针构成一个双向链表。

typedef struct list {
     //头节点
    listNode *head;
    //尾节点
    listNode *tail;
    //节点复制函数
    void *(*dup)(void *ptr);
    //节点释放函数
    void (*free)(void *ptr);
    //节点比较函数
    int (*match)(void *ptr, void *key);
    //节点长度
    unsigned long len;
} list;

redis中链表特性总结

  • 双端:链表节点都带有两个指针,prev和next,这样获取一个节点的前置和后置节点的时间复杂度都是O(1)。
  • 无环:表头的prev指针和表尾的next指针都只想NULL,对链表的访问以NULL为终点。
  • 带有表头节点和表尾节点的指针:获取表头和表尾节点的复杂度是O(1)。
  • 带有长度计数器:方便获取链表的长度复杂度为O(1)。
  • 多态:链表节点使用void*指针来保存节点值,可以用于宝顿各种不同类型的值。

如果你觉得自己学习效率低,缺乏正确的指导,可以加入资源丰富,学习氛围浓厚的技术圈一起学习交流吧!
[Java架构群]
群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的JAVA交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

源码分析start

创建一个不包含任何节点的链表:listCreate

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

将所有节点都置空,不会毁掉这个list:listEmpty

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

    current = list->head;
    len = list->len;
    //循环去利用当前list的free函数去释放节点
    while(len--) {
        next = current->next;
        if (list->free) list->free(current->value);
        zfree(current);
        current = next;
    }
    list->head = list->tail = NULL;
    list->len = 0;
}

利用迭代器去遍历list:

//listIter是指针加上方向
typedef struct listIter {
    listNode *next;
    int direction;
} listIter;

listNode *listNext(listIter *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;
}

链表的复制:

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;
    listRewind(orig, &iter);
    while((node = listNext(&iter)) != NULL) {
        void *value;

        if (copy->dup) {
            value = copy->dup(node->value);
            if (value == NULL) {
                listRelease(copy);
                return NULL;
            }
        } else
            value = node->value;
        if (listAddNodeTail(copy, value) == NULL) {
            listRelease(copy);
            return NULL;
        }
    }
    return copy;
}

链表的查询:listSearchKey

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

    listRewind(list, &iter);
    while((node = listNext(&iter)) != NULL) {
        //如果设定了比较函数,就用设定的函数进行比较。否则就是直接比较指针
        if (list->match) {
            if (list->match(node->value, key)) {
                return node;
            }
        } else {
            if (key == node->value) {
                return node;
            }
        }
    }
    return NULL;
}

删除节点:listDelNode

void listDelNode(list *list, listNode *node)
{
    //如果不是头节点
    if (node->prev)
        //当前节点的prev节点的next指向当前节点的next节点
        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);
    //当前列表长度减1
    list->len--;
}

头节点尾节点互换:listRotate

void listRotate(list *list) {
    listNode *tail = list->tail;

    if (listLength(list) <= 1) return;

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

列表的连接:listJoin

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

最后

给大家分享一篇一线开发大牛整理的java高并发核心编程神仙文档,里面主要包含的知识点有:多线程、线程池、内置锁、JMM、CAS、JUC、高并发设计模式、Java异步回调、CompletableFuture类等。

文档地址:一篇神文就把java多线程,锁,JMM,JUC和高并发设计模式讲明白了

码字不易,如果觉得本篇文章对你有用的话,请给我一键三连!关注作者,后续会有更多的干货分享,请持续关注!

以上是关于redis源码-----链表的主要内容,如果未能解决你的问题,请参考以下文章

redis源码-----链表

Redis源码解析——双向链表

redis 5.0.7 源码阅读——双向链表

redis源码学习redis 专属“链表”:ziplist

redis源码学习redis 专属“链表”:ziplist

Redis源码剖析--双端链表Sdlist