6、Redis系統-數據結構-06-跳表

六、跳表(Skiplist)

跳表是一種高效的動態數據結構,可以用于實現有序集合(Sorted Set,Zset)。與平衡樹相比,跳表具有實現簡單、效率高的優點,因此被 Redis 選用作為有序集合的底層數據結構之一。

1. 跳表的結構設計

跳表通過多級鏈表的形式實現,每一級鏈表都跳過一些元素,從而在查詢時能夠快速跳過不必要的元素。跳表的每個節點包含一個或多個前進指針,這些前進指針指向不同級別的節點,使得跳表具有高效的查詢性能。

節點結構

跳表節點的結構定義如下:

typedef?struct?zskiplistNode?{struct?zskiplistNode?*backward;?// 后退指針,指向前一個節點double?score;???????????????????// 節點的分值,用于排序sds ele;????????????????????????// 節點的元素struct?zskiplistLevel?{struct?zskiplistNode?*forward;?// 前進指針,指向下一個節點unsigned?int?span;?????????????// 跨度,表示當前節點和下一個節點之間的距離} level[];?// 按級別劃分的前進指針數組
} zskiplistNode;
跳表結構

跳表的結構定義如下:

typedef?struct?zskiplist?{struct?zskiplistNode?*header, *tail;?// 跳表的頭節點和尾節點unsigned?long?length;????????????????// 跳表的長度,即節點數量int?level;???????????????????????????// 跳表的最大級別
} zskiplist;
2. 跳表的操作

跳表支持多種操作,包括插入、刪除、查找等。以下是一些常見操作的實現示例:

插入操作

插入新節點時,首先確定新節點的級別,然后在每一級鏈表中找到插入位置,將新節點插入到相應的位置。

zskiplistNode *zslInsert(zskiplist *zsl,?double?score, sds ele)?{zskiplistNode *update[ZSKIPLIST_MAXLEVEL];unsigned?int?rank[ZSKIPLIST_MAXLEVEL];int?i, level;zskiplistNode *x;x = zsl->header;for?(i = zsl->level-1; i >=?0; i--) {rank[i] = i == (zsl->level-1) ??0?: rank[i+1];while?(x->level[i].forward &&?(x->level[i].forward->score < score ||?(x->level[i].forward->score == score &&?sdscmp(x->level[i].forward->ele,ele) <?0))) {rank[i] += x->level[i].span;x = x->level[i].forward;}update[i] = x;}level = zslRandomLevel();if?(level > zsl->level) {for?(i = zsl->level; i < level; i++) {rank[i] =?0;update[i] = zsl->header;update[i]->level[i].span = zsl->length;}zsl->level = level;}x = zslCreateNode(level,score,ele);for?(i =?0; i < level; i++) {x->level[i].forward = update[i]->level[i].forward;update[i]->level[i].forward = x;x->level[i].span = update[i]->level[i].span - (rank[0] - rank[i]);update[i]->level[i].span = (rank[0] - rank[i]) +?1;}for?(i = level; i < zsl->level; i++) {update[i]->level[i].span++;}x->backward = (update[0] == zsl->header) ??NULL?: update[0];if?(x->level[0].forward)?x->level[0].forward->backward = x;elsezsl->tail = x;zsl->length++;return?x;
}
查找操作

在跳表中查找目標節點時,從最高級別的鏈表開始,通過前進指針逐級向下查找,直到找到目標節點或確認目標節點不存在。

zskiplistNode *zslFind(zskiplist *zsl,?double?score, sds ele)?{zskiplistNode *x;int?i;x = zsl->header;for?(i = zsl->level-1; i >=?0; i--) {while?(x->level[i].forward &&?(x->level[i].forward->score < score ||?(x->level[i].forward->score == score &&?sdscmp(x->level[i].forward->ele,ele) <?0))) {x = x->level[i].forward;}}x = x->level[0].forward;if?(x && score == x->score && sdscmp(x->ele,ele) ==?0) {return?x;}?else?{return?NULL;}
}
刪除操作

刪除節點時,通過查找操作確定節點位置,然后在每一級鏈表中移除該節點,并調整相關節點的前進指針和跨度。

int?zslDelete(zskiplist *zsl,?double?score, sds ele, zskiplistNode **node)?{zskiplistNode *update[ZSKIPLIST_MAXLEVEL];zskiplistNode *x;int?i;x = zsl->header;for?(i = zsl->level-1; i >=?0; i--) {while?(x->level[i].forward &&?(x->level[i].forward->score < score ||?(x->level[i].forward->score == score &&?sdscmp(x->level[i].forward->ele,ele) <?0))) {x = x->level[i].forward;}update[i] = x;}x = x->level[0].forward;if?(x && score == x->score && sdscmp(x->ele,ele) ==?0) {for?(i =?0; i < zsl->level; i++) {if?(update[i]->level[i].forward == x) {update[i]->level[i].span += x->level[i].span -?1;update[i]->level[i].forward = x->level[i].forward;}?else?{update[i]->level[i].span -=?1;}}if?(x->level[0].forward) {x->level[0].forward->backward = x->backward;}?else?{zsl->tail = x->backward;}while?(zsl->level >?1?&& zsl->header->level[zsl->level-1].forward ==?NULL)zsl->level--;zsl->length--;if?(node) *node = x;else?zslFreeNode(x);return?1;}?else?{return?0;}
}
3. 跳表的優點
  1. 高效查詢:跳表的查詢性能接近于平衡樹,時間復雜度為 O(log N)。
  2. 實現簡單:與紅黑樹等平衡樹相比,跳表的實現相對簡單,容易理解和維護。
  3. 動態調整:跳表能夠高效地進行插入和刪除操作,同時保持整體結構的有序性。
4. 跳表的使用示例

以下是一些使用 Redis 跳表實現有序集合的示例,展示了如何利用跳表進行數據的存儲和操作。

插入數據

ZADD myzset 1?"one"
ZADD myzset 2?"two"
ZADD myzset 3?"three"

獲取數據

ZRANGE myzset 0 -1 WITHSCORES
# 1) "one"
# 2) "1"
# 3) "two"
# 4) "2"
# 5) "three"
# 6) "3"

刪除數據

ZREM myzset?"two"
ZRANGE myzset 0 -1 WITHSCORES
# 1) "one"
# 2) "1"
# 3) "three"
# 4) "3"
結論

通過上述解析,我們可以更好地理解跳表的設計思想和實現原理,從而在實際開發中更好地利用跳表提供的優勢。在 Redis 中,跳表通過高效的多級鏈表結構,實現了有序集合的快速插入、刪除和查詢操作,適用于需要有序數據存儲的場景。了解跳表的內部實現,可以幫助我們在實際應用中更好地利用 Redis 的性能和功能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/42373.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/42373.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/42373.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

階段三:項目開發---搭建項目前后端系統基礎架構:任務13:實現基本的登錄功能

任務描述 任務名稱&#xff1a; 實現基本的登錄功能 知識點&#xff1a; 了解前端Vue項目的基本執行過程 重 點&#xff1a; 構建項目的基本登陸功能 內 容&#xff1a; 通過實現項目的基本登錄功能&#xff0c;來了解前端Vue項目的基本執行過程&#xff0c;并完成基…

如何讓代碼兼容 Python 2 和 Python 3?Future 庫助你一臂之力

目錄 01Future 是什么? 為什么選擇 Future? 安裝與配置 02Future 的基本用法 1、兼容 print 函數 2、兼容整數除法 3、兼容 Unicode 字符串 03Future 的高級功能 1. 處理字符串與字節 2. 統一異常處理…

linux kthread任務管理

目錄 一、linux 創建內核線程1.1 kthread_create1.2 kthread_create_worker kthread_queue_work 二、設置線程優先級和調度策略2.1 sched_setscheduler2.2 調度策略 一、linux 創建內核線程 1.1 kthread_create 在 linux 中&#xff0c;可以使用 kthread_create 接口創建內核…

移動校園(7)ii:uniapp路由響應攔截器處理token,以及微信小程序報錯當前頁面正在處于跳轉狀態,請稍后再進行跳轉....

依據昨天的寫完&#xff0c;在token過期之后&#xff0c;再次調用接口&#xff0c;會觸發后端攔截&#xff0c;扔進全局錯誤處理中間件 前端說明提示都沒有&#xff0c;只有一個這個&#xff0c;現在優化一下&#xff0c;再寫一個類似全局后置守衛&#xff0c;當狀態碼是401的時…

MySQL——數據連接池

數據庫連接 --- 執行完畢 --- 釋放&#xff08;連接到釋放的過程十分浪費系統資源&#xff09; 池化技術&#xff1a;準備一些預先的資源&#xff0c;過來就連接預先準備好的 編寫連接池&#xff0c;實現一個接口 DataSource 開源數據源實現&#xff08;拿來即用&#xff09;…

增強安全防護,解讀智慧校園系統的登錄日志功能

在構建智慧校園系統時&#xff0c;登錄日志功能扮演著不可或缺的角色&#xff0c;它不僅是系統安全的守護者&#xff0c;也是提升管理效率和確保合規性的有力工具。這一機制詳細記錄每次登錄嘗試的方方面面&#xff0c;涵蓋了時間戳、用戶身份、登錄來源的IP地址乃至使用的設備…

phpcms 升級php8.3.8

windows 2008 server 不支持php8.3.8,需升級為windows 2012 1.下載php8.3.8 PHP8.3.9 For Windows: Binaries and sources Releases 2.配置php.ini (1.)在php目錄下找到php.ini-development文件&#xff0c;把它復制一份&#xff0c;改名為php.ini (2.)修改php安裝目錄 根…

《昇思 25 天學習打卡營第 10 天 | ResNet50 遷移學習 》

《昇思 25 天學習打卡營第 10 天 | ResNet50 遷移學習 》 活動地址&#xff1a;https://xihe.mindspore.cn/events/mindspore-training-camp 簽名&#xff1a;Sam9029 使用遷移學習進行狼狗圖像分類 簡介 在機器學習和深度學習中&#xff0c;我們經常面臨數據不足的問題。 遷…

python【文件操作】

文件操作 一、創建文件夾二、文件操作模式1.覆蓋寫入2.讀取3.追加 三、 Python腳本在文件中查找和替換文本四、 python清空文件夾 一、創建文件夾 判斷文件或者文件夾是否存在 import ospathrD://測試文件夾 if not os.path.exists(path):os.mkdir(path)print(os.path.exists…

C++模板元編程(二)——完美轉發

完美轉發指的是函數模板可以將自己的參數“完美”地轉發給內部調用的其它函數。所謂完美&#xff0c;即不僅能準確地轉發參數的值&#xff0c;還能保證被轉發參數的左、右值屬性不變。 文章目錄 場景舊的方法新的方法內部實現參考文獻 場景 思考下面的代碼&#xff1a; templ…

高防服務器的重要性

在數字化時代&#xff0c;網絡安全已成為企業和個人最為關注的問題之一。隨著網絡攻擊的日益頻繁和復雜&#xff0c;傳統的服務器租用服務已難以滿足高安全需求的市場。高防服務器租用應運而生&#xff0c;成為保護網絡安全的重要解決方案。本文將探討高防服務器租用的概念、重…

專業140+總分420+天津大學815信號與系統考研經驗天大電子信息與通信工程,真題,大綱,參考書。

順利上岸天津大學&#xff0c;專業課815信號與系統140&#xff0c;總分420&#xff0c;總結一些自己的復習經歷&#xff0c;希望對于報考天大的同學有些許幫助&#xff0c;少走彎路&#xff0c;順利上岸。專業課&#xff1a; 815信號與系統&#xff1a;指定教材吳大正&#xf…

2-26 基于matlab開發的制冷循環模型

基于matlab開發的制冷循環模型。Simscape兩相流域中的制冷循環模型&#xff0c;在simulink中完成多循環溫度控制。程序已調通&#xff0c;可直接運行。 2-26 制冷循環模型 Simscape兩相流域 - 小紅書 (xiaohongshu.com)

Arduino ESP8266 開發環境搭建

Arduino ESP8266 開發環境搭建 很久之前學嵌入式時&#xff0c;用過Arduino8266進行開發&#xff0c;開發成本低、難度小&#xff0c;體驗很不錯。 近期&#xff0c;又突然要用&#xff0c;遂再次搭建環境&#xff0c;但變動挺多&#xff0c;有些小波折&#xff0c;開貼記錄。…

生成式AI應用實列和價值鏈

生成式AI應用實列和價值鏈 生成式AI應用實列ChatGPTGeminiGitHub CopilotSynthesia 價值鏈 生成式AI應用實列 ChatGPT ChatGPT 并不是生成式 AI 行業中唯一的公司。 Stability AI 的 Stable Diffusion 可以根據文本描述生成圖像&#xff0c;發布后 90 天內&#xff0c;在 Git…

vue是如何進行監聽數據變化的?vue2和vue3分別是什么,vue3為什么要更換

在 Vue 中&#xff0c;數據變化的監聽是通過響應式系統來實現的。Vue 2.x 和 Vue 3 在這方面有一些區別。 Vue 2.x 的數據監聽 Vue 2.x 使用的是 Object.defineProperty() 方法來實現數據的響應式。當你聲明一個 Vue 實例的數據對象時&#xff0c;Vue 將遍歷這個對象的屬性&a…

清除屏幕上信息的命令clear

清除屏幕上信息的命令clear There is no nutrition in the blog content. After reading it, you will not only suffer from malnutrition, but also impotence. The blog content is all parallel goods. Those who are worried about being cheated should leave quickly. 清…

高考志愿填報千萬要注意這四點

在高考志愿填報過程中&#xff0c;確實有很多需要留心的點。我為你總結了四個關鍵點&#xff0c;希望能幫助你順利完成志愿填報&#xff1a; 1、學校提供的支持 學校作為學生志愿填報咨詢服務的主陣地&#xff0c;應提供體系化和制度化的支持。包括及時關注并傳達政策動向和相…

行內元素、塊級元素居中

行內元素居中 水平居中 {text-align&#xff1a;center;}垂直居中 單行——行高等于盒子高度 <head><style>.father {width: 400px;height: 200px;/* 行高等于盒子高度&#xff1a;line-height: 200px; */line-height: 200px;background-color: pink;}.son {}&…

如何做好IT類的技術面試?

我們在找工作時&#xff0c;需要結合自己的現狀&#xff0c;針對意向企業做好充分準備。作為程序員&#xff0c;你有哪些面試IT技術崗的技巧&#xff1f; 方向一&#xff1a;分享你面試IT公司的小技巧 我分享一些基于廣泛觀察和用戶反饋的面試IT公司的小技巧&#xff1a; 技術準…