链表的使用十分广泛,甚至很多高级编程语言都内置了这种数据结构。但是C语言却不没有。不过C语言编写的Redis却自己构建了链表这种数据结构在自己内部。
127.0.0.1:6379> LPUSH list a b c d e //向链表中添加a b c d e f
(integer) 5 //此时链表中的数据个数
127.0.0.1:6379> RPUSH list f g //在向链表中添加 f g (在a b c d e f 后添加)
(integer) 7
127.0.0.1:6379> LRANGE list 0 -1 //输出链表中所有数据
1) "e"
2) "d"
3) "c"
4) "b"
5) "a"
6) "f"
7) "g"
127.0.0.1:6379>
注:Redis列表是简单的字符串列表,按照插入顺序排序。添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
L RANGE返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
更多Redis的LIST操作可以在API中查看也可通过菜鸟网站快速掌握一些常用的操作指令。
一,Redis中对于链表的使用
Redis中很多地方都用到了链表这一数据结构:链表键,发布和订阅,慢查询,监视器等功能。Redis服务器也使用链表来保存多个客户端的状态信息和构建客户端输出缓冲区。
二,链表和链表节点的实现源代码
每个链表节点使用一个adlist.h/listNode结构来实现
typedef struct listNode{
//前置节点(前驱)
struct listNode *prev;
//后置节点(后继)
struct listNode *next;
//节点的值
void *value;
}listNode;
通过前驱和后继就可以将一个个链表节点连起来组成链表了。
Redis也提供了另外一种形式的链表结构adlist.h/list
typedef struct list{
//表头节点
listNode *head;
//表尾节点
listNode *tail;
//链表所包含的节点数量
unsigned long len;
//节点值复制函数
void *(*dup)(void *ptr);
//节点值释放函数
void (*free)(void *ptr);
//节点值对比函数
int (*match)(void *ptr,void *key);
}list;
这样的list函数为链表提供了头指针head,尾指针tail,记录长度的len。还有操作函数dup,free,match.
dup函数:用于复制链表节点所保存的值。
free函数:用于释放节点保存的值
match函数:用于对比链表节点所保存的值和另一个值是否相等。
三,Redis链表的特性
1,双端:listNode有前驱(prev)和后继(next)指针,因此可以获取某个节点的前驱节点后后继节点。复杂度为O(1)。
2,无环:表头节点无前驱节点(表头的prev指针指向null),表尾节点无后继节点(表尾的next指针指向null)。
3,多态:链表节点可以使用void*指针来保存节点值,并且可以通过list结构中的dup,free,match三个属性为节点值设置类型特定的函数,所以链表可以用于保存各种不同类型的值。
4,节点计数器:可以方便的获得list中节点的数量。复杂度为O(1)。
5,头结点(head)和尾结点(tail):头结点和尾节点的使用可以方便的获得链表的头结点和尾结点。时间复杂度为O(1)。