跳跃表

跳跃表(skiplist)是一种有序数据结构,通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目标

跳跃表支持O(logN),O(N)复杂度的节点查找,还可以通过顺序性的操作来大量处理节点,跳跃表的效率可以和平衡树进行相媲美

Redis使用跳跃表作为有序集合键的底层实现之一,如果一个有序集合中包含的元素比较多,或者有序集合中的元素的成员是比较长的字符串的时候,Redis就会使用跳跃表作为有序集合键的底层实现

Redis中使用跳跃表:

  1. 实现有序集合
  2. 集群节点中用作内部数据结构

跳跃表实现

zskiplistNode结构用于表示跳跃表节点
zskiplist结构用于表示跳跃表节点相关信息

一个跳跃表

header:指向跳跃表的表头节点
tail:指向跳跃表的表尾节点
level:记录目前跳跃表内,层数最大的那个节点的层数(表头节点的层数不计算在内)
length:记录跳跃表的长度,就是节点的个数(表头节点不计算在内)
level(层):L1,L2,L3,表示每个节点的各个层,每层有两个属性:前进指针和跨度,前进指针用于表示位于表尾方向的其他节点,跨度记录了前进指针所指向节点和当前节点的距离,上图,箭头表示前进指针,数字表示跨度,当程序从表头向表尾遍历的时候,访问会沿着层的前进指针进行
backward(后退指针):BW表示节点的后退指针,指向位于当前节点的前一个节点,后退指针在程序从表尾向表头遍历的时候使用
score(分值):1.0,2.0,3.0表示节点所保存的分值,跳跃表中按分值大小从小到大排序
obj(成员对象):O1,O2,O3就是节点所保存的成员对象

表头节点也有后退指针,分值,成员对象,不过表头节点的这些属性用不到,省略了,只显示了表头节点的各个层

跳跃表节点

typedef struct zskiplistNode{
  //层
  struct zskiplistLevel{
    //前进指针
    struct zskiplistNode *forward;
    //跨度
    unsigned int span;
  }level[];
  //后退指针
  struct zskiplistNode *backward;
  //分值
  double score;
  //成员对象
  robj *obj;
}zskiplistNode;  

层(level):程序通过这些层可以加快访问其他节点的速度,一般,层的数量越多,访问其他节点的速度越快
创建一个新节点的时候,程序根据幂次定律随机生成一个1到32之间的数作为level数组的大小

前进指针:用于从表头向表尾方向访问节点,可以用来遍历跳跃表中所有节点

跨度:用于记录两个节点之间的距离

  1. 两个节点跨度越大,离得越远
  2. 指向NULL的所有前进指针的跨度为0

跨度和遍历操作无关,是用来计算排位的

排位:在查找某个节点的过程中,将沿途访问过的所有层的跨度累加起来,得到的结果就是目标节点在跳跃表中的排位

后退指针:用于从表尾向表头方向访问节点,每次只能后退到前一个节点

分值和成员:所有节点都按分值从小到大排序,obj是一个指针,指向一个字符串对象,字符串对象保存一个SDS值,各个节点保存的成员对象必须唯一,但多个节点的分值可以相同,相同分值的,按obj在字典中的排序,从小到大排序

跳跃表

通过使用一个zskiplist来维持这些节点,程序可以更方便的对整个跳跃表进行处理,快速访问表头节点和表尾节点,快速获取跳跃表节点的数量

typedef struct zskiplsit{
  //表头节点和表尾节点
  struct zskiplistNode *header,*tail;
  //节点数量
  unsigned long length;
  //层数最大节点的层数
  int level;
}zskiplist;

跳跃表API

函数 作用 时间复杂度
zslCreate 创建一个 新的跳跃表 O(1)
zslFree 释放给定跳跃表,以及表中包含的所有节点 O(N),N是跳跃表长度
zslInsert 将包含给定成员和分值的新节点添加到跳跃表中 O(logN),最坏O(N),N为表长
zslDelete 删除跳跃表中包含给定成员和分值的节点 O(logN),最坏为O(N)
zslGetRank 返回包含给定成员和分值的节点在跳跃表中的排位 O(logN),最坏O(N)
zslGetElementByRank 返回跳跃表在给定排位上的节点 O(logN),最最坏O(N)
zslIsInRange 给定一个分值范围,如果跳跃表中有至少一个节点的分值在这个范围之内,返回1,否则返回0 通过表头和表尾节点可以检测O(1)
zslFirstInRange 给定一个分值范围,返回跳跃表中第一个符合这个范围的节点 O(logN),最坏O(N)
zslLastInRange 给定一个分值范围,返回跳跃表中最后一个符合这个范围的节点 O(logN),最坏O(N)
zalDeleteRangeByScore 给定一个分值范围,删除 跳跃表中所有在这个范围内的节点 O(N),N是删除节点的数量
zslDeleteRangeByRank 给定一个排位范围,删除所有在这个范围内的节点 O(N)
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容