高效的跳表

2024-02-02 12:44
文章标签 高效 跳表

本文主要是介绍高效的跳表,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

高效的跳表

  • 一、 概念
  • 二、 实现原理
  • 三、存在的问题
  • 四、解决方法
  • 五、如何保证效率
  • 六、代码实现
  • 七、总结
    • 对比平衡搜索树
    • 对比哈希表

一、 概念

跳表,是一种用来查询数据的数据结构,它是由William Pugh发明的,借助有序链表,来实现高效地查询

二、 实现原理

William Pugh的优化思路是,每相邻两个节点升高一层,增加一个指针,让指针指向下下个节点,依次类推,形成下图的c,每一层都能排除一半,类似于二分查找,时间复杂度为O(log n)
在这里插入图片描述

三、存在的问题

插入删除数据时,就会打乱上下相邻两层链表上节点个数严格的2:1的对应关系,而要维持这种对应关系,就必须把新插入的节点及其后面的所有节点重新进行调整,但这会让时间复制度退化为O(n)

四、解决方法

William Pugh为了解决这个问题,做了一个大胆的处理,不再严格要求这种对应比例关系,而是插入一个节点的时候,随机出一个层数,这样每次插入和删除都不再需要考虑其它节点的层数,实现起来也就简单多了
在这里插入图片描述

五、如何保证效率

一般跳表会设计一个最大层数maxLevel的限制,其次,会设置一个多增加一层的概率p,伪代码如下图
在这里插入图片描述
在Redis的skiplist实现中,p取1/4,maxLevel取32,根据前面的伪代码,定量分析如下图
在这里插入图片描述
一个节点的平均层数,计算如下图
在这里插入图片描述

六、代码实现

首先,得定义一个节点结构体,一个节点由值和它的层数(下一个结点指针的集合)组成
在这里插入图片描述
跳表,则有三个成员,_head是一个哨兵节点,概率p和最大层数maxLevel给缺省值即可,同时,构造函数内,还需给一个随机数种子,后面用来获取节点层数
在这里插入图片描述
在这里插入图片描述
查找某个值,从上往下开始找,让当前节点指针指向哨兵节点,判断它的下一个节点值和目标值的大小关系,下一个节点值为空或比目标值大,就往下走,即层数下标-1;如果比目标值小,就往右走;否则,则表明找到了,直接返回true即可,如果层数下标都小于0了,就返回false,表明没有找到
在这里插入图片描述
类似于单链表,跳表要插入一个节点或删除一个节点,就必须找到目标节点的前一个节点的集合,这样才能插入或者删除节点,例如,插入20,它的前一个节点集合,自上而下为_head,17,19,如下图
在这里插入图片描述
代码类似于查找目标值,不再赘述
在这里插入图片描述
获取节点层数
在这里插入图片描述

插入节点,首先,获取它的前一个节点的集合,其次,获取节点的层数,同时,需要保证_head节点的层数始终是所有节点中最多的,然后就是链表的插入操作了
在这里插入图片描述
删除节点,首先,得判断节点在不在,不在,就不需要删除了,直接返回即可,删除操作也就是链表的删除操作,最后,做一个层数更新,因为删除节点后,头节点的层数可能会有很多是不必要的,影响查找效率,所以做了一个小的优化
在这里插入图片描述
下面的一个leetcode题目,可以用来验证写的对不对
跳表

七、总结

对比平衡搜索树

对比AVL树和红黑树,都可以做到遍历数据有序,时间复杂度也差不多,而跳表的优势在于:

实现简单,容易控制,而平衡树增删改查都更复杂

跳表的额外空间消耗更低,平衡树节点需要存储三个节点指针,父亲和左右孩子,还有平衡因子或颜色等消耗

对比哈希表

相对于哈希表,优势小了很多,首先,哈希表查找数据的时间复杂度为O(1),比跳表快,跳表的优势在于:

遍历数据有序

跳表的空间消耗略小一些,哈希表存在链接指针和表空间消耗

哈希表扩容有性能损耗

哈希表在极端场景下,哈希冲突高,效率下降厉害,需要红黑树来弥补

这篇关于高效的跳表的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/670747

相关文章

在Golang中实现定时任务的几种高效方法

《在Golang中实现定时任务的几种高效方法》本文将详细介绍在Golang中实现定时任务的几种高效方法,包括time包中的Ticker和Timer、第三方库cron的使用,以及基于channel和go... 目录背景介绍目的和范围预期读者文档结构概述术语表核心概念与联系故事引入核心概念解释核心概念之间的关系

SpringMVC高效获取JavaBean对象指南

《SpringMVC高效获取JavaBean对象指南》SpringMVC通过数据绑定自动将请求参数映射到JavaBean,支持表单、URL及JSON数据,需用@ModelAttribute、@Requ... 目录Spring MVC 获取 JavaBean 对象指南核心机制:数据绑定实现步骤1. 定义 Ja

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

Python基于微信OCR引擎实现高效图片文字识别

《Python基于微信OCR引擎实现高效图片文字识别》这篇文章主要为大家详细介绍了一款基于微信OCR引擎的图片文字识别桌面应用开发全过程,可以实现从图片拖拽识别到文字提取,感兴趣的小伙伴可以跟随小编一... 目录一、项目概述1.1 开发背景1.2 技术选型1.3 核心优势二、功能详解2.1 核心功能模块2.

基于Python构建一个高效词汇表

《基于Python构建一个高效词汇表》在自然语言处理(NLP)领域,构建高效的词汇表是文本预处理的关键步骤,本文将解析一个使用Python实现的n-gram词频统计工具,感兴趣的可以了解下... 目录一、项目背景与目标1.1 技术需求1.2 核心技术栈二、核心代码解析2.1 数据处理函数2.2 数据处理流程

Python中bisect_left 函数实现高效插入与有序列表管理

《Python中bisect_left函数实现高效插入与有序列表管理》Python的bisect_left函数通过二分查找高效定位有序列表插入位置,与bisect_right的区别在于处理重复元素时... 目录一、bisect_left 基本介绍1.1 函数定义1.2 核心功能二、bisect_left 与

Python使用FFmpeg实现高效音频格式转换工具

《Python使用FFmpeg实现高效音频格式转换工具》在数字音频处理领域,音频格式转换是一项基础但至关重要的功能,本文主要为大家介绍了Python如何使用FFmpeg实现强大功能的图形化音频转换工具... 目录概述功能详解软件效果展示主界面布局转换过程截图完成提示开发步骤详解1. 环境准备2. 项目功能结

Python Pandas高效处理Excel数据完整指南

《PythonPandas高效处理Excel数据完整指南》在数据驱动的时代,Excel仍是大量企业存储核心数据的工具,Python的Pandas库凭借其向量化计算、内存优化和丰富的数据处理接口,成为... 目录一、环境搭建与数据读取1.1 基础环境配置1.2 数据高效载入技巧二、数据清洗核心战术2.1 缺失

使用Python和SQLAlchemy实现高效的邮件发送系统

《使用Python和SQLAlchemy实现高效的邮件发送系统》在现代Web应用中,邮件通知是不可或缺的功能之一,无论是订单确认、文件处理结果通知,还是系统告警,邮件都是最常用的通信方式之一,本文将详... 目录引言1. 需求分析2. 数据库设计2.1 User 表(存储用户信息)2.2 CustomerO

Java中的StringBuilder之如何高效构建字符串

《Java中的StringBuilder之如何高效构建字符串》本文将深入浅出地介绍StringBuilder的使用方法、性能优势以及相关字符串处理技术,结合代码示例帮助读者更好地理解和应用,希望对大家... 目录关键点什么是 StringBuilder?为什么需要 StringBuilder?如何使用 St