跳錶

跳錶

跳錶概念

  1. 二分查找法依賴於數組的隨機訪問特性,只能用數組實現算法

    跳錶是基於鏈表實現相似於二分查找的算法數組

  2. 查找、插入、刪除各方面性能都不錯的動態數據結構,甚至能夠替代紅黑樹數據結構

  3. Redis 中的有序集合(Sorted Set)就是用跳錶來實現的函數

跳錶結構

  1. 對於一個有序的單鏈表,想在其中查找某個數據,只能從頭至尾遍歷鏈表。效率很低
  2. 對鏈表創建一級索引,每兩個結點提取一個結點到上一級,抽出來的一級稱爲索引層
  3. 索引層結點有指針指向下一級結點
  4. 在查找結點時,先在索引層遍歷,再降低到原始鏈表,就能減小遍歷次數
  5. 當鏈表很長,使用多級索引結構能夠大大提升查找效率

跳錶性能

跳錶的高度

  1. 第 k 級索引的結點個數是第 k-1 級索引的結點個數的 \(\frac{1}{2}\),那麼第 k 級索引 結點的個數就是 \(\frac{n}{2^k}\)
  2. 假設索引有 h 級,最高級的索引有 2 個結點。經過上面的公式,能夠獲得求得 \(h=log_2n-1\)
  3. 若是包含原始鏈表這一層,整個跳錶的高度就是 \(log_2n\)

查找時間複雜度

  1. 上級索引經過指針降低到下級索引性能

  2. 當每級索引都是兩個結點抽出一個結點做爲上一級索引的結點時,每一層最多遍歷3個結點spa

    時間複雜度爲 \(O(2*logn)\),即 \(O(logn)\)指針

  3. 若是每一層最多要遍歷 m 個結點,那麼時間複雜度爲 \(O(m*logn)\)對象

插入時間複雜度

  1. 在單鏈表中,若是知道要插入的位置,插入結點的時間複雜度是 \(O(1)\)索引

    爲了保證原始鏈表中數據的有序性,須要先找到要插入的位置,這個查找操做比較耗時內存

  2. 查找某個結點的的時間複雜度是 \(O(logn)\),查找某個數據應該插入的位置,時間複雜度也是 \(O(logn)\)

刪除時間複雜度

  1. 若是這個結點在索引中也有出現,咱們除了要刪除原始鏈表中的結點,還要刪除索引中的結點
  2. 刪除一個結點要找到其前驅結點,若是是雙向鏈表則能夠經過指針得到
  3. 時間複雜度爲 \(O(logn)\)

內存消耗

  1. 比起單鏈表,跳錶須要存儲多級索引,要消耗更多的存儲空間

  2. 若是將包含 n 個結點的單鏈表構形成跳錶,須要額外再用接近 n 個結點的存儲空間

  3. 每隔三個結點抽出一個結點比每隔兩個會節省索引存儲空間,但性能會降低

  4. 在實際的軟件開發中,原始鏈表中存儲的多是很大的對象

    而索引結點只須要存儲關鍵值和幾個指針,並不須要存儲對象

    因此當對象比索引結點大不少時,索引佔用的額外空間能夠忽略

索引動態更新

  1. 跳錶中插入數據,若是不更新索引,某 2 個索引結點之間數據過多,性能退化

  2. 跳錶是經過隨機函數來維護索引與原始鏈表大小之間的平衡

  3. 經過隨機函數,來決定將這個結點插入到哪幾級索引中

    好比隨機函數生成了值 K,就將這個結點添加到第一級到第 K 級索引中

    隨機函數的選取很重要,從機率上來說,可以保證跳錶的索引大小和數據大小平衡性,避免性能過分退化

相關文章
相關標籤/搜索