跳躍表
本文將總結一種數據結構:跳躍表。前半部分跳躍表性質和操作的介紹直接摘自《讓算法的效率跳起來--淺談“跳躍表”的相關操作及其應用》上海市華東師範大學第二附屬中學 魏冉。之後將附上跳躍表的源代碼,以及本人對其的瞭解。難免有錯誤之處,希望指正,共同進步。謝謝。
跳躍表(Skip List)是1987年才誕生的一種嶄新的數據結構,它在進行查找、插入、刪除等操作時的期望時間複雜度均爲O(logn),有着近乎替代平衡樹的本領。而且最重要的一點,就是它的編程複雜度較同類的AVL樹,紅黑樹等要低得多,這使得其無論是在理解還是在推廣性上,都有着十分明顯的優勢。
首先,我們來看一下跳躍表的結構
跳躍表由多條鏈構成(S0,S1,S2 ……,Sh),且滿足如下三個條件:
每條鏈必須包含兩個特殊元素:+∞ 和 -∞(其實不需要)
S0包含所有的元素,並且所有鏈中的元素按照升序排列。
每條鏈中的元素集合必須包含於序數較小的鏈的元素集合。
操作
一、查找
目的:在跳躍表中查找一個元素x
在跳躍表中查找一個元素x,按照如下幾個步驟進行:
1. 從最上層的鏈(Sh)的開頭開始
2. 假設當前位置爲p,它向右指向的節點爲q(p與q不一定相鄰),且q的值爲y。將y與x作比較
(1) x=y 輸出查詢成功及相關信息
(2) x>y 從p向右移動到q的位置
(3) x<y 從p向下移動一格
3. 如果當前位置在最底層的鏈中(S0),且還要往下移動的話,則輸出查詢失敗
二、插入
目的:向跳躍表中插入一個元素x
首先明確,向跳躍表中插入一個元素,相當於在表中插入一列從S0中某一位置出發向上的連續一段元素。有兩個參數需要確定,即插入列的位置以及它的“高度”。
關於插入的位置,我們先利用跳躍表的查找功能,找到比x小的最大的數y。根據跳躍表中所有鏈均是遞增序列的原則,x必然就插在y的後面。
而插入列的“高度”較前者來說顯得更加重要,也更加難以確定。由於它的不確定性,使得不同的決策可能會導致截然不同的算法效率。爲了使插入數據之後,保持該數據結構進行各種操作均爲O(logn)複雜度的性質,我們引入隨機化算法(Randomized Algorithms)。
我們定義一個隨機決策模塊,它的大致內容如下:
產生一個0到1的隨機數r r ← random()
如果r小於一個常數p,則執行方案A, if r<p then do A
否則,執行方案B else do B
初始時列高爲1。插入元素時,不停地執行隨機決策模塊。如果要求執行的是A操作,則將列的高度加1,並且繼續反覆執行隨機決策模塊。直到第i次,模塊要求執行的是B操作,我們結束決策,並向跳躍表中插入一個高度爲i的列。
我們來看一個例子:
假設當前我們要插入元素“40”,且在執行了隨機決策模塊後得到高度爲4
步驟一:找到表中比40小的最大的數,確定插入位置
步驟二:插入高度爲4的列,並維護跳躍表的結構
三、刪除
目的:從跳躍表中刪除一個元素x
刪除操作分爲以下三個步驟:
在跳躍表中查找到這個元素的位置,如果未找到,則退出
將該元素所在整列從表中刪除
將多餘的“空鏈”刪除
我們來看一下跳躍表的相關複雜度:
空間複雜度: O(n) (期望)
跳躍表高度: O(logn) (期望)
相關操作的時間複雜度:
查找: O(logn) (期望)
插入: O(logn) (期望)
刪除: O(logn) (期望)
之所以在每一項後面都加一個“期望”,是因爲跳躍表的複雜度分析是基於概率論的。有可能會產生最壞情況,不過這種概率極其微小。