數據結構與算法分析(十一)跳錶

  1. 跳錶(Skip list):
  2. 它是一種各方面性能都比較優秀的動態數據結構,可以支持快速的插入、刪除、查找操作,寫起來也不復雜,甚至可以替代紅黑樹(Red-black tree)
  3. Redis 中的有序集合(Sorted Set)就是用跳錶來實現的。
  4. 對於一個單鏈表來講,即便鏈表中存儲的數據是有序的,如果我們要想在其中查找某個數據,也只能從頭到尾遍歷鏈表。這樣查找效率就會很低,時間複雜度會很高,是 O(n)。
  5. 鏈表加多級索引的結構,就是跳錶
  6. 每兩個結點會抽出一個結點作爲上一級索引的結點,那第一級索引的結點個數大約就是 n/2,第二級索引的結點個數大約就是 n/4,第三級索引的結點個數大約就是 n/8,依次類推
  7. 也就是說,第 k 級索引的結點個數是第 k-1 級索引的結點個數的 1/2,那第 k級索引結點的個數就是 n/(2k)。
  8. 什麼是跳錶?

  9. 爲一個值有序的鏈表建立多級索引,比如每2個節點提取一個節點到上一級,我們把抽出來的那一級叫做索引或索引層。如下圖所示,其中down表示down指針,指向下一級節點。以此類推,對於節點數爲n的鏈表,大約可以建立log2n-1級索引。像這種爲鏈表建立多級索引的數據結構就稱爲跳錶。

  10. 跳錶的時間複雜度?
    1.計算跳錶的高度
    如果鏈表有n個節點,每2個節點抽取抽出一個節點作爲上一級索引的節點,那第1級索引的節點個數大約是n/2,第2級索引的節點個數大約是n/4,依次類推,第k級索引的節點個數就是n/(2^k)。假設索引有h級別,最高級的索引有2個節點,則有n/(2^h)=2,得出h=log2n-1,包含原始鏈表這一層,整個跳錶的高度就是log2n。
    2.計算跳錶的時間複雜度
    假設我們在跳錶中查詢某個數據的時候,如果每一層都遍歷m個節點,那在跳錶中查詢一個數據的時間複雜度就是O(m*logn)。那這個m是多少呢?如下圖所示,假設我們要查找的數據是x,在第k級索引中,我們遍歷到y節點之後,發現x大於y,小於後面的節點z,所以我們通過y的down指針,從第k級下降到第k-1級索引。在第k-1級索引中,y和z之間只有3個節點(包含y和z),所以,我們在k-1級索引中最多隻需要遍歷3個節點,以此類推,每一級索引都最多隻需要遍歷3個節點。所以m=3。因此在跳錶中查詢某個數據的時間複雜度就是O(logn)。

  11. 跳錶的空間複雜度及如何優化?
    1.計算索引的節點總數
    如果鏈表有n個節點,每2個節點抽取抽出一個節點作爲上一級索引的節點,那每一級索引的節點數分別爲:n/2,n/4,n/8,…,8,4,2,等比數列求和n-1,所以跳錶的空間複雜度爲O(n)。
    2.如何優化時間複雜度
    如果鏈表有n個節點,每3或5個節點抽取抽出一個節點作爲上一級索引的節點,那每一級索引的節點數分別爲(以3爲例):n/3,n/9,n/27,…,27,9,3,1,等比數列求和n/2,所以跳錶的空間複雜度爲O(n),和每2個節點抽取一次相比,時間複雜度要低不少呢。

  12. 高效的動態插入和刪除?
    跳錶本質上就是鏈表,所以僅插作,插入和刪除操時間複雜度就爲O(1),但在實際情況中,要插入或刪除某個節點,需要先查找到指定位置,而這個查找操作比較費時,但在跳錶中這個查找操作的時間複雜度是O(logn),所以,跳錶的插入和刪除操作的是時間複雜度也是O(logn)。

  13. 跳錶索引動態更新?
    當往跳錶中插入數據的時候,可以選擇同時將這個數據插入到部分索引層中,那麼如何選擇這個索引層呢?可以通過隨機函數來決定將這個節點插入到哪幾級索引中,比如隨機函數生成了值K,那就可以把這個節點添加到第1級到第K級索引中。

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