Skip List

什麼是skip list?

“Skip lists are a data structure that can be used in place ofbalanced trees. Skip lists use probabilistic balancing rather than strictlyenforced balancing and as a result the algorithms for insertion and deletion inskip lists are much simpler and significantly faster than equivalent algorithmsfor balanced trees.“

 

如上爲skip list作者William Pugh對skip list的解釋,跳錶是一種可以替代平衡樹的數據結構,跳錶使用的平衡算法並不是嚴格要求的平衡,這使插入和刪除操作是更簡單,並且明顯比平衡樹快速。

 

跳錶數據結構


如上圖中的a鏈表,是一個有序鏈表,如果從中找一個節點,最多可能需要遍歷每一個節點,那麼時間複雜度就是O(n);n爲鏈表中節點的個數。




如上圖中的b鏈表,每隔一個節點多了一層指針,指向它前面第二2個節點,那麼我們要查找一個節點,最多可能需要遍歷(n/2)+ 1個節點,時間複雜度就是O(n/2);

 


如上圖中的c鏈表,在b鏈表的基礎上多了一層指針,每第四個節點,指向它前面第四個節點,那麼我們要查找一個節點,最多可能需要遍歷(n/4)+ 2個節點,時間複雜度就是O(n/4);

 


如上圖中的d鏈表,如果每第2^i個節點有指針指向它前面第2^i個節點,那麼查找某個節點的時間複雜度可以降低到O(logn),這種結構查詢起來很快速,但是插入和刪除確是不切實際的。

 


一個節點有k個向前的指針,那麼就稱這個節點爲k層節點,每個節點的層數是隨機產生的,產生level 1的概率是50%,level2的概率是25%,level 3的概率是12.5%……,每個節點的層數的產生要保證採用這種相同的機制;每個節點的第i層指針,指向下一個至少有i層的節點。因爲會滑過一些中間節點,所以稱爲跳錶。

 

跳錶算法

查找(僞碼如下)

Search(list, searchKey)

x :=list→header

--loop invariant: x → key < searchKey

for  i := list→level  downto 1 do

while x →forward[i]→ key < searchKey do

x :=  x →forward[i]

--  x→ key < searchKey ≤ x→ forward[1] → key

x:=  x →forward[1]

if  x →key = searchKey  then return x → value

else  return  failure

  

    從頂層開始找,每層中尋找比目標小的最大的一個節點,然後轉到下一層,然後向前移動一個節點,如果相等就代表找到了,如果不相等,就代表沒有這個節點。

插入(僞碼如下)


Insert(list, searchKey, newValue)

local  update[1..MaxLevel]

x :=list→header

for  i := list→level  downto 1 do

while x →forward[i]→ key < searchKey do

x :=  x →forward[i]

-- x →key < searchKey  ≤ x →forward[i] →key

update[i] :=  x

x:=  x →forward[1]

if  x →key = searchKey  then x → value :=  newValue

else

lvl := randomLevel()

if  lvl > list → level  then

for  i := list→level + 1 to  lvl  do

update[i] := list→header

list→ level := lvl

x := makeNode(lvl, searchKey, value)

for  i := 1  to level  do

x →forward[i] := update[i] →forward[i]

update[i] →forward[i] := x

從頂層開始找,每層中尋找比目標小的最大的一個節點,並記錄該節點到update數組,如果新節點的層數大於之前的,則更新list→level,並將list→header放到update數組,其實update數組存放的就是i層中指向目標節點(正插入)的前一個節點,所以最後就是循環每一層,將每層中指向目標的前一節點的對應指針指向目標節點,目標節點的下一個節點指向前一個節點的下一個節點。

 

刪除(僞碼如下)

Delete(list, searchKey)

local  update[1..MaxLevel]

x := list→header

for  i := list→ level  downto 1 do

while x→forward[i]→ key < searchKey  do

x :=  x →forward[i]

update[i]:=  x

x :=  x →forward[1]

if  x →key = searchKey  then

for  i := 1 to  list → level  do

if  update[i] →forward[i]  ≠ x then break

update[i]→forward[i] := x→ forward[i]

free(x)

while list→level > 1 and

list→header→ forward[list →level] = NIL  do

list→level := list →level – 1

從頂層開始找,每層中尋找比目標小的最大的一個節點,並記錄該節點到update數組,循環每層,將update中指向目標節點(被刪除的節點)的指針指向目標節點的下一個節點;如果被刪節點的層數是最高的,就要更新list→level,減去高出的部分。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章