講講跳躍表(Skip Lists)


跳躍表(Skip Lists)是一種有序的數據結構,它通過在每個節點中維持多個指向其他節點的指針,從而達到快速訪問節點的目的。在大部分情況下,跳躍表的效率可以和平衡樹相媲美,並且在實現上比平衡樹要更為簡單,因而得到了廣泛的應用。

如上圖所示,是一個跳躍表的示例。由此可以看出跳躍表的幾個特點:

  • 有序性,如上圖中各節點呈遞增趨勢;

  • 跳躍表由多個層組成;

  • 跳躍表的第一層始終包含所有元素;

  • 如果某個元素位於第 i 層,那該層一下的所有層也會包含此元素。

既然是鏈表的一種,那在實現時,固然要考慮插入、刪除、查找等幾個主要方法,下面來一一解析。

查找

要查找一個元素,應從頂層開始,自頂向下查找,又因為其有序性,因此與平衡樹上的查找其實很類似。

以之前的圖為例,要搜索 12,從頂層為入口,步驟大致如下:

  1. 從 L3 的第一個節點查詢后一個節點 21,發現比 12 大,跳至下一層;

  2. 從 L2 的第一個節點查詢后一個節點 9,比 12 小,因此繼續向后;

  3. 繼續查詢 L2 的下一個節點 21,比 12 大,跳至下一層;

  4. 從 L1 的第一個節點開始查詢,直至 17 時發現比 12 大,再次調至下一層;

  5. 從 L0 的第一個節點開始查詢,最終發現 12 這個節點,查詢結束。

如果要查詢的節點在 L0 中都不存在,則應返回並告知“該節點不存在”。

插入

要插入一個節點,不難想象首先需要查詢插入的位置,因此首先其實是類似的執行一次查詢。然后視情況定是做替換操作還是新增節點。插入的時候要利用一個隨機算法來獲取該元素要插入的層高,並根據“如果某個元素位於第 i 層,那該層一下的所有層也會包含此元素”這一特性,在要插入層和以下層中都要插入這個新元素。最后還要注意維護層高。以下是插入過程的一個示例:

刪除

刪除的第一步和插入很類似,首先要執行查找過程。如果查找到,則將該元素刪除。這里也必須注意“如果某個元素位於第 i 層,那該層一下的所有層也會包含此元素”這一特性。最后還要注意維護層高。

性能上,跳躍表支持平均 O(log N)、最壞 O(N) 復雜度的節點查找,還可以通過順序性操作來批量處理節點。

代碼實現在網上有很多代碼可以參考,且實現方法和細節也不盡相同,因此不在這里提及,而是更多的關注原理。有時候掌握基礎與原理其實更為重要。

本文的插圖來自於 William Pugh 關於跳躍表的論文《Skip Lists: A Probabilistic Alternative to Balanced Trees》,其中分析了跳躍表的實現及性能,值得研讀。

——————————

推薦閱讀:

說框架設計思路

老王說架構

一次性講透Activiti工作流

FaaS技術架構

華為Java編程軍規,每季度代碼驗收標准

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM