链表的作用

首先我们知道,链表提供了高效的节点重排能力、顺序性的访问方式、灵活的增删节点并调整链表的长度。作为一种常用的数据结构,在很多高级的编程语言里都可以看到。实现的方式大同小异。

与数组的比较

从内存空间来看,数组是一个连续的内存空间属于连续存储存储形式。而链表则是离散存储的存储形式,有一个指针指向一个节点。所以意味着链表在内存中可以是离散的。
就从内存存储方式来看,数组是一个连续的空间,查询更快,更加适合使用序列来访问数组元素。而链表更适对线性表长度无法确定,频繁的插入删除操作的动态性比较强的线性表。下图可见,数组和链表的存储形式。

数组 链表
a other
b a
c other
d b
e other
nil c

节点的定义

首先我们看一下节点的定义。
prev 记录前一个节点的指针
next 记录下一个节点的指针
value 记录节点的阵阵的值
这样如果你知道第一个节点就能完整的把整个链表循环显示出来。
image
其实目前来看整个链表的结构已经出现了,多个listNode通过prev next 就可以连起来行程一个链表。但是redis中的链表还对listNode 进行了一个封装,增加了一些冗余字段来提高访问的性能,跟上一篇文章说的SDS有相似地方。

typedef struct listNode{
    //前置节点
    struct listNode *prev;
    //后置节点
    struct listNode *next;
    //节点的值
    void *value;
}

Redis中的list

在redis中对listNode再次封装了下,使用了一个list。下面我们看下代码:
可以看到跟SDS类似,多了一个表头,表尾,数量和3个函数。
这几个属性能够达到什么效果呢?
这3个函数可以说是对链表最常用的函数,使用起来十分的方便。链表数量作用跟SDS相似,可以用O(1)的复杂度获取整个链表的长度,表头和表尾可以快速的在表头和表尾添加元素。否则如果要在最后添加需要循环整个链表拿到尾节点,改变尾节点的next添加新节点。在redis中使用链表,几乎都是使用list。

typedef struct list{
    //链表头
    listNode *head;
    //链表尾
    listNode *tail;
    //链表数量
    unsigned long len;
    //节点复制韩式布
    vode *(*dup) (void *ptr);
    //节点释放
    vode *(*free) (void *ptr);
    //节点对比
    vode *(*match) (void *ptr,void *key);
}

大二小的宝
222 声望74 粉丝