Redis是一个开源的、基于内存的、支持多种数据结构的键值型数据库。其中,有序集合(sorted set)是一种常用的数据结构,它可以存储一组带有分数(score)的成员(member),并按照分数从小到大排序。有序集合在很多场景下都很有用,比如排行榜、延时队列、时间轴等。
那么,Redis是如何实现有序集合的呢?答案是使用了一种叫做跳表(skiplist)的数据结构。跳表是一种基于链表的、支持快速查找、插入和删除的数据结构。它的主要思想是在链表的基础上,增加了多级索引,每级索引都是一个指向链表节点的指针数组,每个指针都指向下一个节点或者NULL。每级索引的指针数量都是随机生成的,遵循一定的概率分布,通常是指数分布或者几何分布。这样,每级索引都可以看作是原链表的一个子集,越高级的索引包含的指针越少,但是跨越的节点越多。通过这种方式,跳表可以在O(log n)的时间复杂度内完成查找、插入和删除操作。
接下来,我们来看看Redis中跳表的源码实现。首先,我们需要定义跳表节点和跳表结构体:
// 跳表节点
// 成员对象
// 后退指针
// 前进指针
// 表头节点和表尾节点
// 表中节点的数量
// 表中层数最大的节点的层数
从上面的代码可以看出,跳表节点包含了分数、成员对象、后退指针和一个可变长度的层数组。每个层包含了前进指针和跨度。前进指针指向当前层下一个节点,跨度表示当前节点和下一个节点之间的间隔。后退指针指向前一个节点,方便从后向前遍历。跳表结构体包含了表头节点、表尾节点、表中节点数量和最大层数。
接着,我们需要定义一些常量和辅助函数:
// 最大层数
// 平均每两个节点出现一个更高层节点的概率
// 返回一个介于1和ZSKIPLIST_MAXLEVEL之间的随机值,作为节点的层数。
// 根据幂次定律,越大的值出现概率越小。