首页
学习
活动
专区
圈层
工具
发布
    • 综合排序
    • 最热优先
    • 最新优先
    时间不限
  • 来自专栏阿伟的个人博客

    跳表

    增加了向前指针的链表叫作跳表跳表全称叫做跳跃表,简称跳表跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。 跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。(来自百度百科) 其的一次增删改查的平均时间复杂度均为O(logN)。 跳表结点的数据结构如下: class Skiplist { public static class Node { int val; List<Node> next 还是以该跳表为例,若我们待删除的元素为3。 第四层,当前结点的下一个位置是5,不为3,下移 第三层,当前结点的下一个位置是5,不为3,下移 第二层,当前结点的下一个位置是3,删除其下一个位置,下移 第一层,当前结点的下一个位置为2小于三,右移,当前位置的下一个元素为

    53930发布于 2020-08-12
  • 来自专栏机械之心

    跳表

    # 跳表的时间复杂度 在一个具有多级索引的跳表中,第一级索引的结点个数大约就是 n/2 ,第二级索引的结点个数大约就是 n/4 ,第三级索引的结点个数大约就是 n/8 ,依次类推,也就是说,第 k 级索引的结点个数是第 k-1 级索引的结点个数的 1/2 ,那第 k 级索引结点的个数就是 n/(2k) 。 假设原始链表大小为 n,那第一级索引大约有 n/2 个结点,第二级索引大约有 n/4 个结点,以此类推,每上升一级就减少一半,直到剩下 2 个结点。 索引节点数 = n/2 + n/4 + n/8 … + 8 + 4 + 2 = n-2 所以,跳表的空间复杂度是 O(n) 。 跳表的存储空间其实还有压缩空间。 # 跳表索引动态更新 当我们不停地往跳表中插入数据时,如果我们不更新索引,就有可能出现某 2 个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。

    50620编辑于 2023-04-07
  • 来自专栏程序猿~

    跳表 - skipList

    简介 SkipList(跳表)这种数据结构是由William Pugh于1990年在在 Communications of the ACM June 1990, 33(6) 668-676 发表了Skip SkipList还有一个优势就是实现简单,SkipList的实现只花了2个小时,而红黑树,我可能得2天。 Redis Redis当中的Sorted-set这种有序的集合,正是对于跳表的改进和应用。 new Node(Integer.MAX_VALUE); p1.right=p2; p2.left=p1; p1.down=head; head.up =p1; p2.down=tail; tail.up=p2; head=p1; tail=p2; } //删除结点

    63030发布于 2020-08-27
  • 来自专栏C/C++、数据结构、算法

    DS高阶:跳表

    但是这个结构在插入删除数据的时候有很大的问题,插入或者删除一个节点之后,就会打乱上下相邻两层链表上节点个数严格的2:1的对应关系。 一般跳表会设计一个最大层数maxLevel的限制,其次会设置一个多增加一层的概率p。 那么计算这个随机层数的伪代码如下图: 一个节点的平均层数(也即包含的平均指针数目),计算如下: 现在很容易计算出: 当p=1/2时,每个节点所包含的平均指针数目为2; 当p=1/4时,每个节点所包含的平均指针数目为 时间复杂度:logN 具体的分析可以看下面的文章:Redis内部数据结构详解(6)——skiplist 2、skiplist的模拟实现 力扣有一道设计跳表的题. - 力扣(LeetCode)设计跳表 平衡树节点存储每个值有三叉链,平衡因子/颜色等消耗skiplist中p=1/2时,每个节点所包含的平均指针数目为2;skiplist中p=1/4时,每个节点所包含的平均指针数目为1.33; 2. skiplist

    28500编辑于 2024-05-26
  • 来自专栏山行AI

    浅析skiplist(跳表)

    skiplist(跳表)的应用场景 1. 2. 跳表 1. 结构 跳表由William Pugh 1989年发明。 引用自:https://en.wikipedia.org/wiki/Skip_list 跳表是一个“概率型”的数据结构,在很多应用场景中可以替代平衡树。 2. 复杂度 红黑树:插入、查找为O(logn),但常数项较小;无锁实现的复杂性很高,一般需要加锁;数据天然有序。 相比于二叉查找树,跳表维持结构平衡的成本比较低,完全靠随机。而二叉查找树需要Rebalance来重新调整平衡的结构。

    2.8K40发布于 2019-06-28
  • 来自专栏慕枫技术笔记

    这玩意叫跳表

    先和2比较,比2大则直接与13比较,比13大则继续与24 比较,比24大继续与33比较,结果比33小,那么进入L0层比较最终找到目标值27。 如果在L1层之上再增加一级索引Level2 2-》24,那么首先直接和2比较,比2大直接跳到24节点。 假设我们在原始的链表中每两个节点提取出一个节点作为一级索引的节点的话,那么Level1层就有n/2个节点,而Level2层的索引就有个节点,那么以此类推,第x层索引的节点个数就是n/个节点。 我们再假设最高层级为m,对应的节点个数为2,那么我们可以获得这样的等式,那么我们可以得到最高层的m值为m=log2n-1,结合最初始的链表,整个跳表的高度就是log2n,综合整个数据检索的过程,跳表检索的时间复杂度为 另外跳表长度表示跳表中包含的跳表节点数,而level则表示跳表拥有多少层检索索引。

    60610编辑于 2023-03-20
  • 来自专栏C++&linux

    【数据结构】跳表

    2. ,那在插入或删除时,只会影响每层前后的节点,而不会影响整个跳表,因为上下层节点的1:2比例关系我们干脆就不维护了,直接让层数变为随机的了。 可以看到,随着层数的增加,由于不断的累乘p,概率其实在一直减小,有人可能会担心skiplist的空间消耗过大,但其实通过节点层数的平均值,可以看到,当概率为0.5时,每个节点平均包含的指针数目也仅仅才为2, 原论文:Skip Lists: A Probabilistic Alternative to Balanced Trees 张铁蕾大佬的文章 2. 站在程序员实现数据结构的角度来讲,平衡树的插入删除和跳表的插入删除来比,平衡树实现的难度还是比较大的,同时也不好控制,而skiplist的增删查改相对来说较容易控制很多。 2.

    54810编辑于 2024-02-23
  • 来自专栏用户4352451的专栏

    跳跃表(跳表

    当有64个节点的链表的时候,则会创建多少层索引, 通过计算回事5层,那么每一层的索引个数呢,n/2^k (n为总的索引树,k为创建的索引层数(不包括原始链表数据结构)), 最高的层的索引层的长度为2 ,那我们计算出 层级为 k = log2^n- 1 ,如果我们每一层遍历M个元素那么我们的时间复杂度为O(m(log2^n-1)) ,我们的是两个元素结合为一个节点那么每一层最多遍历3个元素,那么我们时间复杂度为 O(3log2^n -1) 那么时间复杂度为 O(logn) 现在就是在原有的得单链表上创建了多层索引而达到二分法查找,达到很高。

    59320发布于 2020-08-26
  • 来自专栏JMCui

    跳表(SkipList) 和 ConcurrentSkipListMap

    一、跳表(SkipList) 对于单链表,即使链表是有序的,如果想要在其中查找某个数据,也只能从头到尾遍历链表,这样效率自然就会很低,跳表就不一样了。 跳表是一种可以用来快速查找的数据结构,有点类似于平衡树。它们都可以对元素进行快速的查找。 就查询的性能而言,跳表的时间复杂度是 O(logn)。 跳表的本质,其实是同时维护了多个链表,并且链表是分层的: ? 其中最低层的链表,维护了跳表内所有的元素,每往上一层链表,都是下面一层的子集。 跳表内每一层链表的元素都是有序的。查找时,可以从顶级链表开始找。 从上面很容易看出,跳表是一种利用空间换时间的算法。

    1.3K20发布于 2020-03-19
  • 来自专栏叽叽西

    数据结构-跳表

    k 级索引的结点个数是第 k-1 级索引的结点个数的 1/2,那第 k级索引结点的个数就是 n/(2k)。 假设索引有 h 级,最高级的索引有 2 个结点。通过上面的公式,我们可以得到 n/(2h)=2,从而求得 h=log2n-1。如果包含原始链表这一层,整个跳表的高度就是 log2n。 跳表的空间复杂度分析并不难,我在前面说了,假设原始链表大小为 n,那第一级索引大约有 n/2 个结点,第二级索引大约有 n/4 个结点,以此类推,每上升一级就减少一半,直到剩下 2 个结点。 这几级索引的结点总和就是 n/2+n/4+n/8…+8+4+2=n-2。所以,跳表的空间复杂度是 O(n)。 跳表索引动态更新 跳表索引动态更新当我们不停地往跳表中插入数据时,如果我们不更新索引,就有可能出现某 2 个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。

    53010编辑于 2022-05-17
  • 来自专栏Michael阿明学习之路

    数据结构--跳表SkipList

    对单链表查找一个元素的时间复杂度是 O(n) 通过对链表建立多级索引的结构,就是跳表,查找任意数据、插入数据、删除数据的时间复杂度均为 O(log n) 前提:建立了索引,用空间换时间的思路 (每两个节点建立一个索引 )索引节点总和 n/2+n/4+n/8+…+8+4+2 = n-2,空间复杂度 O(n) 插入和删除后,动态更新索引,避免局部链表元素过多或者过少,退化成单链表 ? skiplist.h /** * @description: 跳表 * @author: michael ming * @date: 2019/4/22 22:21 * @modified by unsigned int UINT; template <class T> class skipNode { public: T data; skipNode<T> **next; //跳表节点的 false; UINT lv = 0; for(int i = 0; i < maxLevel; ++i) { if(rand()%2)

    41320发布于 2021-02-20
  • 来自专栏程序员小灰

    漫画:什么是 “跳表” ?

    假设原始链表有n个结点,那么各层索引的结点总数是n/2+n/4+n/8+n/16+......2,约等于n。 也就是说,优化之后的数据结构所占空间,是原来的2倍。这是典型的以空间换时间的做法。 假设我们要从跳表中删除结点10,首先我们按照跳表查找结点的方法,找到待删除的结点: 接下来,按照一般链表的删除方式,把结点10从原始链表当中删除: 这样是不是删除工作就完成了呢?并不是。 程序中跳表采用的是双向链表,无论前后结点还是上下结点,都各有两个指针相互指向彼此。 2. 程序中跳表的每一层首位各有一个空结点,左侧的空节点是负无穷大,右侧的空节点是正无穷大。 new Node(Integer.MAX_VALUE); p1.right=p2; p2.left=p1; p1.down=head; head.up =p1; p2.down=tail; tail.up=p2; head=p1; tail=p2; } //删除结点

    85760发布于 2020-08-27
  • 来自专栏皮皮星球

    golang实现跳表(SkipList)

    跳表这种数据结构利用空间换时间,性能和红黑树比肩,还能支持区间搜索,在redis和leveldb等开源项目中都用被应用。 跳表的结构如图所示: image.png 在最底层包含了所有的数据节点,每一层链表都有一个指向下一层和自己相同的节点,向后的指针指向随机的同一层比自己大的数据。 时间复杂度分析 不难理解,对于一个有n个节点的链表,如果每两个节点会提取出一个节点作为索引节点,那么第一层的节点个数为n/2,再往上一层,节点数变成n/4,以此类推,第k层的索引个数为n/(2^k),假设层数有 x层,并且第x层的节点个数为2,也就是n/(2^x) = 2,所以x = (logn - 1),而第0层是链表本身,所以整个跳表的高度就是logn,如果每一层都需要遍历m个节点,那么在跳表中查询某个数的时间复杂度就是 简单的单向跳表实现: skiplist

    1.5K10发布于 2020-09-23
  • 来自专栏算法之名

    ConcurrentSkipListMap跳表原理解析

    内部结构如下(图片来源于网络),这里面Node其实就是HeadIndex中的level1,level2,level3中的一个个绿点。 ? //竞争成功的,退出'for (;;)'循环 break outer; } } //到此时表示已经节点已经put成功了,但对于跳表来说 level <= (max = h.level)) { //根据层数level不断创建新增节点的下层索引 //注意此时只是新增了新节点的索引,并没有关联到跳表的真实体中 >[level+1]; //根据层数level不断创建新增节点的下层索引,并放入数组中 //此时只是新增了新节点的索引,并没有关联到跳表的真实体中 for (;;) { //获取原始头索引以及该头索引的链表后续索引,当ConcurrentSkipListMap刚初始化的时候,r为null //但是我们查找肯定不会在空的跳表中查找

    67110发布于 2019-12-03
  • 来自专栏小明说Java

    Redis压缩列表和跳表

    Redis 的压缩列表(ziplist)和跳表(skiplist)是两种不同的数据结构,它们在 Redis 中被用于实现不同的功能。压缩列表实际上类似于一个数组,数组中的每一个元素都对应保存一个数据。 跳表(skiplist)有序链表只能逐一查找元素,导致操作起来非常缓慢,于是就出现了跳表,时间复杂度为O(N)。 具体来说,跳表,在链表的基础上,增加了多级索引,通过索引位置的几个跳转,实现数据的快速定位,如下图所示:如果我们要在链表中查找33这个元素,只能从头开始遍历链表,查找6次,直到找到33为止。 当数据量很大时,跳表的查找复杂度就是O(logN)。总之,压缩列表和跳表是两种不同的数据结构,它们在 Redis 中被用于实现不同的功能。 压缩列表用于存储短的列表或集合,而跳表用于实现可以在对数时间内进行搜索、插入和删除操作的有序集合。我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

    1.2K10编辑于 2023-11-21
  • 来自专栏烟草的香味

    数据结构之跳表

    跳表来了, 顾名思义, 跳表就是可以跳跃的表, 我简单画了张图: 在原来链表的基础上, 建立一个新的索引链表, 原链表没两个建立一个 原来查找节点5的访问顺序是: 1->2->3->4->5->6, 从上面的例子可以看出, 简直就是二分查找的翻版, 时间复杂度O(logn) 空间复杂度 很清楚的看出来, 跳表的解决方案就是用空间来换时间 若原来的链表占用空间为n, 那么一级索引占用空间为n/2, 二级索引占用空间为 n/4 总占用空间=n+n/2+n/4+...+2=2n-2 所以, 其空间复杂度为O(n) 插入和删除 当链表有了高效的查找时, 高效的删除和插入也就是顺理成章的事了. 那么如何保证跳表的平衡, 避免跳表因为插入而出现复杂度退化呢? , 比如: 链表共又3级索引, 随机数是2, 那么就将新插入的节点添加到第一、二级索引中, 如下图: 以上, 就是跳表的简单介绍!!

    56530发布于 2019-07-25
  • 来自专栏Redis源码学习系列

    Redis源码学习之跳表

    跳表作为一种平衡数据结构,经常和平衡树进行比较,在大多数场景下,跳表都可以达到平衡树的效率(查询节点支持平均O(lgN),最坏O(N)的复杂度),但实现和维护起来却比平衡树简单很多。 score,以及每个节点的层数结构,每层都包含着前进指针与跨度;除此之外,每个节点还包含一个后退指针,假设跳表只有一层,那么整个跳表将退化为双端链表。 跳表,持有跳表的结构包括指向跳表表头和表尾的指针,以及整个跳表的长度(即第一层的节点数,但不包含头结点),还有整个跳表最高层的层数。 最终,Redis中的一个长度为2,层高为2跳表如下图所示 插入节点 当进行插入操作的时候,程序会维护两个数组,rank数组保存每层中插入节点前驱前驱节点的排行值,update数组保存每层插入节点的前驱节点 在插入节点之前,update[3]指向头结点,rank[3]=0,rank[0]=2,第三层左边节点到右边节点的跨度是4,那么从图中可以看出,新节点的跨度=左边节点(即插入节点的前驱)跨度-(rank[

    14.6K108发布于 2018-10-11
  • 来自专栏yuyy.info技术专栏

    跳表:为什么Redis一定要用跳表来实现有序集合?

    极限情况下,索引层高度为log2n-1,总高度为log2n。 假设原始链表大小为n,那第一级索引大约有n/2个结点,第二级索引大约有n/4个结点,以此类推,每上升一级就减少一半,直到剩下2个结点。也就是计算这棵二叉树的节点数 - 叶子节点数 - 根节点。 索引层的结点总和就是n/2+n/4+n/8…+8+4+2=n-2。所以,跳表的空间复杂度是O(n)。 调整策略,两个节点取一个索引节点改为三个节点取一个索引节点,看看时间和空间复杂度变化。 总的索引结点大约就是n/3+n/9+n/27+…+9+3+1=n/2,空间占用减少一半。时间复杂度为3*log3n。 跳表索引动态更新 当我们不停地往跳表中插入数据时,如果我们不更新索引,就有可能出现某2个索引结点之间数据非常多的情况。极端情况下,跳表还会退化成单链表。

    1K11编辑于 2022-11-16
  • 来自专栏计算机技术

    Skiplist跳表的通俗理解

    跳表就是跨越层级的管理,这种管理结构就存在多样性了: 总经理-部门经理-总监-组长-基层员工。 这一管理层级肯定存在。 总经理-部门经理-组长-基层员工。这一管理层级可能存在。 这种跨层管理就是跳表跳表有什么好处就是执行命令速度快,总经理可以直接给基层员工安排任务。所以跳表要解决的问题就是提高有序表的查询速度。 (3) skip_list.print() ret = skip_list.search(3) print(3, "find", ret) 运行结果: 0层 : 2,4,6, 1层 : 2,6, 2层 : 2,6, 3层 : 2, 4层 : 5层 : 6层 : 7层 : 8层 : 9层 : after delete 4 0层 : 2,6, 1层 : 2, 2层 : 2, 3层 : 2, 4层 : 5层 : 6层 : 7层 : 8层 : 9层 : 2 find True 4 find False 0层 : 2,3,6, 1层 : 2,3, 2层 : 2,3, 3层 : 2,3

    56090编辑于 2022-04-02
  • 来自专栏CSDN搜“看,未来”

    数据结构(9)-- 跳表

    文章目录 跳表 跳表的搜索 跳表的插入 抛硬币 跳表的删除 跳表的代码实现 跳表数据结构 初始化跳表 插入节点 删除节点 销毁跳表 为什么Redis要用跳表来实现有序集合? ,发现第2层是9,小于17,继续搜索,发现9节点的下一个数是17,搜索完成。 \n"); return NULL; } level = slRandomLevel(); printf("score:%.2lf level:%d\n",score probability of a node to have a given number of levels will make then less memory intensive than btrees.2) 0; while (rand_num < p && flow < max_flow-1) { srand(time(NULL)); rand_num = rand() % (p * 2)

    50730发布于 2021-09-18
领券