0

0

C++怎么实现跳表(Skip List)_C++有序结构替代红黑树【查找】

穿越時空

穿越時空

发布时间:2026-03-09 14:35:23

|

686人浏览过

|

来源于php中文网

原创

跳表值得手写因其并发友好、内存局部性优、可控性强;需避免层级越界、断链、硬编码层数等错误,next数组须内联固定长度以提升缓存效率。

c++怎么实现跳表(skip list)_c++有序结构替代红黑树【查找】

跳表在 C++ 里为什么值得手写而不是直接用 std::set

跳表不是 STL 标准组件,std::set 底层是红黑树,O(log n) 查找但常数大、内存局部性差;跳表靠多层链表 + 随机提升实现均摊 O(log n),插入/删除更易并发,且自己控制层级和随机策略时,能压测、调参、嵌入自定义比较逻辑——比如你正做日志索引或实时排序缓存,又不想引入 Boost 或第三方库,手写一个轻量跳表反而更可控。

常见错误现象:find() 返回空指针却没检查层级越界;insert() 后忘记更新前驱数组导致断链;随机层数硬编码为 16,实际数据量小却浪费内存。

  • 层级上限别设死,按 log2(n) 动态估算(n 是预期最大节点数),初始可设为 16,但运行时根据实际 size 调整
  • 随机提升概率必须是 0.5(即每次抛硬币),用 rand() & 1rand() % 2 更快且无 bias
  • 所有节点的 next 数组大小必须统一为当前最大层级,哪怕某次插入只到第 2 层——否则遍历时指针访问会越界

skip_list_node 的内存布局怎么避免 cache line 断裂

跳表性能吃内存布局很重:每个节点带一个 next 指针数组,如果数组长度不固定或用 std::vector 动态分配,指针分散在堆上,一次查找要跨多个 cache line。必须把 next 做成固定长度的内联数组。

示例结构体关键点:

立即学习C++免费学习笔记(深入)”;

Stable Diffusion Online
Stable Diffusion Online

基于Stable Diffusion搭建的AI绘图工具

下载
struct skip_list_node {
    int key;
    std::string value; // 实际业务字段
    skip_list_node* next[16]; // 必须是 [16],不能是 std::unique_ptr<skip_list_node*>[]
};
  • next[16] 放在结构体末尾,用 malloc(sizeof(skip_list_node) + 16 * sizeof(skip_list_node*)) 分配整块内存
  • 不要用 std::array<skip_list_node></skip_list_node>,它会让编译器在结构体里塞 padding,破坏紧凑性
  • 如果 key 是小整型(如 int),把它放结构体最前面,利于 CPU 预取时提前拿到比较值

插入时怎么维护 update 数组而不漏层

跳表插入本质是“从顶层往下找每层最后一个 ≤ key 的节点”,把这些节点记进 update[] 数组,再逐层把新节点插到它们后面。漏掉某一层,就会导致该层链表断裂,后续 find() 在那层直接跳过新节点。

典型错误:for (int i = current_level - 1; i >= 0; i--) 循环里,没对每一层都执行 update[i] = x,而是只在找到位置时才赋值。

  • 初始化 update 数组全为 head 指针:skip_list_node* update[16]; for (int i = 0; i
  • 搜索时每下降一层,先保存当前节点到 update[i],再沿 next[i] 走:“先存后走”,不是“走到再存”
  • 新节点层级为 lvl,则只对 i = 0lvl-1 层执行插入,更高层不用动

查不到节点时 find() 返回什么最安全

返回 nullptr 看似自然,但容易掩盖边界问题:比如 key 小于所有节点,或跳表为空,find() 走完顶层就停了,根本没进任何 next 指针——这时候返回 nullptr 没问题;但如果用户想“找 floor key”,就需要返回小于等于 key 的最大节点,此时 nullptr 就不够用了。

更稳妥的做法是让 find() 返回一对指针:std::pair<skip_list_node bool></skip_list_node>,bool 表示是否精确命中。但多数场景下,只要文档写清行为,返回 nullptr 即可。

  • 绝对不要返回野指针或未初始化的局部变量地址
  • 如果支持重复 key,find() 应返回第一个匹配节点,而非任意一个——这由插入时“相等时往右走”的约定保证
  • 调试时可在 find() 开头加 assert:assert(head_ != nullptr);,空跳表应单独处理,不进主逻辑

跳表最难调的永远不是算法逻辑,而是指针赋值顺序和内存释放时机:delete 节点前,必须确保所有层级的前驱节点的 next[i] 都已绕过它,否则删完立刻触发 use-after-free。这个点没有银弹,只能靠 ASan + 反复压测。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

490

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

202

2025.07.04

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

490

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

202

2025.07.04

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

990

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

607

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

314

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

235

2025.08.29

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

59

2026.03.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 11万人学习

C 教程
C 教程

共75课时 | 5.3万人学习

C++教程
C++教程

共115课时 | 21.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号