跳表是乙個隨機化的資料結構,實質就是一種可以進行二分查詢的有序鍊錶。
跳表在原有的有序鍊錶上面增加了多級索引,通過索引來實現快速查詢。
跳表不僅能提高搜尋效能,同時也可以提高插入和刪除操作的效能。
考慮乙個有序鍊錶,我們要查詢3、7、17這幾個元素,我們只能從頭開始遍歷鍊錶,直到查詢到元素為止。
上述這個鍊錶是有序的,但是不能使用二分查詢,是不是很捉急?(p.s.陣列可以實現二分查詢)
那麼,有沒有什麼方法可以實現有序鍊錶的二分查詢呢?
答案是肯定的,那就是我們將要介紹的這種資料結構——跳表。
我們把一些節點從有序表中提取出來,快取一級索引,就組成了下面這樣的結構:
現在,我們要查詢17這個元素是不是要快很多呢?
我們只要從一級索引往後遍歷即可,只需要經過1、6、15、17這幾個元素就可以找到17了。
那麼,我們要查詢11這個元素呢?
我們從一級索引的1開始,向右到6,再向右發現是15,它比11大,此路不通,從6往下走,再從下面的6往右走,到7,再到11。
同樣地,一級索引也可以往上再提取一層,組成二級索引,如下:
這時候我們再查詢17這個元素呢?
只需要經過6、15、17這幾個元素就可以找到17了。
這基本上就是跳表的核心思想了,其實這也是乙個「空間換時間」的演算法,通過向上提取索引增加了查詢的效率。
上面講的都是跳表的查詢,那麼,該如何向跳表中插入元素呢?
比如,我們要向上面這個跳表新增乙個元素8。
首先,我們先根據投硬幣的方式,決定8這個元素要佔據的層數,沒錯就是扔硬幣,是不是很好玩兒^^
比如,層數level=2。
然後,找到8這個元素在下面兩層的前置節點。
接著,就是鍊錶的插入元素操作了,比較簡單。
最後,就像下面這樣:
查詢、插入元素都講了,下面我們就來說說怎麼刪除元素。
首先,找到各層中包含元素x的節點。
然後,使用標準的鍊錶刪除元素的方法刪除即可。
比如,要刪除17這個元素。
上面舉的例子是完全隨機的跳表,那麼,如果我們每兩個元素提取乙個元素作為上一級的索引會怎麼樣呢?
這是不是很像平衡二叉樹,現在這顆樹元素比較少,可能不太明顯,我們來看個元素個數多的情況。
我們知道單鏈表查詢的時間複雜度為o(n),而插入、刪除操作需要先找到對應的位置,所以插入、刪除的時間複雜度也是o(n)。
那麼,跳表的時間複雜度是多少呢?
如果按照標準的跳表來看的話,每一級索引減少k/2個元素(k為其下面一級索引的個數),那麼整個跳表的高度就是(log n)。
學習過平衡二叉樹的同學都知道,它的時間複雜度與樹的高度成正比,即o(log n)。
所以,這裡跳表的時間複雜度也是o(log n)。(這裡不一步步推倒了,只要記住,查詢時每次減少一半的元素的時間複雜度都是o(log n),比如二叉樹的查詢、二分法查詢、歸併排序、快速排序)
我們還是以標準的跳表來分析,每兩個元素向上提取乙個元素,那麼,最後額外需要的空間就是:
n/2 + n/(2^2) + n/(2^3) + ... + 8 + 4 + 2 = n - 2
所以,跳表的空間複雜度是o(n)。
(1)跳表是可以實現二分查詢的有序鍊錶;
(2)每個元素插入時隨機生成它的level;
(3)最低層包含所有的元素;
(4)如果乙個元素出現在level(x),那麼它肯定出現在x以下的level中;
(5)每個索引節點包含兩個指標,乙個向下,乙個向右;
(6)跳表查詢、插入、刪除的時間複雜度為o(log n),與平衡二叉樹接近;
為什麼redis選擇使用跳表而不是紅黑樹來實現有序集合?
首先,我們來分析下redis的有序集合支援的操作:
1)插入元素
2)刪除元素
3)查詢元素
4)有序輸出所有元素
5)查詢區間內所有元素
其中,前4項紅黑樹都可以完成,且時間複雜度與跳表一致。
但是,最後一項,紅黑樹的效率就沒有跳表高了。
在跳表中,要查詢區間的元素,我們只要定位到兩個區間端點在最低層級的位置,然後按順序遍歷元素就可以了,非常高效。
而紅黑樹只能定位到端點後,再從首位置開始每次都要查詢後繼節點,相對來說是比較耗時的。
此外,跳表實現起來很容易且易讀,紅黑樹實現起來相對困難,所以redis選擇使用跳表來實現有序集合。
關於redis中Zset元素的使用
zset在set基礎上增加了乙個排序 權值 需手動指定,分數越小,越排前面 zadd zadd name 序號 value 序號2 value2 依據序號的重要程度排序 zrange zrange name start end 查詢zset中的元素,預設從小到大排序,若要從大到小,使用zrevran...
使用redis中的zset實現實時排行榜
redis在業務開發中會被頻繁使用,zset是其中一種特殊用法,zset具排行榜的天然特性,我前幾個月在一次開發中使用到了zset,就是因為涉及到要實現乙個排行榜,那是我第一次用到zset,雖然之前都看過redis幾種資料型別的資料結構及其使用方法,但是真正用起來的時候,還是有一些細節的東西要處理的...
用Redis中的zset實現乙個限流器
我還記得14年搶紅公尺的時候,下面這個圖是我最煩的乙個圖 搶了兩個星期,才終於買到了我的第一台小公尺手機 紅公尺1s。小公尺 加入了乙個排隊的機制,於是我們可以感知到自己被限流了,但大部分服務,比如最近各大電商的搶茅台活動,並沒有讓我們感知到限流,不管你是手速不夠還是被限流,都會給你返回 很遺憾,已...