专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

一种插入、查找后继节点耗时为 lglgu 的算法van Emde Boas Trees

前提

假设总共有n个int元素,它的值在 {0,1,..,u-1}范围内,可以做到插入、删除、后继节点耗时为 lglgu 。

常用的应用场景如,网络路由表。对于IPV4来讲,u的取值范围是 93_1.png

如果u不是特别大,比如93_2.png,那么相当于总共的时间是 lglgn

lglgu 在什么样的场景下才会出现?

对于一个算法,如果它的迭代结构为

93_3.png

可以得到,它的耗时为O(lgk),那么要得到lglg的效果,相当于,迭代的结构为

93_4.png

使得lgk=u,有

93_5.png

此时算法的运行时间为 lglgu

如何使得u的存储和删除是常量时间?

使用数组存储所有的元素,数组的index就是要存储的n的值,数组u的值为0,表示当前值没有,1,表示有,这种结构为Bit Vector,如下:

93_6.png

上示中,u=16,目前存储的元素为 {1,9,10,15}

此时,存储和删除的时间都是O(1),查找后继节点的时间为O(u)

在bit vector的基础上,如何加快后继节点的查找速度?

把u分成93_7.png个cluster,然后在每个cluster上去构建一个树

93_8.png

每个cluster的树的构建规则是根据每个值之间的或得到的结果,那么要查找对应的值是否存在,只需要看当前的cluster树的顶点是不是1即可

给每个cluster的树取名为summary

93_9.png对于构建的树,新插入的元素值在u中的坐标可表示为

93_10.png

i表示在那个cluster,j表示在cluster中的位置,取函数 high(x)=i,low(x)=j

整个结构称作V,它包含如下信息

  • V.cluster[i]大小为93_11.png,其中 93_12.png
  • V.summary大小为93_13.png,从V.summary[i]能够判断 V.cluster[i]是不是空的

successor的获取方法为:

  • 先看high(x)里面,耗时为 93_14.png
  • high(x)里面没有找到下一个非空的cluster i ,耗时为 93_15.png
  • 找到i的第一个存在的元素即可,耗时为 93_16.png

在此结构下,总的时间消耗

插入

Insert(V,x):
    //先在u中插入元素
    Insert(V.cluster[high(x)],low(x))
    //更新summary
    Insert(V.summary,high(x))

它的耗时为

93_17.png

可得,T(u)=O(lgu),没有达到预期的效果

查找后继

Successor(V,x):
    //计算出在那个cluster
    i=high(x)
    //查找当前的cluster是不是有这个元素
    j=Successor(V.cluster[i],low(x))
    if j not exist:
        //先找到i后面的非空的summary
        i=Successor(V.summary,i)
        //从找到的cluster中寻找后继者,Integer.MIN_VALUE表示我不知道具体的位置是那个
        j=Successor(V.cluster[i],Integer.MIN_VALUE)
    return index(i,j)

它的耗时为

93_18.png

93_19.png

总的耗时时间并不好,再次优化结构

在查找后继节点的过程中,如果当前的cluster不存在值,就找下一个cluster的元素j=Successor(V.cluster[i],Integer.MIN_VALUE),而根据后继节点的性质,当保存了每个cluster的最小元素的时候,这次查找就可以干掉。
其次,cluster查找的时候,如果能够立马知道,是否能够在当前cluster找到元素,那么就能决定,到底是找当前的clusterj=Successor(V.cluster[i],low(x))还是在下一个i=Successor(V.summary,i),当存储了每个cluster的max元素的下标的时候,如果low(x)<max显然就在当前cluster,否则就是下一个,这样只需要执行1次Successor

Successor(V,x):
    //最小的元素只存储在V.min
    if x < V.min:
        return V.min
    i=high(x)
    if low(x) < V.cluster[i].max:
        j=Successor(V.cluster[i],low(x))
    else
        i=Successor(V.summary,high(x))
        j=V.cluster[i].min
    return index(i,j)

它的耗时为

93_20.png

即T(u)=O(lglgu)

插入方式优化

Insert(V,x):
    //先考虑V没有元素存在
    if V.min == None
        V.min=V.max=x
        return
    if x<V.min
        swap(x,V.min)
    if x>V.max
        V.max=x
    //如果当前cluster没有元素
    if V.cluster[high(x)].min == None:
        Insert(V.summary,high(x))  //第一次调用Insert,custer之前没有值,更新summary
    Insert(V.cluster[high(x)],low(x))  //第二次调用Insert,在u中插入元素

当第一次调用去更新summary的时候,V.cluster[high(x)]肯定是没有值的,那么第二次调用 Insert(V.cluster[high(x)],low(x))的时候,只会执行V.min == None

这里只在V.min中存储了最小值 它的时间为 O(lglgu)

删除实际在这种方式下,它的耗时也是O(lglgu)

文章永久链接:https://tech.souyunku.com/47217

未经允许不得转载:搜云库技术团队 » 一种插入、查找后继节点耗时为 lglgu 的算法van Emde Boas Trees

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们