数据结构--跳表

跳表

  • 原理
  • 实现

原理

跳表(skiplist)是一种链表,而链表查询的时间复杂度为O(n),为了优化查询效率,我们可以让每相邻两个节点升高一层,增加一个指针,让指针指向下下个节点:
在这里插入图片描述

这样所有新增加的指针连成了一个新的链表,但它包含的节点个数只有原来的一半。在查询时,我们不再需要与链表中每个节点逐个进行比较了,只需要先比较上面的一层链表,当目标值小于下一个节点的值时,就跳到下一层继续比较,这样比较的节点数大概只有原来的一半。以此类推,我们可以在第二层新产生的链表上,继续为每相邻的两个节点升高一层,增加一个指针,从而产生第三层链表,这样搜索效率就进一步提高了。
在这里插入图片描述
按照上面生成链表的方式,上面每一层链表的节点个数是下面一层的节点个数的一半,这样查找过程就非常类似二分查找,使得查找的时间复杂度可以降低到O(log n)。但是插入删除数据的时候会打乱上下相邻两层链表上节点个数严格的2:1的对应关系,如果要维持这种对应关系,就必须对整个结构重新进行调整,不仅实现繁琐,还影响效率。skiplist的设计为了避免这种问题,不再严格要求上下相邻两层链表上节点个数严格的2:1的对应关系,而是插入一个节点的时候随机出一个层数。这样每次插入和删除都不需要考虑其他节点的层数。
在这里插入图片描述
一般跳表会设计一个最大层数maxLevel的限制,其次会设置一个多增加一层的概率p,这两个参数的取值为p = 1/4,maxLevel = 32,这样新增一个结点时其层数的伪代码如下:
在这里插入图片描述
可以得知跳表中每个结点的平均层数为:
在这里插入图片描述
经过推导,可以得知跳表的查询的平均时间复杂度为O(logN),具体推导过程可以参考 复杂度推导。

实现

#include<iostream>
#include<vector>
#include<time.h>
#include<stdlib.h>using namespace std;float p=0.5;		//产生下一层的概率
int maxLevels=32;	//最大层数template<class T>
struct listNode {listNode(T data, int levels):_data(data),_next(levels, nullptr){}listNode(){}~listNode(){}T _data;					//结点数据vector<listNode<T>*> _next;	//指向下一个结点的指针
};template<class T>
class skipList {
public:skipList(){srand(time(nullptr));_head = new listNode<T>(T(), maxLevels);}~skipList() {listNode<T>* cur = _head;listNode<T>* next =nullptr;while (cur) {next = cur->_next[0];delete cur;cur = next;}}bool search(T data) {listNode<T>* cur = _head;int level = maxLevels-1;while (level>=0) {if (nullptr == cur->_next[level]|| data < cur->_next[level]->_data) {--level;}else if(data == cur->_next[level]->_data) {return true;}else {cur = cur->_next[level];}}return false;}void add(T data) {vector<listNode<T>*> preLinks(maxLevels,nullptr);getPreLink(data, preLinks);listNode<T>* np = new listNode<T>(data, getLevels());int level = np->_next.size() - 1;while (level >= 0) {np->_next[level] = preLinks[level]->_next[level];preLinks[level]->_next[level] = np;--level;}}bool erase(T data) {if (!search(data)) {return false;}vector<listNode<T>*> preLinks(maxLevels, nullptr);getPreLink(data, preLinks);int level = preLinks[0]->_next[0]->_next.size() - 1;listNode<T>* tmp = preLinks[0]->_next[0];while (level >= 0) {preLinks[level]->_next[level] = preLinks[level]->_next[level]->_next[level];--level;}delete tmp;tmp = nullptr;return true;}
private://获取某个结点所有与之相连的前一个结点void getPreLink(T& data,vector<listNode<T>*>& links) {int level = maxLevels - 1;listNode<T>* cur = _head;while (level >= 0) {if (nullptr == cur->_next[level] || cur->_next[level]->_data >= data) {links[level] = cur;--level;}else {cur = cur->_next[level];}}}int getLevels() {int levels = 1;while (rand() <= RAND_MAX * p && levels < maxLevels) {++levels;}printf("level:%d\n", levels);return levels;}
private:listNode<T>* _head;	//头节点
};int main() {skipList<int> sl;printf(" is find %d: %d\n", 1, sl.search(1));sl.add(1);sl.add(2);sl.add(1);sl.add(5);sl.add(9);printf(" is find %d: %d\n", 5, sl.search(5));printf(" is find %d: %d\n", 1, sl.search(1));printf(" is erase %d: %d\n", 1, sl.erase(1));printf(" is erase %d: %d\n", 5, sl.erase(5));printf(" is erase %d: %d\n", 10, sl.erase(10));printf(" is find %d: %d\n", 5, sl.search(5));printf(" is find %d: %d\n", 1, sl.search(1));return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/475146.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学术论文投稿】JavaScript 前端开发:从入门到精通的奇幻之旅

【中文核刊&普刊投稿通道】2024年体育科技与运动表现分析国际学术会议(ICSTPA 2024)_艾思科蓝_学术一站式服务平台 更多学术会议论文投稿请看&#xff1a;https://ais.cn/u/nuyAF3 目录 一、引言 二、JavaScript 基础 &#xff08;一&#xff09;变量与数据类型 &am…

云计算实训室建设的必要性

一、云计算发展的背景 云计算作为一种新型的信息技术服务模式&#xff0c;通过互联网提供动态易扩展且通常是虚拟化的资源&#xff0c;涵盖了从基础设施服务&#xff08;IaaS&#xff09;、平台服务&#xff08;PaaS&#xff09;到软件服务&#xff08;SaaS&#xff09;等多个…

鼠标绘制轮廓

需要对label进行提升&#xff0c;新建MyLabel类&#xff0c;并将其提升到label控件上&#xff0c;详见上篇控件提升 mylabelmouse.h #pragma once #include <QtWidgets/QMainWindow> #include "ui_mylabelmouse.h" #include <QMenu> #include "My…

LLM( Large Language Models)典型应用介绍 1 -ChatGPT Large language models

ChatGPT 是基于大型语言模型&#xff08;LLM&#xff09;的人工智能应用。 GPT 全称是Generative Pre-trained Transformer。-- 生成式预训练变换模型&#xff1a; Generative&#xff08;生成式&#xff09;&#xff1a;可以根据输入生成新的文本内容&#xff0c;例如回答问题…

STM322完全学习——FSMC控制LCD显示屏

一、GPIO初始化 首先这个功能只有大容量的STM32系列有&#xff0c;C8T6是没有的。再就是FSMC这个使用的是GPIO的复用功能&#xff0c;下面先完成我们需要使用的GPIO的初始化 void TFTLCD_GPIO_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_…

MongoDB数据备份与恢复(内含工具下载、数据处理以及常见问题解决方法)

一、工具准备 对MongoDB进行导入导出、备份恢复等操作时需要用到命令工具&#xff0c;我们要先检查一下MongoDB安装目录下是否有这些工具&#xff0c;正常情况下是没有的:)&#xff0c;因为新版本的MongoDB安装时不包含这些工具&#xff0c;需要我们手动下载安装。下载成功之后…

【C语言】volatile 防止编译的时候被优化

volatile 易变的 volatile是 C 和 C 中的一个类型修饰符&#xff0c;用于指示编译器该变量可能在程序之外被更改&#xff0c;因此不应对其进行优化。这在涉及硬件寄存器、信号处理或多线程编程时非常有用。 如果你做过单片机开发&#xff0c;你肯定写过这样的代码&#xff1a;…

el-table实现最后一行合计功能并合并指定单元格

效果图如下&#xff1a; 表格代码如下&#xff1a; <el-table width"100%"ref"tableRef" style"margin-bottom: 15px;":data"jlData"class"tableHeader6"header-row-class-name"headerStyleTr6":row-class-n…

【JavaSE】【网络编程】UDP数据报套接字编程

目录 一、网络编程简介二、Socket套接字三、TCP/UDP简介3.1 有连接 vs 无连接3.2 可靠传输 vs 不可靠传输3.3 面向字节流 vs 面向数据报3.4 双向工 vs 单行工 四、UDP数据报套接字编程4.1 API介绍4.1.1 DatagramSocket类4.1.1.1 构造方法4.1.1.2 主要方法 4.1.2 DatagramPocket…

web——sqliabs靶场——第十二关——(基于错误的双引号 POST 型字符型变形的注入)

判断注入类型 a OR 1 1# 发现没有报错 &#xff0c;说明单引号不是闭合类型 测试别的注入条件 a) OR 1 1# a)) OR 1 1# a" OR 11 发现可以用双引号闭合 发现是")闭合 之后的流程还是与11关一样 爆破显示位 先抓包 是post传参&#xff0c;用hackbar来传参 unam…

【Linux】开发工具make/Makefile、进度条小程序

Linux 1.make/Makefile1.什么是make和Makefile&#xff1f;2.stat命令3.Makefile单个文件的写法4.Makefile多个文件的写法 2.进度条1.回车\r、换行\n2.缓冲区3.进度条1.倒计时程序2.进度条程序 1.make/Makefile 1.什么是make和Makefile&#xff1f; 一个工程中的源文件不计其…

Ubuntu22.04配置强化学习环境及运行相关Demo

什么是强化学习 强化学习&#xff08;Reinforcement Learning&#xff0c;简称 RL&#xff09;是机器学习中的一个重要分支&#xff0c;属于一种基于试错机制的学习方法。它通过让智能体&#xff08;Agent&#xff09;与环境&#xff08;Environment&#xff09;进行交互&…

GitHub 开源项目 Puter :云端互联操作系统

每天面对着各种云盘和在线应用&#xff0c;我们常常会遇到这样的困扰。 文件分散在不同平台很难统一管理&#xff0c;付费订阅的软件越来越多&#xff0c;更不用说那些烦人的存储空间限制了。 最近在 GitHub 上发现的一个开源项目 Puter 彻底改变了我的在线办公方式。 让人惊…

深入解析小程序组件:view 和 scroll-view 的基本用法

深入解析小程序组件:view 和 scroll-view 的基本用法 引言 在微信小程序的开发中,组件是构建用户界面的基本单元。两个常用的组件是 view 和 scroll-view。这两个组件不仅功能强大,而且使用灵活,是开发者实现复杂布局和交互的基础。本文将深入探讨这两个组件的基本用法,…

河道水位流量一体化自动监测系统:航运安全的护航使者

在广袤的水域世界中&#xff0c;航运安全始终是至关重要的课题。而河道水位流量一体化自动监测系统的出现&#xff0c;如同一位强大的护航使者&#xff0c;为航运事业的稳定发展提供了坚实的保障。 水位传感器&#xff1a;负责实时监测河道的水位变化。这些传感器通常采用先进的…

开源可视化工具对比:JimuReport VS DataEase

在当今数据驱动的时代&#xff0c;高效的数据可视化工具成为企业洞察业务、做出决策的关键利器。那对于企业来讲如何选择BI产品呢&#xff1f; 在开源可视化工具的领域中&#xff0c;JimuReport和DataEase 以其独特的优势脱颖而出&#xff0c;究竟谁更胜一筹呢&#xff1f;让我…

jquery还有其应用场景,智慧慢慢地被边缘化,但不会消亡

一、jQuery 的辉煌过往 jQuery 的诞生与崛起 在前端开发的漫长历史中&#xff0c;2006 年诞生的 jQuery 犹如一颗耀眼的新星划破天际。它由 John Resig 创造&#xff0c;一出现便以其独特的魅力迅速吸引了广大开发者的目光。在那个前端技术发展相对缓慢的时期&#xff0c;jQue…

TSmaster 专栏索引

文章目录 软件下载官方中文手册和视频教程窗口对齐关闭窗体报文格式转换TSmaster 硬件配置及连接TSmaster Measurement setup&#xff08;测量设置&#xff09; 软件下载 下载路径&#xff1a;https://www.tosunai.com/downloads/ 官方中文手册和视频教程 窗口对齐 一个工作…

Java小白成长记(创作笔记一)

目录 序言 思维导图 开发流程 新建SpringBoot并整合MybatisPlus 新建SpringBoot 整合MybatisPlus 统一结果封装 全局异常处理 引入数据库 序言 在一个充满阳光的早晨&#xff0c;一位对编程世界充满好奇的年轻人小小白&#xff0c;怀揣着梦想与激情&#xff0c;踏上了学习…

SpringBoot+Vue 2 多方法实现(图片/视频/报表)文件上传下载,示例超详细 !

目录 一、主流方法介绍 1. Base 64 2. 二进制流传输 3. multipart/form-data 4. FTP/SFTP 5. 云存储服务API 二、multipart/form-data 方式上传单个文件 1、前端部分 2、后端部分 三、multipart/form-data 方式上传多个文件 1、前端部分 2、后端部分 四、Base 64 方…