跳表數據結構

跳表(Skip List)是一種支持高效插入、刪除和查找鏈表結構,用于加速查找操作,特別適用于有序數據集合。它在Redis、LevelDB等系統中被用于**有序集合(Sorted Set)**的實現。

1. 跳表的結構

跳表的核心思想是:
在鏈表的基礎上,引入多級索引,類似于高速公路的匝道,提高查找效率。

一個跳表通常由多層索引構成:

  • 最底層(Level 0) 是一個有序單鏈表,存儲所有數據;
  • 上層索引(Level > 0)部分節點構成,起到“跳躍”的作用,加速查找;
  • 最上層索引少量節點構成,使得查找可以迅速縮小范圍。

示例跳表(3 層):

Level 2:    1 --------------> 9 ----------------> 19
Level 1:    1 ----> 5 -----> 9 ----> 13 -------> 19
Level 0:    1 -> 3 -> 5 -> 7 -> 9 -> 11 -> 13 -> 15 -> 17 -> 19

每一層都是上一層的子集,節點的“晉升”是概率性的(通常是 1/2)。

2. 跳表的基本操作

查找

跳表的查找過程類似于二分查找:

  1. 從最高層索引開始,查找小于目標值的最大節點;
  2. 向下移動到下一層索引,繼續查找;
  3. 直到底層(Level 0),最終在普通鏈表中找到目標節點或確認其不存在。

時間復雜度:
O ( log ? n ) O(\log n) O(logn) —— 因為跳表的高度是O(log n),查找路徑長度也大約是O(log n)

插入

  1. 查找插入位置,找到前驅節點;
  2. 隨機決定新節點的層數(常見做法:擲硬幣,每次有 50% 概率提升一層);
  3. 在每一層進行插入,更新索引。

時間復雜度:

  • 平均 O(log n),因為最多遍歷 log n 層;
  • 最壞 O(n)(所有元素都在同一層)。

刪除

  1. 查找目標節點(與查找操作類似);
  2. 在每一層移除節點
  3. 如果某層為空,則刪除該層

時間復雜度:
O ( log ? n ) O(\log n) O(logn)

3. 跳表 vs. 其他數據結構

數據結構查找時間復雜度插入時間復雜度刪除時間復雜度額外空間適用場景
跳表O(log n)O(log n)O(log n)O(n)有序數據、高效查找
平衡二叉搜索樹 (AVL, 紅黑樹)O(log n)O(log n)O(log n)O(n)適用于動態數據
哈希表O(1)O(1)O(1)O(n)適用于無序數據、頻繁查詢
鏈表O(n)O(1)O(n)O(n)適用于插入、刪除較多

跳表 vs. 紅黑樹

  • 跳表實現更簡單,只需維護索引,而紅黑樹需要復雜的旋轉操作;
  • 跳表在分布式環境中更友好,如 Redis 的有序集合(ZSet)采用跳表;
  • 紅黑樹適用于內存受限的場景,因為跳表的索引層需要額外存儲空間。

4. 實際應用

Redis

Redis 有序集合(Sorted Set) 的底層結構是 跳表 + 哈希表

  • 跳表:用于范圍查詢ZRANGEZREVRANGE
  • 哈希表:用于O(1) 查找ZADD

LevelDB

Google 的 LevelDB 用跳表存儲MemTable,然后刷盤成 SSTable

5. 代碼實現(Java)

跳表節點

class SkipListNode {int val;SkipListNode[] next; // 指向不同層級的下一個節點public SkipListNode(int val, int level) {this.val = val;this.next = new SkipListNode[level];}
}

跳表類

import java.util.Random;class SkipList {private static final int MAX_LEVEL = 16;  // 最大層數private final SkipListNode head; // 頭節點private int levelCount = 1; // 當前最大層數private final Random random = new Random();public SkipList() {head = new SkipListNode(-1, MAX_LEVEL); // 初始化頭節點}// 查找public boolean search(int target) {SkipListNode cur = head;for (int i = levelCount - 1; i >= 0; i--) {while (cur.next[i] != null && cur.next[i].val < target) {cur = cur.next[i];}}cur = cur.next[0];  // 進入最底層return cur != null && cur.val == target;}// 插入public void insert(int num) {SkipListNode[] update = new SkipListNode[MAX_LEVEL]; // 記錄每層的前驅節點SkipListNode cur = head;for (int i = levelCount - 1; i >= 0; i--) {while (cur.next[i] != null && cur.next[i].val < num) {cur = cur.next[i];}update[i] = cur;  // 記錄前驅節點}int newLevel = randomLevel();levelCount = Math.max(levelCount, newLevel);SkipListNode newNode = new SkipListNode(num, newLevel);for (int i = 0; i < newLevel; i++) {newNode.next[i] = update[i].next[i];update[i].next[i] = newNode;}}// 刪除public void delete(int num) {SkipListNode cur = head;SkipListNode[] update = new SkipListNode[MAX_LEVEL];for (int i = levelCount - 1; i >= 0; i--) {while (cur.next[i] != null && cur.next[i].val < num) {cur = cur.next[i];}update[i] = cur;}SkipListNode target = cur.next[0];if (target == null || target.val != num) return;for (int i = 0; i < levelCount; i++) {if (update[i].next[i] != target) break;update[i].next[i] = target.next[i];}}// 隨機生成層數private int randomLevel() {int level = 1;while (random.nextDouble() < 0.5 && level < MAX_LEVEL) {level++;}return level;}
}

6. 總結

  • 跳表通過多層索引加速查詢,時間復雜度接近O(log n)
  • 插入/刪除時動態調整索引,比紅黑樹實現簡單;
  • Redis、LevelDB 等系統采用跳表,適用于有序集合、范圍查詢等場景;
  • 比紅黑樹占用更多空間,但更適合并發和分布式環境

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

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

相關文章

系統會把原先的對話狀態堆棧從 [“assistant“] 更新為 [“assistant“, “update_flight“]這個更新的處理過程

這個更新主要是在 State 定義中通過 Annotated 來自動處理的。在 State 類型中&#xff0c;我們對 dialog_state 字段綁定了 update_dialog_stack 函數&#xff0c;如下所示&#xff1a; class State(TypedDict):messages: Annotated[list[AnyMessage], add_messages]user_inf…

HTTP發送POST請求的兩種方式

1、json String json HttpRequest.post(getUrl(method, "v1", url, userId, appKey)).header("Content-type", "application/json") // 設置請求頭為 JSON 格式.body(JSONUtil.toJsonStr(params)) // 請求體為 JSON 字符串.execute().body(); …

Windows 萬興恢復專家 Wondershare Recoverit-v13.5.7.9-[電腦數據恢復工具]

Windows 萬興恢復專家Wondershare_Recoverit 鏈接&#xff1a;https://pan.xunlei.com/s/VOL3z608vzAj_IYTvH-F1q7kA1?pwdiu89# 1. 打開Setup.exe進行安裝&#xff0c;安裝完不要打開軟件&#xff0c;記住安裝目錄 2. 將"Crack"文件夾內的所有文件復制到安裝目錄 …

Blender UV紋理貼圖,導出FBX到Unity

加載ps好的模型貼圖。右下角選擇《材質》基礎色里面選擇《圖像紋理》&#xff0c;選擇你的圖片。 選擇上面UV選項卡。左上角選擇UV編輯器。選中物體&#xff0c;TAB進入編輯模式。即可調整映射的圖像范圍。 其中渲染設置可以在左側下邊脫出。 導出帶紋理FBX模型 路徑選擇復…

華為hcia——Datacom實驗指南——以太網幀和IPV4數據包格式(一)

實驗開始 第一步配置環境 第二步配置客戶端 如圖所示&#xff0c;我們把客戶端的ip配置成192.168.1.10&#xff0c;網關設為192.168.1.1 第三步配置交換機1 system-view sysname LSW1 vlan batch 10 interface ethernet0/0/1 port link-type access port default vlan 10 qu…

解鎖 Ryu API:從 Python 接口到 REST 設計全解析

Ryu 4.34 版本的 API 功能分類、核心接口說明及示例代碼&#xff0c;結合其 Python 應用開發接口和 REST API 的設計特點進行綜合解析&#xff1a; 一、Python 應用開發 API Ryu 的核心能力通過 Python 類庫實現&#xff0c;開發者需繼承 RyuApp 類并注冊事件處理函數。 1. 應…

如何在需求分析階段考慮未來擴展性

在需求分析階段考慮未來擴展性的關鍵在于 前瞻規劃、靈活架構、標準設計。其中&#xff0c;前瞻規劃尤為重要&#xff0c;因為通過全面分析業務發展趨勢與技術演進&#xff0c;能夠在初期設計階段預留足夠擴展空間&#xff0c;降低后期改造成本&#xff0c;為企業長期發展奠定堅…

Docker搭建Redis哨兵模式【一主兩從三哨兵】

Docker搭建Redis哨兵模式 系統: CentOS 7 Dockder 版本: VMware虛擬機 網絡適配器 網絡連接 橋接模式:直接連接物理網絡查看IP命令 ip addr一、哨兵模式概述 1. 官方文檔與關聯博客 官方文檔:https://redis.io/docs/latest/operate/oss_and_stack/management/sentinel關聯博…

關于統計建模大賽的選題

文章目錄 0.大賽主題1.量化分析和風險管理2.金融市場預測與統計建模3.投資與機器學習相關4.大數據和醫療5.智能制造相關的6.教育行業 0.大賽主題 統計創新應用數據引領未來&#xff1a;這個主題其實很寬泛&#xff0c;沒有什么明確的這個要求&#xff0c;所以只要是和我們的統…

Docker 學習筆記:從入門到部署,實戰演練全流程!

&#x1f4cc; 開篇&#xff1a;為什么要學 Docker&#xff1f; 還在為環境不一致、部署麻煩、依賴沖突頭疼嗎&#xff1f;Docker 讓一切變得簡單&#xff01;作為現代開發和運維的神器&#xff0c;Docker 讓我們可以用 一句命令 解決 “在我電腦上能跑” 的問題。今天&#x…

ThinkPhp 5 安裝阿里云內容安全(綠化)

composer require alibabacloud/green-20220302 首先要把php5(不支持php7)的執行文件設置到PATH環境變量 此外還要先執行composer update php5.5和php5.6的區別 5.5認為 <? 開頭的也是php文件&#xff0c;包括 <?php 5.6認為 <? 開頭的不是php文件&#xff0c;只…

使用NVM工具管理Node版本

Date: 2025.03.10 14:53:55 author: lijianzhan NVM&#xff08;Node Version Manager&#xff09;用于在同一個系統上管理多個 Node.js 版本,NVM 允許你安裝、使用和切換不同的 Node.js 版本。這對于前端工作人員來說可以更方便的管理和維護不同nodejs版本的項目。 &#xff0…

Vue主流的狀態保存框架對比

一、Vuex 4&#xff08;官方傳統方案&#xff09; 優點&#xff1a; 官方背書&#xff1a;Vue 官方長期維護&#xff0c;成熟穩定。結構化清晰&#xff1a;通過 state/mutations/actions/getters 強制約定代碼結構&#xff0c;適合大型團隊協作。插件生態&#xff1a;支持中間…

AIGC視頻生成模型:慕尼黑大學、NVIDIA等的Video LDMs模型

大家好&#xff0c;這里是好評筆記&#xff0c;公主號&#xff1a;Goodnote&#xff0c;專欄文章私信限時Free。本文詳細介紹慕尼黑大學攜手 NVIDIA 等共同推出視頻生成模型 Video LDMs。NVIDIA 在 AI 領域的卓越成就家喻戶曉&#xff0c;而慕尼黑大學同樣不容小覷&#xff0c;…

NVIDIA k8s-device-plugin源碼分析與安裝部署

在《kubernetes Device Plugin原理與源碼分析》一文中&#xff0c;我們從源碼層面了解了kubelet側關于device plugin邏輯的實現邏輯&#xff0c;本文以nvidia管理GPU的開源github項目k8s-device-plugin為例&#xff0c;來看看設備插件側的實現示例。 一、Kubernetes Device Pl…

C++ 數據結構詳解及學習規劃

C++數據結構詳解及學習規劃 一、C++常用數據結構詳解與示例 以下是C++中核心數據結構的分類及具體實現示例: 1. 線性數據結構 a. 數組(Array) ? 定義:存儲固定大小、同類型元素的連續內存結構。 ? 特點:快速隨機訪問(O(1)),但插入/刪除效率低(O(n))。 ? 應用場…

如何使用Postman,通過Mock的方式測試我們的API

這篇文章將教會大家如何利用 postman&#xff0c;通過 Mock 的方式測試我們的 API。 什么是 Mock Mock 是一項特殊的測試技巧&#xff0c;可以在沒有依賴項的情況下進行單元測試。通常情況下&#xff0c;Mock 與其他方法的主要區別就是&#xff0c;用于取代代碼依賴項的模擬對…

如何檢查電腦的硬盤健康狀況?

檢查硬盤健康狀況可以使用多種工具和方法。以下是一些常用的工具和步驟&#xff1a; Windows系統&#xff1a; 使用Windows內置工具&#xff1a; 磁盤檢查&#xff1a;可以通過命令提示符&#xff08;cmd&#xff09;使用chkdsk命令來檢查硬盤錯誤。例如&#xff0c;輸入chkd…

JavaWeb中提供的對cookie的操作

JavaWeb中提供的對cookie的操作 簡介服務端創建Cookie對象&#xff0c;然后將Cookie添加到HTTP響應結果中讀取請求端瀏覽器的Cookie設置/讀取Cookie在客戶端的有效期URL編碼/解碼 簡介 Servlet API為Servlet訪問Cookie提供了簡單易用的接口。javax.servlet.http.Cookie類用來表…

Android中AIDL和HIDL的區別

在Android中&#xff0c;AIDL&#xff08;Android Interface Definition Language&#xff09; 和 HIDL&#xff08;HAL Interface Definition Language&#xff09; 是兩種用于定義跨進程通信接口的語言。AIDL 是 Android 系統最早支持的 IPC&#xff08;進程間通信&#xff0…