跳躍表(SkipList)是一種能高效實現插入、刪除、查找的內存數據結構,這些操做的指望複雜度都是O(logN)。與紅黑樹以及其餘的二分查找樹相比,跳躍表的優點在於實現簡單,並且在併發場景下加鎖粒度更小,從而能夠實現更高的併發性。正由於這些優勢,跳躍表普遍使用於KV數據庫中,諸如Redis、LevelDB、HBase都把跳躍表做爲一種維護有序數據集合的基礎數據結構。算法
衆所周知,鏈表這種數據結構的查詢複雜度爲O(N),這裏N是鏈表中元素的個數。在已經找到要刪除元素的狀況下,再執行鏈表的刪除操做其實很是高效,只需把待刪除元素前一個元素的next指針指向待刪除元素的後一個元素便可,複雜度爲O(1),如圖所示數據庫
但問題是,鏈表的查詢複雜度過高,由於鏈表在查詢的時候,須要逐個元素地查找。若是鏈表在查找的時候,可以避免依次查找元素,那麼查找複雜度將下降。而跳躍表就是利用這一思想,在鏈表之上額外存儲了一些節點的索引信息,達到避免依次查找元素的目的,從而將查詢複雜度優化爲O(logN)。將查詢複雜度優化以後,天然也優化了插入和刪除的複雜度。數據結構
跳躍表的定義以下:併發
•跳躍表由多條分層的鏈表組成(設爲S0, S1, S2, ... , Sn),例如圖中有6條鏈表。
•每條鏈表中的元素都是有序的。
•每條鏈表都有兩個元素:+∞(正無窮大)和- ∞(負無窮大),分別表示鏈表的頭部和尾部。
•從上到下,上層鏈表元素集合是下層鏈表元素集合的子集,即S1是S0的子集,S2是S1的子集。
•跳躍表的高度定義爲水平鏈表的層數。dom
在跳躍表中查找一個指定元素的流程比較簡單。如圖所示,以左上角元素(設爲currentNode)做爲起點查找元素5:優化
•若是發現currentNode後繼節點的值小於等於待查詢值,則沿着這條鏈表向後查詢,不然,切換到當前節點的下一層鏈表。
•繼續查詢,直到找到待查詢值爲止(或者currentNode爲空節點)爲止。spa
跳躍表的插入算法要複雜一點。如圖所示。首先,須要按照上述查找流程找到待插入元素的前驅和後繼;而後,按照以下隨機算法生成一個高度值:指針
(圖在跳躍表插入元素48)
最後,將待插入節點按照高度值生成一個垂直節點(這個節點的層數正好等於高度值),以後插入到跳躍表的多條鏈表中去。假設height=randomHeight(p),這裏須要分兩種狀況討論:
•若是height大於跳躍表的高度,那麼跳躍表的高度被提高爲height,同時須要更新頭部節點和尾部節點的指針指向。
•若是height小於等於跳躍表的高度,那麼須要更新待插入元素前驅和後繼的指針指向。blog
跳躍表的查找、刪除、插入的複雜度都是O(logN)。索引
文章基於《HBase原理與實踐》一書