redis中zSet排序原理----skipList跳跃表

skiplist简介

skip List是一种随机化的数据结构,基于并联的链表,实现简单,插入、删除、查找的复杂度均为O(logN)(大多数状况下),由于其性能匹敌红黑树且实现较为简单,所以在不少著名项目都用跳表来代替红黑树,例如LevelDB、Reddis的底层存储结构就是用的SkipList。segmentfault

目前经常使用的key-value数据结构有三种:Hash表、红黑树、SkipList,它们各自有着不一样的优缺点:
Hash表:插入、查找最快,为O(1);如使用链表实现则可实现无锁;数据有序化须要显式的排序操做。
红黑树:插入、查找为O(logn),但常数项较小;无锁实现的复杂性很高,通常须要加锁;数据自然有序。
SkipList:插入、查找为O(logn),但常数项比红黑树要大;底层结构为链表,可无锁实现;数据自然有序。数组

SkipList基本数据结构及其实现

一个跳表,应该具备如下特征:数据结构

一、一个跳表应该有几个层(level)组成;
一般是10-20层,leveldb中默认为12层。并发

二、跳表的第0层包含全部的元素;
且节点值是有序的。性能

三、每一层都是一个有序的链表;
层数越高应越稀疏,这样在高层次中能'跳过’许多的不符合条件的数据。spa

四、若是元素x出如今第i层,则全部比i小的层都包含x;线程

五、每一个节点包含key及其对应的value和一个指向该节点第n层的下个节点的指针数组
x->next[level]表示第level层的x的下一个节点指针

skiplist的查询过程

查询的第一个比vx大的节点的前一个值,看是否相等。相等则存在,不然查找下一层,直到层数为0。blog

以已有数据1三、2二、7五、80、99为例排序

clipboard.png

从最高层(此处为2)开始

一、level2找到结点Node75小于80,且level2.Node75->next 大于80,则进入level1查找(此处已经跳过了13~75中间的结点(22),

二、level1.Node75 < 80 < level1.Node75->next,进入level0

三、level0.Node75->next 等于80,找到结点

skiplist的插入过程

假设插入一新键值key,值为84,level为当前层

clipboard.png

一、从最高层开始找到每一层比84大的节点的前一个值,存入prev[level]。

这里

prev[2] = leve2.Node75

prev[1] = leve1.Node75

prev[0] = level0.Node80

二、初始化一个新的节点84
三、为x随机选择一个高度h,这里选2
四、x->next[0..h-1] = prev[0..h-1]->next
五、prev[0..h-1]->next[0..h-1] = x

(步骤四、5为链表插入结点的操做)

skiplist删除操做

删除操做相似于插入操做,包含以下3步:一、查找到须要删除的结点 二、删除结点 三、调整指针

总结

若是要实现一个key-value结构,需求的功能有插入、查找、迭代、修改,那么首先Hash表就不是很适合了,由于迭代的时间复杂度比较高;而红黑树的插入极可能会涉及多个结点的旋转、变色操做,所以须要在外层加锁,这无形中下降了它可能的并发度。而SkipList底层是用链表实现的,能够实现为lock free,同时它还有着不错的性能(单线程下只比红黑树略慢),很是适合用来实现咱们需求的那种key-value结构。

相关文章
相关标签/搜索