漫畫 | 什麼是跳躍表?

轉自:https://baijiahao.baidu.com/s?id=1571323359136961&wfr=spider&for=pc

幾天以前......

幾天之後......

拍賣行的商品總數量有幾十萬件,對應數據庫商品表的幾十萬條記錄。

如果是按照商品名稱精確查詢還好辦,可以直接從數據庫查出來,最多也就上百條記錄。

如果是沒有商品名稱的全量查詢怎麼辦?總不可能把數據庫裏的所有記錄全查出來吧,而且還要支持不同字段的排序。

所以,只能提前在內存中存儲有序的全量商品集合,每一種排序方式都保存成獨立的集合,每次請求的時候按照請求的排序種類,返回對應的集合。

比如按價格字段排序的集合:

比如按等級字段排序的集合:

需要注意的是,當時還沒有Redis這樣的內存數據庫,所以小灰只能自己實現一套合適的數據結構來存儲。

拍賣行商品列表是線性的,最容易表達線性結構的自然是數組和鏈表。可是,無論是數組還是鏈表,在插入新商品的時候,都會存在性能問題。

按照商品等級排序的集合爲例,如果使用數組,插入新商品的方式如下:

如果要插入一個等級是3的商品,首先要知道這個商品應該插入的位置。使用二分查找可以最快定位,這一步時間複雜度是O(logN)。

插入過程中,原數組中所有大於3的商品都要右移,這一步時間複雜度是O(N)。所以總體時間複雜度是O(N)。

如果使用鏈表,插入新商品的方式如下:

如果要插入一個等級是3的商品,首先要知道這個商品應該插入的位置。鏈表無法使用二分查找,只能和原鏈表中的節點逐一比較大小來確定位置。這一步的時間複雜度是O(N)。

插入的過程倒是很容易,直接改變節點指針的目標,時間複雜度O(1)。因此總體的時間複雜度也是O(N)。

這對於擁有幾十萬商品的集合來說,這兩種方法顯然都太慢了。

——————————————

新節點和各層索引節點逐一比較,確定原鏈表的插入位置。O(logN)

把索引插入到原鏈表。O(1)

利用拋硬幣的隨機方式,決定新節點是否提升爲上一級索引。結果爲“正”則提升並繼續拋硬幣,結果爲“負”則停止。O(logN)

總體上,跳躍表插入操作的時間複雜度是O(logN),而這種數據結構所佔空間是2N,既空間複雜度是 O(N)。

自上而下,查找第一次出現節點的索引,並逐層找到每一層對應的節點。O(logN)

刪除每一層查找到的節點,如果該層只剩下1個節點,刪除整個一層(原鏈表除外)。O(logN)

總體上,跳躍表刪除操作的時間複雜度是O(logN)。

小灰和大黃並不知道,他們的這一解決方案和若干年後Redis當中的Sorted-set不謀而合。而Sorted-set這種有序集合,正是對於跳躍表的改進和應用。

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