百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

有序链表升级版:跳表的基本原理(跳跃链表的查找效率为)

ztj100 2025-02-03 16:17 12 浏览 0 评论

背景

在元素有序的情况下,数组可以基于二分查找快速定位元素,而普通链表就比较尴尬了,定位元素的时间复杂度还是 O(N)。

那有没有办法给有序链表加速呢?跳表便是有序链表的升级版,拥有较高的读写性能,且相比于红黑树和平衡树,实现复杂度也更低。

而 Redis 的有序集合底层的数据结构之一就是跳表,本文主要讲述跳表的基本实现原理。

跳表

下图展示了跳表的示例结构:

可以看到跳表通过在原始链表上层建立索引,并通过指针将索引节点串联起来,最终达到跳跃查找的效果。

下面展示了一个 SkipNode 的数据结构:

每个节点都有一个 key 值,作为节点排序以及定位的依据,value 则保存节点数据,另外还会维护 down,right 指针,用于遍历节点。

查询

查找节点的过程相对简单,设置一个临时节点 temp = head,流程如下:

?从头结点出发,如果当前节点的key与查询的key相等,那么返回当前节点

?如果key不相等,且右侧为null,那么证明只能向下,temp = temp.down

?如果key不相等,且右侧节点key小于当前节点key,证明还可往右,temp = temp.right

?如果key不相等,且右侧节点key大于当前节点key,证明目标节点在当前节点与右侧节点之间,此时向下,temp = temp.down

下图中红色节点展示了查找【节点 8】 的路线:

删除

删除操作的核心有两点:

?找到待删除节点的前驱节点

?每一层的待删除节点都需要删除


设置 temp = head,流程如下:

?如果temp右侧为null,那么temp=temp.down

?如果temp右侧不为null,并且右侧的key等于待删除的key,那么先删除节点,再向下 temp=temp.down,为了删除下层节点

?如果temp右侧不为null,并且右侧key小于待删除的key,那么temp向右temp=temp.right

?如果temp右侧不为null,并且右侧key大于待删除的key,那么temp向下temp=temp.down

下图展示了【节点 7】被删除的过程,其中红色节点是查找前驱节点的路线,自顶向下逐层删除节点。

插入

插入操作较为复杂,核心点是需要考虑索引的维护,如果严格按照上一层索引个数是当前层索引个数的 1/2 规则,在插入的过程中会频繁涉及大范围索引重建,对性能影响较大。

跳表舍弃了理想状态的索引结构,而是采用随机的方式决定新增节点在上层是否需要建立索引,在保证一定索引格式的同时也极大缩小了索引维护的性能开销。

插入节点的过程一般是由下往上,从底层开始插入,如何找到待插入节点的前驱节点进行插入操作,这边可以使用栈将定位待插入位置的过程中途经的下行节点记录下来。

另外如果插入的元素不断向上建立索引,最终导致索引层数超过了原跳表的最大层数,需要同时维护新的 head 指针。

流程如下:

?找到待插入位置,从底层开始插入

?完成当前层插入后,判断是否需要向上建立索引,首先判断当前索引层级是否大于最大值,如果大于则停止建立,否则通过随机数逻辑判断是否继续向上建立索引,如果随机数不满足要求,也停止建立索引

?不断重复第二步,直到概率退出或者索引层数大于最大索引层

下图展示了插入【节点 6 】的过程,其中因为新增节点的索引高度超出了原来索引的最大高度,所以需要对应新增一个 head 节点;绿色节点则作为下行节点被记录下来。

相关推荐

利用navicat将postgresql转为mysql

导航"拿来主义"吃得亏自己动手,丰衣足食...

Navicat的详细教程「偷偷收藏」(navicatlite)

Navicat是一套快速、可靠并价格适宜的数据库管理工具,适用于三种平台:Windows、macOS及Linux。可以用来对本机或远程的MySQL、SQLServer、SQLite、...

Linux系统安装SQL Server数据库(linux安装数据库命令)

一、官方说明...

Navicat推出免费数据库管理软件Premium Lite

IT之家6月26日消息,Navicat推出一款免费的数据库管理开发工具——NavicatPremiumLite,针对入门级用户,支持基础的数据库管理和协同合作功能。▲Navicat...

Docker安装部署Oracle/Sql Server

一、Docker安装Oracle12cOracle简介...

Docker安装MS SQL Server并使用Navicat远程连接

...

Web性能的计算方式与优化方案(二)

通过前面《...

网络入侵检测系统之Suricata(十四)——匹配流程

其实规则的匹配流程和加载流程是强相关的,你如何组织规则那么就会采用该种数据结构去匹配,例如你用radixtree组织海量ip规则,那么匹配的时候也是采用bittest确定前缀节点,然后逐一左右子树...

使用deepseek写一个图片转换代码(deepnode处理图片)

写一个photoshop代码,要求:可以将文件夹里面的图片都处理成CMYK模式。软件版本:photoshop2022,然后生成的代码如下://Photoshop2022CMYK批量转换专业版脚...

AI助力AUTOCAD,生成LSP插件(ai里面cad插件怎么使用)

以下是用AI生成的,用AUTOLISP语言编写的cad插件,分享给大家:一、将单线偏移为双线;;;;;;;;;;;;;;;;;;;;;;单线变双线...

Core Audio音频基础概述(core 音乐)

1、CoreAudioCoreAudio提供了数字音频服务为iOS与OSX,它提供了一系列框架去处理音频....

BlazorUI 组件库——反馈与弹层 (1)

组件是前端的基础。组件库也是前端框架的核心中的重点。组件库中有一个重要的板块:反馈与弹层!反馈与弹层在组件形态上,与Button、Input类等嵌入界面的组件有所不同,通常以层的形式出现。本篇文章...

怎样创建一个Xcode插件(xcode如何新建一个main.c)

译者:@yohunl译者注:原文使用的是xcode6.3.2,我翻译的时候,使用的是xcode7.2.1,经过验证,本部分中说的依然是有效的.在文中你可以学习到一系列的技能,非常值得一看.这些技能不单...

让SSL/TLS协议流行起来:深度解读SSL/TLS实现1

一前言SSL/TLS协议是网络安全通信的重要基石,本系列将简单介绍SSL/TLS协议,主要关注SSL/TLS协议的安全性,特别是SSL规范的正确实现。本系列的文章大体分为3个部分:SSL/TLS协...

社交软件开发6-客户端开发-ios端开发验证登陆部分

欢迎订阅我的头条号:一点热上一节说到,Android客户端的开发,主要是编写了,如何使用Androidstudio如何创建一个Android项目,已经使用gradle来加载第三方库,并且使用了异步...

取消回复欢迎 发表评论: