zoukankan      html  css  js  c++  java
  • redis源码学习之adlist

    参考《Redis 设计与实现》 (基于redis3.0.0) 作者:黄健宏
    学习redis3.2.13

    TOC

    介绍

    链表简单了解:

    • 链表是一种线性结构,由很多节点串联在一起,每个节点间由指针连接。
    • 每个节点含存储数据部分与指向下一个节点的部分。
    • 链表的节点可动态增减,增减头尾节点时间复杂度为O(1)。非常适合数据量预先难以知晓或变化频繁的情况。

    注:增减头尾节点时间复杂度为O(1)的前提是,拥有头结点的同时拥有尾节点指针
    C语言没有链表这种数据结构,redis造了属于它自己的链表

    链表结构

    节点定义

    typedef struct listNode {
        //指向前一个节点
        struct listNode *prev;
        //指向后一个节点
        struct listNode *next;
        //指向存储的值
        void *value;
    } listNode;

    根据节点的结构可知redis中的链表为双向链表,取书中的例子如图:

    管理结构定义

    typedef struct list {
        //头节点指针
        listNode *head;
        //尾节点指针
        listNode *tail;
        //自定义dup函数指针,用于节点存储值的深拷贝
        void *(*dup)(void *ptr);
        //自定义free函数指针,用于节点存储值的释放
        void (*free)(void *ptr);
        //自定义match函数指针,用于检查节点存储值是否与key匹配
        int (*match)(void *ptr, void *key);
        //节点长度
        unsigned long len;
    } list;

    还是取书中的已有例子,redis链表结构直观描述如下:

    节点中的数据域是void *类型,配合管理结构中的函数指针,这使得其支持任意数据的存储

    迭代器

    redis的list实现了自己的迭代器,list的遍历由迭代器的来提供,使遍历操作得以简化
    迭代器结构定义如下

    typedef struct listIter {
        //指向的节点
        listNode *next;
        //迭代方向
        int direction;
    } listIter;
    //迭代方向定义如下
    #define AL_START_HEAD 0
    #define AL_START_TAIL 1

    迭代器的获取

    //获取链表指定迭代方向的迭代器
    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;
    }

    使用迭代器遍历

        ...
        #define listNodeValue(n) ((n)->value)
        ...
        listIter *iter = listGetIterator(list,<direction>);
        while ((node = listNext(iter)) != NULL) {
        //   doSomethingWith(listNodeValue(node));    
         }

    后记

    • 通过void *类型存储数据,函数指针存储处理数据的对应方法,以回调的方式执行,可增加容器的灵活性
    • 使用迭代器可以简化遍历操作




    原创不易,转载请注明出处,谢谢
  • 相关阅读:
    MVC中权限管理
    ElasticSearch作为Windows服务启动
    linux下mysql常用的一些命令
    用Markdown写博客
    JAVA设计模式——简单工厂
    JAVA设计模式——单例模式
    JAVA设计模式——开篇
    Centos7.3安装和配置Mysql5.7
    java开发环境配置——IDEA SVN的使用
    java开发环境配置——IntelliJ IDEA
  • 原文地址:https://www.cnblogs.com/Keeping-Fit/p/14088118.html
Copyright © 2011-2022 走看看