zoukankan      html  css  js  c++  java
  • 跳表学习

    转自:https://zhuanlan.zhihu.com/p/68516038

    https://zhuanlan.zhihu.com/p/53975333?ivk_sa=1024320u

    1.跳表

    跳表全称为跳跃列表,它允许快速查询,插入和删除一个有序连续元素的数据链表。

    • 平均查找和插入时间复杂度都是O(logn)。
    • 通过维护一个多层次的链表,且每一层链表中的元素是前一层链表元素的子集。
    • 算法在最稀疏的层次进行搜索,直至需要查找的元素在该层两个相邻的元素中间,则跳到下一个层次继续搜索。

    在单链表中插入的复杂度为O(n),在原始链表的基础上,每两个结点提取一个结点建立索引,我们把抽取出来的结点叫做索引层或者索引,down 表示指向原始链表结点的指针。

    比如上图在查找15的过程中,首先在第二级索引层比较,通过14的down指针跳到第一级索引层,与14比较,以及14的next 17比较,发现15在两者之间,那么就跳到14的down指针,到原始链表中查找。

    通过对链表加多级索引的数据结构,就是跳表

    2.跳表复杂度

    时间复杂度:

    如果一个链表有 n 个结点,如果每两个结点抽取出一个结点建立索引的话,那么第一级索引的结点数大约就是 n/2,第二级索引的结点数大约为 n/4,以此类推第 m 级索引的节点数大约为 n/(2^m)。则m=log(n)-1,那么跳表高度为logn,在查询跳表的时候,如果每一层都需要遍历 k 个结点,那么最终的时间复杂度就为 O(k*log(n))。k是常数,可以忽略。

    空间复杂度:

    如果一个链表有 n 个结点,如果每两个结点抽取出一个结点建立索引的话,那么第一级索引的结点数大约就是 n/2,第二级索引的结点数大约为 n/4,以此类推第 m 级索引的节点数大约为 n/(2^m),等比数列求和,跳表的空间复杂度为 o(n)。

    3.插入和删除

    插入:

    就可能会造成两个索引点之间的结点过多的情况,所以需要维护索引与原始链表的大小平衡,也就是结点增多了,索引也相应增加,避免出现两个索引之间结点过多的情况,查找效率降低。

    跳表是通过一个随机函数来维护这个平衡的,当我们向跳表中插入数据的的时候,我们可以选择同时把这个数据插入到索引里,那我们插入到哪一级的索引呢,这就需要随机函数,来决定我们插入到哪一级的索引中。

    因为删除和插入节点是不可预测的,很难预测,所以选择随机抛硬币的方式来选择。

    插入流程:

    1. 新节点和各层索引节点逐一比较,确定原链表的插入位置。O(logN)
    2. 把索引插入到原链表。O(1)
    3. 利用抛硬币的随机方式,决定新节点是否提升为上一级索引。结果为“正”则提升并继续抛硬币,结果为“负”则停止。O(logN)

    删除:

    单向链表,删除时不仅要删除节点还要删除索引,需要获取其前驱节点;双向链表,删除时无需前驱。

    删除流程:

    1. 自上而下,查找第一次出现节点的索引,并逐层找到每一层对应的节点。O(logN)
    2. 删除每一层查找到的节点,如果该层只剩下1个节点,删除整个一层(原链表除外)。O(logN)

    4.应用

     在进行排序时,可以维护,以空间换时间。

  • 相关阅读:
    npm optionalDependencies 依赖处理
    grafana 8.0 新的报警机制
    cube.js prometheus 监控
    cube.js 新版本playground 特性
    data mesh & data lake & data fabric
    java 几个开源dataframe 的实现包
    archaius netflix 的配置管理工具框架
    dremio 文件夹数据分区
    dremio 17 发布了
    Linux系统挂载未分配硬盘空间
  • 原文地址:https://www.cnblogs.com/BlueBlueSea/p/15362238.html
Copyright © 2011-2022 走看看