跳躍表原理

跳躍表的引入

咱們知道,普通單鏈表查詢一個元素的時間複雜度爲O(n),即便該單鏈表是有序的,咱們也不能經過2分的方式縮減時間複雜度。算法

 

 

如上圖,咱們要查詢元素爲55的結點,必須從頭結點,循環遍歷到最後一個節點,不算-INF(負無窮)一共查詢8次。那麼用什麼辦法可以用更少的次數訪問55呢?最直觀的,固然是新開闢一條捷徑去訪問55。post

 

 

如上圖,咱們要查詢元素爲55的結點,只須要在L2層查找4次便可。在這個結構中,查詢結點爲46的元素將耗費最多的查詢次數5次。即先在L2查詢46,查詢4次後找到元素55,由於鏈表是有序的,46必定在55的左邊,因此L2層沒有元素46。而後咱們退回到元素37,到它的下一層即L1層繼續搜索46。很是幸運,咱們只須要再查詢1次就能找到46。這樣一共耗費5次查詢。spa

 

那麼,如何才能更快的搜尋55呢?有了上面的經驗,咱們就很容易想到,再開闢一條捷徑。3d

如上圖,咱們搜索55只須要2次查找便可。這個結構中,查詢元素46仍然是最耗時的,須要查詢5次。即首先在L3層查找2次,而後在L2層查找2次,最後在L1層查找1次,共5次。很顯然,這種思想和2分很是類似,那麼咱們最後的結構圖就應該以下圖。指針

 

 

咱們能夠看到,最耗時的訪問46須要6次查詢。即L4訪問55,L3訪問2一、55,L2訪問3七、55,L1訪問46。咱們直覺上認爲,這樣的結構會讓查詢有序鏈表的某個元素更快。那麼究竟算法複雜度是多少呢?blog

 

若是有n個元素,由於是2分,因此層數就應該是log n層 (本文全部log都是以2爲底),再加上自身的1層。以上圖爲例,若是是4個元素,那麼分層爲L3和L4,再加上自己的L2,一共3層;若是是8個元素,那麼就是3+1層。最耗時間的查詢天然是訪問全部層數,耗時logn+logn,即2logn。爲何是2倍的logn呢?咱們以上圖中的46爲例,查詢到46要訪問全部的分層,每一個分層都要訪問2個元素,中間元素和最後一個元素。因此時間複雜度爲O(logn)class

 

至此爲止,咱們引入了最理想的跳躍表,可是若是想要在上圖中插入或者刪除一個元素呢?好比咱們要插入一個元素2二、2三、24……,天然在L1層,咱們將這些元素插入在元素21後,那麼L2層,L3層呢?咱們是否是要考慮插入後怎樣調整鏈接,才能維持這個理想的跳躍表結構。咱們知道,平衡二叉樹的調整是一件使人頭痛的事情,左旋右旋左右旋……通常人還真記不住,而調整一個理想的跳躍表將是一個比調整平衡二叉樹還複雜的操做。幸運的是,咱們並不須要經過複雜的操做調整鏈接來維護這樣完美的跳躍表。有一種基於機率統計的插入算法,也能獲得時間複雜度爲O(logn)的查詢效率,這種跳躍表纔是咱們真正要實現的。效率

 

容易實現的跳躍表

容易實現的跳躍表,它容許簡單的插入和刪除元素,並提供O(logn)的查詢時間複雜度,如下咱們簡稱爲跳躍表。二叉樹

 

先討論插入,咱們先看理想的跳躍表結構,L2層的元素個數是L1層元素個數的1/2,L3層的元素個數是L2層的元素個數的1/2,以此類推。從這裏,咱們能夠想到,只要在插入時儘可能保證上一層的元素個數是下一層元素的1/2,咱們的跳躍表就能成爲理想的跳躍表。那麼怎麼樣才能在插入時保證上一層元素個數是下一層元素個數的1/2呢?很簡單,拋硬幣就能解決了!假設元素X要插入跳躍表,很顯然,L1層確定要插入X。那麼L2層要不要插入X呢?咱們但願上層元素個數是下層元素個數的1/2,因此咱們有1/2的機率但願X插入L2層,那麼拋一下硬幣吧,正面就插入,反面就不插入。那麼L3到底要不要插入X呢?相對於L2層,咱們仍是但願1/2的機率插入,那麼繼續拋硬幣吧!以此類推,元素X插入第n層的機率是(1/2)的n次。這樣,咱們能在跳躍表中插入一個元素了。搜索

 

在此仍是以上圖爲例:跳躍表的初試狀態以下圖,表中沒有一個元素:

 

 

若是咱們要插入元素2,首先是在底部插入元素2,以下圖:

 

 

而後咱們拋硬幣,結果是正面,那麼咱們要將2插入到L2層,以下圖

 

 

繼續拋硬幣,結果是反面,那麼元素2的插入操做就中止了,插入後的表結構就是上圖所示。接下來,咱們插入元素33,跟元素2的插入同樣,如今L1層插入33,以下圖:

 

 

而後拋硬幣,結果是反面,那麼元素33的插入操做就結束了,插入後的表結構就是上圖所示。接下來,咱們插入元素55,首先在L1插入55,插入後以下圖:

 

 

而後拋硬幣,結果是正面,那麼L2層須要插入55,以下圖:

 

 

繼續拋硬幣,結果又是正面,那麼L3層須要插入55,以下圖:

 

 

繼續拋硬幣,結果又是正面,那麼要在L4插入55,結果以下圖:

 

 

繼續拋硬幣,結果是反面,那麼55的插入結束,表結構就如上圖所示。

 

以此類推,咱們插入剩餘的元素。固然由於規模小,結果極可能不是一個理想的跳躍表。可是若是元素個數n的規模很大,學過幾率論的同窗都知道,最終的表結構確定很是接近於理想跳躍表。

 

固然,這樣的分析在感性上是很直接的,可是時間複雜度的證實實在複雜,在此我就不深究了,感興趣的能夠去看關於跳躍表的paper。

 

再討論刪除,刪除操做沒什麼講的,直接刪除元素,而後調整一下刪除元素後的指針便可。跟普通的鏈表刪除操做徹底同樣。

 

再來討論一下時間複雜度,插入和刪除的時間複雜度就是查詢元素插入位置的時間複雜度,這不難理解,因此是O(logn)。

相關文章
相關標籤/搜索