在上一篇当中我们简单分析了一下简单动态字符串,下面我们来看一下redis另外一种数据结构,双向链表(ADList)。在源码当中的src/adlist.c
以及src/adlist.h
中可以看到这部分的代码,先来看一下adlist的数据结构
可以看到list结构体中有两个listNode链表节点,分别指向的是链表的头结点和尾节点,此外还有三个函数,dup,free以及match分别是对链表节点的值进行复制,释放以及匹配。此外还有len这个成员变量,可以将获取链表长度的时间复杂度从O(N)
变为O(1)
。
我们看下这个结构体当中listNode这个数据结构
可以看到这个链表节点中有分别指向前一个以及后面一个节点的指针,这样就可以保证链表可以进行双向遍历,value存储了每个节点对应的值。链表的基本数据结构示意如下:
在src/adlist.c
当中我们可以看到对于链表的一系列操作的函数,包括创建,释放,插入节点,删除节点等操作,下面就其中几个函数进行分析。
- listRotate
对于一个单向链表而言,对链表进行旋转的操作一般指的是将链表从头到尾的指向顺序变成从尾到头的指向,但是对于ADList来说,这种链表是一个双向链表,不需要上述的这种操作就可以实现从尾到头的遍历,那么这个函数的具体含义是什么呢,我们看下源码。
从代码可以看到这个函数的含义是将尾节点插入到链表的头部,有点循环移位的意思。
- listIndex
这个函数的作用是查找到对应index的节点,我们看下代码。
可以看到这里的index并不只能是非负数,如果index小于0的话查找将会从尾节点开始,并且向头节点进行遍历,如果index=-1的话查找的就是尾节点。如果index>=0那么就从头节点开始向尾部方向进行遍历。
- listEmpty与listRelease
这两个函数的含义分别是对链表的元素进行释放以及对于整个链表的空间进行释放。我们先来看下listEmpty函数,这个函数首先获取链表的长度,在一个while循环当中从链表的头节点开始不断向后遍历,每次释放链表中的每一个元素,一直到链表的长度为0,最后将链表的头节点和尾节点都置为null。但是这个函数并不会对链表本身进行释放,而listRelease函数除了会执行上述的listEmpty之外,还会对于链表本身的空间进行释放。
关于链表的操作比较简单,在src/adlist.c当中都有很清楚的说明,这里只列举了一部分函数进行分析,如果希望看到更多的函数可以去看下源码。
如果对你有帮助,请作者喝一杯牛奶吧