一種插入、查找後繼節點耗時爲 lglgu 的算法van Emde Boas Trees

前提

假設總共有n個int元素,它的值在 {0,1,..,u-1}範圍內,能夠作到插入、刪除、後繼節點耗時爲 lglgu 。算法

經常使用的應用場景如,網絡路由表。對於IPV4來說,u的取值範圍是 2^{32}數組

若是u不是特別大,好比u=n^{O(1)},那麼至關於總共的時間是 lglgnbash

lglgu 在什麼樣的場景下才會出現?

對於一個算法,若是它的迭代結構爲網絡

T(k)=T(k/2)+O(1)

能夠獲得,它的耗時爲O(lgk),那麼要獲得lglg的效果,至關於,迭代的結構爲函數

T(lgk)=T(lgk/2)+O(1)

使得lgk=u,有優化

T(u)=T((lgk)^{1/2})+O(1)=T(\sqrt u)+O(1)

此時算法的運行時間爲 lglguui

如何使得u的存儲和刪除是常量時間?

使用數組存儲全部的元素,數組的index就是要存儲的n的值,數組u的值爲0,表示當前值沒有,1,表示有,這種結構爲Bit Vector,以下:spa

上示中,u=16,目前存儲的元素爲 {1,9,10,15}.net

此時,存儲和刪除的時間都是O(1),查找後繼節點的時間爲O(u)3d

在bit vector的基礎上,如何加快後繼節點的查找速度?

把u分紅\sqrt u個cluster,而後在每一個cluster上去構建一個樹

每一個cluster的樹的構建規則是根據每一個值之間的或獲得的結果,那麼要查找對應的值是否存在,只須要看當前的cluster樹的頂點是否是1便可

給每一個cluster的樹取名爲summary

對於構建的樹,新插入的元素值在u中的座標可表示爲

index(x)=i*\sqrt u+j

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

整個結構稱做V,它包含以下信息

  • V.cluster[i]大小爲\sqrt u,其中 0\leq i \lt \sqrt u
  • V.summary大小爲\sqrt u,從V.summary[i]可以判斷 V.cluster[i]是否是空的

successor的獲取方法爲:

  • 先看high(x)裏面,耗時爲 O(\sqrt u)
  • high(x)裏面沒有找到下一個非空的cluster i ,耗時爲 O(\sqrt u)
  • 找到i的第一個存在的元素便可,耗時爲 O(\sqrt u)

在此結構下,總的時間消耗

插入

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

它的耗時爲

T(u)=2T(\sqrt u)+O(1)

可得,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)
複製代碼

它的耗時爲

T(u)=3T(\sqrt u)+O(1)

T(u)=O((lgu)^{lg3})

總的耗時時間並很差,再次優化結構

在查找後繼節點的過程當中,若是當前的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)
複製代碼

它的耗時爲

T(u)=T(\sqrt u)+O(1)

即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)

相關文章
相關標籤/搜索