• 跳表学习


    转自: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.应用

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

  • 相关阅读:
    UVA 11925 Generating Permutations 生成排列 (序列)
    UVA 1611 Crane 起重机 (子问题)
    UVA 11572 Unique snowflakes (滑窗)
    UVA 177 PaperFolding 折纸痕 (分形,递归)
    UVA 11491 Erasing and Winning 奖品的价值 (贪心)
    UVA1610 PartyGame 聚会游戏(细节题)
    UVA 1149 Bin Packing 装箱(贪心)
    topcpder SRM 664 div2 A,B,C BearCheats , BearPlays equalPiles , BearSorts (映射)
    UVA 1442 Cave 洞穴 (贪心+扫描)
    UVA 1609 Foul Play 不公平竞赛 (构(luan)造(gao)+递归)
  • 原文地址:https://www.cnblogs.com/BlueBlueSea/p/15362238.html
Copyright © 2020-2023  润新知