说明
本篇文章介绍redis的双向链表。redis用很简洁的代码实现了每本数据结构书籍必有的双向链表结构。可以推荐给正在学习数据结构的同学看看这代码
实现
redis使用两个结构体实现了双向链表,即list和listNode。另外还有一个listIter用来实现遍历list每个节点的迭代器
listNode
1 2 3 4 5
| typedef struct listNode { struct listNode *prev; struct listNode *next; void *value; } listNode;
|
- 双向链表节点,只有三个变量,两个指向前后节点的指针,这两个指针就能串起来整个链表,另外还有一个存放value地址的指针
list
1 2 3 4 5 6 7 8 9 10 11
| 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为了提供更强大的接口,实现了三个可以自定义的函数回调,用来实现特殊的需求
- dup: 在listDup中使用,复制链表的时候,如果自定义该函数,则每个listNode的value变量会使用该回调进行复制,如果该函数返回NULL,则会导致整个复制链表过程失败
- free:在listDelNode和listRelease中使用,如果自定义该函数,则释放listNode的时候就会先调用一次该函数以确保正确的可以释放value这个指针
- match:在listSearchKey中使用,如果自定义该函数,则在search过程中,调用该函数进行匹配操作
listIter
1 2 3 4 5 6 7 8 9
| typedef struct listIter { listNode *next; int direction; } listIter;
#define AL_START_HEAD 0 #define AL_START_TAIL 1
|
- 可以通过listGetIterator创建指定list,指定方向的一个迭代器,遍历完之后可以通过listReleaseIterator释放
- 遍历过程中也可以通过listRewind和listRewindTail来重置迭代器状态
- 迭代器可以控制方向(从后往前/从前往后),该方向可以通过宏变量指定
- 迭代器遍历链表的一个简单例子
1 2 3 4
| iter = listGetIterator(list,<direction>); while ((node = listNext(iter)) != NULL) { doSomethingWith(listNodeValue(node)); }
|
函数分析
函数 |
描述 |
时间复杂度 |
listCreate |
创建一个空的链表 |
O(1) |
listRelease |
释放整个list,包括list的各个节点 |
O(N),N为元素个数 |
listAddNodeHead |
增加一个值为value的节点到list的头部 |
O(1) |
listAddNodeTail |
增加一个值为value的节点到list的尾部 |
O(1) |
listInsertNode |
增加一个节点到指定节点的前/后,after表示插入前还是后 |
O(1) |
listDelNode |
删除指定的节点,因为效率问题,没有判断node是否真的是该list的节点 |
O(1) |
listGetIterator |
创建指定list,指定方向的一个迭代器 |
O(1) |
listNext |
获取迭代器的下一个节点 |
O(1) |
listRewind |
重置迭代器为从头往后遍历 |
O(1) |
listRewindTail |
重置迭代器为从后往前遍历 |
O(1) |
listReleaseIterator |
释放迭代器内存 |
O(1) |
listDup |
完整的复制一个链表 |
O(N),N为元素个数 |
listSearchKey |
从list中查找指定节点 |
O(N),N为元素个数 |
listIndex |
返回list中下标为index的节点,index如果为正值,表示从头开始的小标,且下标从0开始,即0为head,如果index为负值,表示从后往前的下标,且下标从-1开始,即-1表示tail |
O(abs(index)) |
listRotate |
顺时针旋转list,将list的tail节点从尾部移除,插入到list头部 |
O(1) |
每个函数及宏的声明及作用,具体细节可以查看我注释的redis源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #define listLength(l) ((l)->len) #define listFirst(l) ((l)->head) #define listLast(l) ((l)->tail) #define listPrevNode(n) ((n)->prev) #define listNextNode(n) ((n)->next) #define listNodeValue(n) ((n)->value)
#define listSetDupMethod(l,m) ((l)->dup = (m)) #define listSetFreeMethod(l,m) ((l)->free = (m)) #define listSetMatchMethod(l,m) ((l)->match = (m))
#define listGetDupMethod(l) ((l)->dup) #define listGetFree(l) ((l)->free) #define listGetMatchMethod(l) ((l)->match)
list *listCreate(void); void listRelease(list *list); list *listAddNodeHead(list *list, void *value); list *listAddNodeTail(list *list, void *value); list *listInsertNode(list *list, listNode *old_node, void *value, int after); void listDelNode(list *list, listNode *node); listIter *listGetIterator(list *list, int direction); listNode *listNext(listIter *iter); void listReleaseIterator(listIter *iter); list *listDup(list *orig); listNode *listSearchKey(list *list, void *key); listNode *listIndex(list *list, long index); void listRewind(list *list, listIter *li); void listRewindTail(list *list, listIter *li); void listRotate(list *list);
|