数据结构三——跳表
文章出處:極客時間《數(shù)據(jù)結(jié)構(gòu)和算法之美》-作者:王爭。該系列文章是本人的學(xué)習(xí)筆記。
跳表的由來
說明:圖片來自極客時間
由來
二分查找的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,利用數(shù)組隨機訪問的特定查找的時間復(fù)雜度是O(logn)。如果數(shù)據(jù)結(jié)構(gòu)是鏈表,可以達(dá)到這樣的速度嗎?答案是可以的。只是要改造。改造之后的結(jié)構(gòu)就是跳表,是一種動態(tài)數(shù)據(jù)結(jié)構(gòu),可以支持快速的插入、刪除、查找、按范圍查找。功能類似于紅黑樹。Redis中的有序集合使用的就是跳表。
跳表的結(jié)構(gòu)
對于單鏈表來說,存儲的數(shù)據(jù)是有序的,想要查找某個數(shù),時間復(fù)雜度是O(n)。如果對單鏈表建一個一級“索引”,就是說每兩個節(jié)點提取一個節(jié)點。提取出的節(jié)點有一個down指針指向原始鏈表中的同一個節(jié)點。
現(xiàn)在要查找數(shù)據(jù)16,那么查找路徑是:1,4,7,9,13,13(原始鏈表),16。查找7個節(jié)點。單鏈表查找16需要查找10個節(jié)點。
如果對一級索引再建“索引”,形成二級索引。
現(xiàn)在要查找數(shù)據(jù)16,那么查找路徑是:1,7,13,13,13,16。查找6個節(jié)點。
當(dāng)n小的時候,減少的節(jié)點數(shù)量不明顯。如果是n=64。建5級索引。
現(xiàn)在查找62需要11個節(jié)點,路徑是1,33,33,49,49,57,57,61,61,61,62。原來需要62個節(jié)點。提升效果很明顯。當(dāng)n越大,提升效果越明顯。
跳表=鏈表+多級索引
跳表的時空復(fù)雜度
時間復(fù)雜度
當(dāng)節(jié)點個數(shù)為n的時候,跳表會建幾層索引呢?第1級索引節(jié)點個數(shù)n2\dfrac{n}{2}2n?,第2級索引節(jié)點個數(shù)n4\dfrac{n}{4}4n?,第k級索引節(jié)點個數(shù)n2k\dfrac{n}{2^k}2kn?。最上面一層索引節(jié)點個數(shù)是2。也就是說2=n2l2=\dfrac{n}{2^l}2=2ln?,l+1=log2nl+1=log_2nl+1=log2?n,l=log2n?1l=log_2n-1l=log2?n?1。再加上原始鏈表層,跳表有log2nlog_2nlog2?n層,記為logn。
每一層最多查詢的節(jié)點個數(shù)是3。因為在建每一層索引的時候,是每2個數(shù)據(jù)建一個節(jié)點。例如查找數(shù)據(jù)x,在第k層發(fā)現(xiàn)y<x,x>zy<x,x>zy<x,x>z,所以通過y的down指針向,從第k層走到第k-1層。而y和z節(jié)點之間最多有3個節(jié)點(包含y和z)。
那么跳表的時間復(fù)雜度就是O(logn)。和二分查找是同樣的查找效率。
空間復(fù)雜度
鏈表的查找速度和二分一樣,這是需要付出空間代價的。也就是以空間換時間。那么額外需要多少空間呢?n2+n4+n8+...+2=n\dfrac{n}{2}+\dfrac{n}{4}+\dfrac{n}{8}+...+2=n2n?+4n?+8n?+...+2=n,等比數(shù)列求和。所以空間復(fù)雜度是O(n)。
跳表插入和刪除
插入
對于插入來講,為了維持鏈表的有序性,在插入一個數(shù)據(jù)的時候需要先查找到插入的位置。
例如在鏈表中插入6,需要查找插入位置,查找節(jié)點1,1,4,4,5,時間復(fù)雜度和查找一個數(shù)字類似,O(logn)。鏈表的插入操作是O(1),所以整體插入操作時間復(fù)雜度O(logn)。
刪除
刪除操作不僅要刪除鏈表層,同時需要刪除索引層的節(jié)點。時間復(fù)雜度O(logn)。
動態(tài)索引表更新
索引更新
當(dāng)不斷插入數(shù)據(jù)的時候,如果不更新索引層,極端情況下跳表退化為單鏈表。當(dāng)插入數(shù)據(jù)的時候,同時更新某些索引層。至于在哪些層建索引,可以通過隨機函數(shù)來選擇。
思考題
1 redist為什么使用跳表而不是紅黑樹?
redist的核心操作是:
插入一個數(shù)據(jù);
刪除一個數(shù)據(jù);
查找一個數(shù)據(jù);
按范圍查找一個區(qū)間內(nèi)的數(shù)據(jù);
迭代輸出有序序列
紅黑樹效率不高的操作是:按范圍查找一個區(qū)間內(nèi)的數(shù)據(jù)。
其他原因:跳表更容易實現(xiàn),代碼比較簡單。
2 如果每3個或者5個節(jié)點抽取一個做索引,那么跳表的時間復(fù)雜度和空間復(fù)雜度是多少呢?
如果每三個或者五個節(jié)點提取一個節(jié)點作為上級索引,那么對應(yīng)的查詢數(shù)據(jù)時間復(fù)雜度,也還是 O(logn)。其實這里的底數(shù)已經(jīng)不是2,而是3或者5。
空間復(fù)雜度,也依然是一個等比數(shù)列的和:n3+n9+n8+...+3=32(n?1)\dfrac{n}{3}+\dfrac{n}{9}+\dfrac{n}{8}+...+3=\dfrac{3}{2}(n-1)3n?+9n?+8n?+...+3=23?(n?1),記為O(n)。
總結(jié)
- 上一篇: 修改锁的公平性
- 下一篇: Eclipse更改字体大小