redis跳錶之golang實現(1)

歡迎關注公衆號《後臺開發探索之旅》。

 

有序集合


日常開發經常需要對數據進行排序,針對不同的場景,採用特定的排序方法,比如:
(1)數組排序:將數值存入數組中,對數組進行冒泡、快排等排序方法,得到一個有序數組
(2)二叉搜索:構造二叉平衡樹,從根結點開始向左向右搜索,每次查找規模減半,最終找到目標節點
(3)最小根堆:同樣將數值存入數組中,對數組進行堆排序,保持最小值始終在堆頂,從而得到最小值
(4)有序鏈表:將數值存入鏈表中,保持鏈表有序,類似於數組

每一類數據結構都有其適合的場景,存在一些缺點,如下:
(1)數組排序:更新複雜度高,若插入首結點,後面所有元素都需要後移一位
(2)二叉搜索:只適合查找和更新,不能獲取排序列表
(3)最小根堆:只適合獲取最小值
(4)有序鏈表:查找複雜度高,每次都需要從頭遍歷

理想的有序集合是:
(1)查找、插入、刪除的複雜度都小於O(N),即不需要遍歷所有結點
(2)可以獲取排序列表,以及某個結點的排名
(3)可以根據數值查找排名,也可以根據排名查找數值

跳錶(skiplist)就可以滿足這些苛刻的要求,付出的代價是增加一倍的空間消耗,典型的空間換時間。

 

跳錶原理

跳錶實際上是在有序鏈表的基礎上實現的,比如有數值1~10,用有序鏈表表示就是:
1,2,3,4,5,6,7,8,9,10

有序鏈表的缺點是每次都要從頭遍歷,比如查找9,要從1開始查找,那麼能不能跳着查找,比如1,3,5,7,9這種方式呢,增加1層鏈表:
1,3,5,7,10
1,2,3,4,5,6,7,8,9,10

先從第2層開始查找,順序爲1,3,5,7,後面是10,不能繼續向右了,進入下一層,從7接着向右,找到8,9

如果數據量特別大,有幾百萬條數據,還是很慢,能不能再快點,可以的,增加層數到20層,每次從20層開始,本層查找完畢,進入下一層繼續查找。

當跳錶設置爲25層時,無論數據量有多大,查找次數穩定在50次以內,性能非常優秀。

 

redis的跳錶實現


redis基於自身功能需求,擴展了跳錶的功能。每個元素有name和score兩個屬性,name是元素唯一標識符,根據score排序。支持以下操作:
(1)插入name和score,name不能相同,score可以相同; 先根據score排序,若score相同,根據name排序
(2)根據name,刪除元素,獲取元素score,獲取元素rank排名
(3)獲取指定score區間的元素排序列表; 比如傳入1和5,返回1,2,3,4,5
(4)獲取指定rank區間的元素排序列表; 比如獲取前10名的元素列表

 

golang實現


考慮到redis跳錶的強大,用golang實現了其功能,項目地址爲:
https://github.com/throne-developer/skiplist

測試代碼:

func TestSkipListSimple(t *testing.T) {
    sl := New()

    sl.Insert("A", 1)
    sl.Insert("B", 2)
    sl.Insert("C", 3)
    sl.Insert("D1", 6)
    sl.Insert("D2", 6)
    sl.Insert("D3", 6)

    if elem := sl.Find("D1"); elem != nil {
        fmt.Println("Find D1, score=", elem.Score())
    }

    if rank, ok := sl.GetRank("D1"); ok {
        fmt.Println("D1 rank is ", rank)
    }

    if score, ok := sl.GetScore("D1"); ok {
        fmt.Println("D1 score is ", score)
    }

    if elem := sl.FindByRank(5); elem != nil {
        fmt.Println("FindByRank 5, name=", elem.Name())
    }

    for elem := sl.FindGreaterOrEqual(3); elem != nil; elem = elem.Next() {
        fmt.Println("FindGreaterOrEqual 3, name=", elem.Name())
    }

    sl.Delete("A")
}

在此接口基礎上做簡單的封裝,即可實現redis的zset命令,下一篇將介紹golang版本的skiplist內部實現機制。

 

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