這是發生在不少年之前的故事......數據庫
幾天之前......數組
幾天以後......markdown
拍賣行的商品總數量有幾十萬件,對應數據庫商品表的幾十萬條記錄。數據結構
若是是按照商品名稱精確查詢還好辦,能夠直接從數據庫查出來,最多也就上百條記錄。ide
若是是沒有商品名稱的全量查詢怎麼辦?總不可能把數據庫裏的全部記錄全查出來吧,並且還要支持不一樣字段的排序。性能
因此,只能提早在內存中存儲有序的全量商品集合,每一種排序方式都保存成獨立的集合,每次請求的時候按照請求的排序種類,返回對應的集合。3d
好比按價格字段排序的集合:指針
好比按等級字段排序的集合:blog
須要注意的是,當時尚未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這種有序集合,正是對於跳躍表的改進和應用。
對於關係型數據庫如何維護有序的記錄集合呢?使用的是B+樹。有關B+樹的知識,將在之後的漫畫中詳細介紹。
小夥伴們,感謝支持!
—————END—————
喜歡本文的朋友們,歡迎長按下圖關注訂閱號夢見,收看更多精彩內容