美文网首页
Redis 双端链表

Redis 双端链表

作者: wayyyy | 来源:发表于2022-09-13 00:27 被阅读0次

链表在redis中使用非常广泛,比如列表键的底层实现之一就是链表。
当一个列表键包含了数量比较多的元素,又或者列表中包含的元素都是比较长的字符串时,redis就会使用链表最为列表键的底层实现。

链表节点数据结构
//  双端链表节点
typedef struct listNode { 
    struct listNode* prev;  // 前置节点
    struct listNode* next;  // 后置节点
    void* value;            // 节点的值
} listNode;
image.png
双端链表数据结构
// 双端链表结构
typedef struct list {
    listNode* head;
    listNode* tail;
    unsigned long len;
    void* (*dup)(void* ptr)     // 节点值复制函数
    void* (*free)(void* ptr)    // 节点值释放函数
    void* (*match)(void* ptr)   // 节点值对比函数
}

// 双端链表迭代器
typedef struct listIter {
    listNode *next;  // 当前迭代到的节点
    int direction;   // 迭代的方向
} listIter;
image.png
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;
}
image.png
listAddNodeHead

头插法

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;
}
image.png
listAddNodeTail
listInsertNode
listDelNode
迭代器
/*
 * AL_START_HEAD :从表头向表尾迭代
 *  AL_START_TAIL :从表尾想表头迭代
 */
listIter *listGetIterator(list *list, int direction)
{
    // 为迭代器分配内存
    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 *current = iter->next;

    if (current != NULL) {
        // 根据方向选择下一个节点
        if (iter->direction == AL_START_HEAD)
            // 保存下一个节点,防止当前节点被删除而造成指针丢失
            iter->next = current->next;
        else
            // 保存下一个节点,防止当前节点被删除而造成指针丢失
            iter->next = current->prev;
    }

    return current;
}
listSearchKey
listIndex
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;
}

特性总结

Redis的链表实现的特性可总结如下:

  • 双端
    获取某个节点的前置节点和后置节点的复杂度都是O(1)。
  • 无环
    以NULL为终点
  • 带表头指针和表尾指针
    获取表头和表尾节点的复杂度为O(1)。
  • 带链表长度计数器
    获取链表长度的复杂度为O(1)。
  • 多态
    链表节点使用void*指针来保存节点值,并且可以通过list结构的三个属性节点值来设置类型特定函数,所以可用来保存不同类型的值。

相关文章

  • redis 源码见闻录(二)

    双端链表 双端链表是redis list类型的实现之一,另一种是压缩列表。因为双端链表占的内存比较高,一般都是优先...

  • redis数据结构--链表

    首先,给出redis中链表节点的定义: 可以看出,这里的链表是双端链表。下面是链表的定义:

  • Redis双端链表

    本文摘抄自redis源码学习笔记 双端链表在Redis中的地位:它作为一种通用数据结构,在Redis的内部使用非常...

  • Redis 双端链表

    链表在redis中使用非常广泛,比如列表键的底层实现之一就是链表。当一个列表键包含了数量比较多的元素,又或者列表中...

  • 链表

    一个链表节点的结构 链表 Redis的链表 双端:链表节点带有prev和next指针,获得节点的前置或后置节点复杂...

  • Redis底层数据结构之双端链表

    前言 Redis的双端链表是基于双向链表实现的,但传统双向链表存在一些问题,比如获取链表长度需要遍历整个链表,时间...

  • 链表

    链表数据结构 Redis的链表实现是双端链表,每个链表节点由一个listNode结构来表示,每个节点都有一个指向前...

  • redis 笔记(双端链表)

    实现 Redis 的列表类型 双端链表还是 Redis 列表类型的底层实现之一, 当对列表类型的键进行操作 —— ...

  • redis双向链表实现(3)

    链表(list)是Redis中最基本的数据结构, 由adlist.h和adlist.c定义事务模块使用双端链表依序...

  • redis底层数据组织方式

    底层数据结构 redis底层数据结构有:字典、双端链表、压缩链表、整数集合、跳跃表和字典、整数集合、embstr ...

网友评论

      本文标题:Redis 双端链表

      本文链接:https://www.haomeiwen.com/subject/ilqvihtx.html