Redis 的跳躍表:像商場多層導航系統一樣的有序結構

目錄

一 、從 "超市貨架" 的痛點看跳躍表的價值

1.1、跳躍表與商場導航系統的結構對應

1. 1.1、zskiplistNode:帶導航標記的 "商品"(跳躍表節點)

1.1.1.1、level []:商品上的多層導航標記

1.1.1.2、backward:商品的 "后退箭頭"

1.1.1.3、score:商品的 "價格標簽"

1.1.1.4、obj:商品的 "名稱牌"(銜接 SDS!)

1.1.2、zskiplist:商場的 "總服務臺"(跳躍表管理結構)

二、跳躍表的工作流程:像顧客找商品一樣簡單

三、設計細節:為什么跳躍表要這樣設計?

3.1、節點層數為什么隨機?——"熱門商品多掛導航"

3.2、為什么不用平衡樹?——"導航系統比復雜樹狀圖更實用"

3.3、與之前結構的配合:Redis 的 "結構組合拳"

四、總結:跳躍表的設計智慧


如果說 SDS 是 "智能價簽"、鏈表是 "貨架"、字典是 "儲物柜",那么跳躍表就是 Redis 為 "有序商品展示" 設計的商場多層導航系統。當你需要按價格排序展示商品(如電商 APP 的 "價格從低到高"),或者記錄游戲排名這類需要快速定位和范圍查詢的場景時,跳躍表就會像商場的多層導視圖一樣,讓你不用逐個瀏覽就能快速找到目標。

一 、從 "超市貨架" 的痛點看跳躍表的價值

假設你在超市的 "零食區" 貨架上按價格排序擺放著商品:

薯片(5元) → 巧克力(10元) → 牛肉干(15元) → 堅果(20元) → ... → 進口禮盒(100元)

這本質上是一個有序鏈表(類似我們之前講的 list 結構),但有個明顯問題:如果想找 "30 元左右的商品",你必須從第一個商品開始逐個查看 —— 就像顧客在貨架前從頭走到尾,效率很低(時間復雜度 O (N))。

超市為了解決這個問題,會在貨架上方加多層導航牌

  • 地面層(對應貨架本身):每個商品都能看到
  • 中層導航(2 米高):每隔 5 個商品標一個價格區間(如 "5-15 元區→15-30 元區→...")
  • 高層導航(5 米高):標注大區間(如 "0-50 元區→50-100 元區")

這種設計讓顧客先看高層導航定位大致區域,再通過中層導航縮小范圍,最后在地面層精確查找 —— 這就是跳躍表的核心思路:用多層索引實現 "跳著找",把復雜度從 O (N) 降到平均 O (logN)。

1.1、跳躍表與商場導航系統的結構對應

Redis 的跳躍表結構與商場導航系統的對應關系非常直觀,我們結合之前學過的結構知識逐層拆解:

1. 1.1、zskiplistNode:帶導航標記的 "商品"(跳躍表節點)

每個商品就像一個跳躍表節點,不僅有自身信息,還帶著多層導航標記:

typedef struct zskiplistNode {// 層(多層導航標記)struct zskiplistLevel {struct zskiplistNode *forward; // 前進指針(指向遠處的商品)unsigned int span;             // 跨度(中間隔了多少個商品)} level[];// 后退指針(只能回到前一個商品)struct zskiplistNode *backward;// 分值(商品價格,排序依據)double score;// 成員對象(商品名稱,用SDS存儲)robj *obj;
} zskiplistNode;
1.1.1.1、level []:商品上的多層導航標記
  • 這是跳躍表的核心,每個level元素對應一層導航。比如level[0]是 "地面層導航"(必有的基礎層),level[1]是 "中層導航",level[2]是 "高層導航"(最多 32 層)。
  • forward 指針:就像商品上貼的 "前方 50 米有 30 元區" 標簽,直接指向遠處的目標節點。比如在 "15 元牛肉干" 的中層導航(level [1])上,forward 可能直接指向 "30 元餅干",跳過中間的 20 元、25 元商品。
  • span(跨度):記錄兩個節點之間的 "間隔數"。比如從 15 元牛肉干到 30 元餅干中間有 3 個商品,span 就等于 3—— 這就像導航標簽上寫著 "中間有 3 個商品",能快速計算排名(比如知道 15 元是第 3 名,span=3,30 元就是第 6 名)。
1.1.1.2、backward:商品的 "后退箭頭"
  • 每個節點只有一個 backward 指針,只能指向 "前一個節點",就像貨架上的 "返回上一個商品" 箭頭,顧客看完當前商品想回頭,只能一步一步往回走(不能跳)。這和鏈表的 prev 指針功能類似,但跳躍表的 forward 指針能跳,backward 不能 —— 因為后退場景少,沒必要浪費空間做多層后退索引。
1.1.1.3、score:商品的 "價格標簽"
  • score是排序的依據(必須有序),就像商品按價格從小到大排列。在 Redis 的有序集合中,比如ZADD goods 5 "chip" 10 "chocolate",這里的 5 和 10 就是 score。
1.1.1.4、obj:商品的 "名稱牌"(銜接 SDS!)
  • obj存儲的是成員名稱(如 "chip"),底層用SDS實現(呼應我們講過的 SDS 結構):
    • 比如 "chocolate" 這個名稱,實際存儲為 SDS:len=9(9 個字符)、free=9(預分配空間)、buf=['c','h','o','c','o','l','a','t','e','\0']
    • 為什么用 SDS?因為商品名稱可能很長(比如 "2024 限量版進口巧克力"),SDS 的動態擴展和二進制安全特性,能高效存儲這些字符串(和我們之前講的字典鍵存儲邏輯一致)。

1.1.2、zskiplist:商場的 "總服務臺"(跳躍表管理結構)

如果說zskiplistNode是單個商品,zskiplist就是商場服務臺的 "總導視圖",記錄全局信息:

typedef struct zskiplist {struct zskiplistNode *header, *tail; // 首/尾商品位置unsigned long length;                // 商品總數int level;                           // 最高導航層數
} zskiplist;

這幾個字段的作用和服務臺導視圖完全對應:

  • header/tail:導視圖上標著 "零食區起點" 和 "零食區終點",讓你瞬間定位第一個和最后一個商品(O (1) 復雜度)。比如想找最便宜的商品,直接從 header 開始;想找最貴的,直接定位到 tail。
  • length:導視圖上寫著 "共 50 種商品",不用數貨架就知道總數(O (1) 復雜度)—— 這和鏈表的 len 屬性功能相同,但鏈表需要遍歷統計,跳躍表直接記錄。
  • level:導視圖上標著 "最高 3 層導航",告訴你最高層索引是多少,避免在不存在的高層導航中查找(O (1) 復雜度)。

二、跳躍表的工作流程:像顧客找商品一樣簡單

我們用 "找 30 元的商品" 這個場景,看跳躍表的查找過程(對應顧客在商場找 30 元商品):

  1. 從最高層導航開始(比如 3 層):
    服務臺導視圖顯示最高 3 層,顧客先看 3 層導航,發現 "0-50 元區" 的起點是 5 元薯片,終點是 50 元禮盒。30 元在這個區間內,于是下到 2 層導航。

  2. 中層導航縮小范圍(2 層):
    2 層導航標著 "5-15 元→15-30 元→30-50 元",顧客從 5 元薯片出發,順著 2 層導航的 forward 指針跳到 15 元牛肉干(span=2,中間有 2 個商品),再跳到 30 元餅干(span=3,中間有 3 個商品)。

  3. 地面層精確查找(1 層):
    到了 30 元餅干的位置,發現正好是目標,查找結束。如果沒找到,就順著 1 層的 forward 指針逐個查看(因為 1 層是完整鏈表)。

這個過程完美體現了 "高層跳大步,低層走小步" 的效率優勢 —— 比從第一個商品逐個查找快得多。

三、設計細節:為什么跳躍表要這樣設計?

3.1、節點層數為什么隨機?——"熱門商品多掛導航"

每個新節點的層數(1-32 層)是隨機生成的,就像商場會給熱門商品掛更多層導航(比如暢銷零食在高、中、低三層都有標記),普通商品可能只在地面層有標記。

隨機層數的好處:

  • 避免所有節點都掛 32 層導航(浪費空間)
  • 統計上能形成 "高層節點少、低層節點多" 的金字塔結構,保證查找效率

這就像字典的哈希分布策略,通過概率平衡性能和空間。

3.2、為什么不用平衡樹?——"導航系統比復雜樹狀圖更實用"

有序數據結構中,平衡樹(如紅黑樹)也能達到 O (logN) 效率,但 Redis 選跳躍表的原因:

  • 實現簡單:跳躍表的多層索引邏輯比平衡樹的 "旋轉調整" 簡單(就像商場導航比復雜的樹狀分布圖好懂)。
  • 范圍查詢高效:比如找 "20-50 元的商品",跳躍表從 20 元節點開始,順著 1 層 forward 指針就能批量獲取(類似鏈表的順序遍歷),平衡樹需要復雜的左右子樹遍歷。
  • 空間可控:層數上限 32,不會像平衡樹那樣因頻繁調整導致空間波動(類似商場導航層數固定,不會突然增刪樓層)。

3.3、與之前結構的配合:Redis 的 "結構組合拳"

跳躍表不是孤立存在的,而是和其他結構配合工作:

  • 與 SDS 配合:用 SDS 存儲節點的成員名稱(obj),利用其動態字符串特性(如之前講的空間預分配、長度記錄)。
  • 與字典配合:在有序集合中,Redis 會同時用字典(記錄 member 到 score 的映射)和跳躍表(按 score 排序),形成 "快速查找 + 有序遍歷" 的組合(就像商場既有儲物柜按編號找東西,又有導航系統按價格找東西)。

四、總結:跳躍表的設計智慧

跳躍表組件商場導航系統對應技術價值與其他結構的關聯
zskiplistNode.level商品的多層導航標簽分層查找,平均 O (logN) 效率-
forward 指針導航標簽的 "指向箭頭"快速跳躍定位類似字典的哈希定位,但支持有序
span 跨度導航標簽的 "間隔數"快速計算排名(如 ZRANK 命令)-
backward 指針商品的 "后退箭頭"支持反向遍歷(如 ZREVRANGE)類似鏈表的 prev 指針
score 分值商品價格標簽作為排序依據-
obj 成員對象商品名稱牌存儲成員信息用 SDS 實現,復用字符串優化
zskiplist 管理結構商場總導視圖O (1) 獲取全局信息(首尾、總數等)類似鏈表的 list 管理結構

跳躍表就像為 "有序數據快速訪問" 量身定制的導航系統,它沒有追求最復雜的結構,而是用 "多層索引 + 隨機優化" 的簡單思路,平衡了效率、實現難度和空間開銷。這種設計思路和 Redis 的整體哲學一致 —— 為不同場景選擇最合適的結構(字符串用 SDS、無序查找用字典、有序查找用跳躍表),最終實現 "又快又穩" 的性能表現。

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

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

相關文章

小程序點擊之數據綁定

<return /><view class"all-wrap" style"padding-top:{{topHeight}}px;"><view class"my-title">我的收藏</view><scroll-viewclass"collect-list-container"scroll-yscroll-top"{{scrollTop}}"…

數據結構——順序表和單向鏈表(2)

目錄 前言 一、單向鏈表 1、基本概念 2、單向鏈表的設計 &#xff08;1&#xff09;節點設計 &#xff08;2&#xff09;初始化空單向鏈表 &#xff08;3&#xff09;、初始化數據節點 &#xff08;4&#xff09;數據節點 &#xff08;5&#xff09;判斷鏈表是否為空 …

More Effective C++ 條款26:限制某個類所能產生的對象數量

More Effective C 條款26&#xff1a;限制某個類所能產生的對象數量核心思想&#xff1a;通過控制類的實例化過程&#xff0c;限制程序中該類的對象數量&#xff0c;可以防止資源過度使用&#xff0c;確保系統資源合理分配&#xff0c;并實現單例或有限實例模式。 &#x1f680…

CMS系統維護中常見的安全威脅及防護指南!

內容管理系統&#xff08;CMS&#xff09;已成為網站建設的核心工具&#xff0c;但隨之而來的安全風險卻常被低估。超過70%的網站使用CMS構建&#xff0c;而其中近半數曾遭遇安全漏洞威脅。作為運維人員和開發者&#xff0c;了解這些安全威脅并采取相應防護措施至關重要。 一、…

springboot knife4j 接口文檔入門與實戰

Spring Boot3 Knife4j 項目地址https://gitee.com/supervol/loong-springboot-study&#xff08;記得給個start&#xff0c;感謝&#xff09;Knife4j 介紹在國內 Java 開發領域&#xff0c;Knife4j 是一款廣受歡迎的 API 文檔工具&#xff0c;它基于 OpenAPI 規范&#xff0c;在…

Spring Boot 事務失效的八大原因及解決方案詳解

在 Spring Boot 項目開發中&#xff0c;聲明式事務管理通過 Transactional 注解提供了極大的便利。但許多開發者都曾遇到過事務不生效的困擾。本文將詳細分析導致 Spring Boot 事務失效的八大常見情況&#xff0c;并提供相應的解決方案。1. 數據庫引擎不支持事務問題分析&#…

數據結構:順序棧與鏈棧的原理、實現及應用

數據結構詳解&#xff1a;順序棧與鏈棧的原理、實現及應用 1. 引言&#xff1a;棧的核心概念 棧&#xff08;Stack&#xff09;是一種重要的線性數據結構&#xff0c;它遵循后進先出&#xff08;Last In First Out, LIFO&#xff09;的原則。這意味著最后一個被添加到棧中的元素…

apipost 8.x 腳本循環調用接口

apipost 8.x 腳本循環調用接口背景實現先說整體邏輯&#xff1a;最后背景 上周為了找某OA 偶爾出現的詭異現象&#xff0c;需要用測試工具來壓測&#xff0c;看看這個問題能否重現。以前用過Jmeter&#xff0c;但是沒有裝&#xff0c;正好有個國產的apipost看看如何&#xff1…

STM32 - Embedded IDE - GCC - 使用 GCC 鏈接腳本限制 Flash 區域

導言如上所示&#xff0c;Keil限制flash區域只需要在IROM1里將Start框框與Size框框填入具體信息即可。比如bootloader程序一般從0x8000000開始&#xff0c;大小0x10000&#xff08;64KB&#xff09;。此時&#xff0c;flash的范圍被限制在0x8000000 ~ 0x800FFFF。 另外&#xf…

Jenkins和Fastlane的原理、優缺點、用法、如何選擇

Jenkins 和 Fastlane 是軟件開發中用于自動化流程的工具一、Jenkins實現自動化打包1.1具體實現步驟安裝與配置&#xff1a;首先在服務器上安裝 Jenkins&#xff0c;可以通過官方提供的安裝包進行安裝&#xff0c;支持多種操作系統。安裝完成后&#xff0c;通過 Web 界面進行初始…

DOM常見的操作有哪些?

1.DOM文檔對象模型&#xff08;DOM&#xff09;是HTML和XML文檔的編程接口它提供了對文檔結構化表述&#xff0c;并定義了一種方式可以使從程序中對該結構進行訪問&#xff0c;從而改變文檔的結構&#xff0c;樣式和內容任何HTML或XML文檔都可以用DOM表示一個由節點構成的層級結…

【Kubernetes】知識點3

25. 說明Job與CronJob的功能。答&#xff1a;Job&#xff1a;一次性作業&#xff0c;處理短暫的一次性任務&#xff0c;僅執行一次&#xff0c;并保證處理的一個或者多個 Pod 成功結束。CronJob&#xff1a;周期性作業&#xff0c;可以指定每過多少周期執行一次任務。26. Kuber…

LINUX-網絡編程-TCP-UDP

1.目的&#xff1a;不同主機&#xff0c;進程間通信。2.解決的問題1&#xff09;主機與主機之間物理層面必須互相聯通。2&#xff09;進程與進程在軟件層面必須互通。IP地址&#xff1a;計算機的軟件地址&#xff0c;用來標識計算機設備MAC地址&#xff1a;計算機的硬件地址&am…

目標檢測定位損失函數:Smooth L1 loss 、IOU loss及其變體

Smooth L1 Loss 概述 Smooth L1 Loss&#xff08;平滑 L1 損失&#xff09;&#xff0c;是一個在回歸任務&#xff0c;特別是計算機視覺中的目標檢測領域&#xff08;如 Faster R-CNN, SSD&#xff09;非常核心的損失函數。 xxx 表示模型的預測值&#xff0c;yyy 表示真實值&am…

Android開發之fileprovider配置路徑path詳細說明

第一步在清單文件配置fileprovider屬性<providerandroid:name"androidx.core.content.FileProvider"android:authorities"${applicationId}.fileprovider"android:exported"false"android:grantUriPermissions"true"><meta-d…

【ComfyUI】圖像描述詞潤色總結

在 ComfyUI 的工作流中&#xff0c;圖像反推描述詞能幫我們從圖像里抽取語義信息&#xff0c;但這些原始描述往往還顯得生硬&#xff0c;缺乏創意或流暢性。為了讓提示詞更自然、更有表現力&#xff0c;就需要“潤色”環節。潤色節點的任務&#xff0c;不是重新生成描述&#x…

java面試中經常會問到的IO、NIO問題有哪些(基礎版)

文章目錄一、IO 基礎與分類二、NIO 核心組件與原理三、NIO 與 BIO 的實戰對比四、AIO 與 NIO 的區別五、Netty 相關&#xff08;NIO 的高級應用&#xff09;總結Java 中的 IO&#xff08;輸入輸出&#xff09;和 NIO&#xff08;非阻塞 IO&#xff09;是面試中的重要考點&#…

時序數據庫選型指南:如何為工業場景挑選最強“數據底座”

工業4.0時代&#xff0c;工廠化身為巨大的數據生產中心。數以萬計的傳感器、PLC和設備每時每刻都在產生著海量的時間序列數據&#xff08;Time-Series Data&#xff09;&#xff1a;溫度、壓力、流速、振動、設備狀態……這些帶時間戳的數據是工業互聯網的血液&#xff0c;蘊含…

【排序算法】冒泡 選排 插排 快排 歸并

一、冒泡排序// 冒泡排序var bubbleSort function (arr) {const len arr.length;for (let i 0; i < len; i) {let isSwap false;for (let j 0; j < len - 1; j) {// 每一次遍歷都要比較相鄰元素的大小&#xff0c;如果滿足條件就交換位置if (arr[j] > arr[j 1])…

電子病歷空缺句的語言學特征描述與自動分類探析(以GPT-5為例)(中)

語言學特征刻畫(特征庫) 句法特征 句法特征是識別 SYN 類電子病歷空缺句的核心語言學維度,其量化分析通過構建依存句法結構的形式化指標,實現對語法不完整性的客觀描述。該類特征主要包括依存樹不完備指標、謂詞-論元覆蓋率及從屬連詞未閉合三類核心參數,共同構成 SYN 類…