给你30s,如何跟面试官讲清楚跳表

news2025/1/11 4:13:54

查找

假设有如下这样一个有序链表:

想要查找 24、43、59,按照顺序遍历,分别需要比较的次数为 2、4、6

目前查找的时间复杂度是 O(N),如何提高查找效率?

很容易想到二分查找,将查找的时间复杂度降到 O(LogN)

具体来说,我们把链表中的一些节点提取出来,作为索引,类似于二叉搜索树,得到如下结构:

这里我们把 10、30、50、80 提取出来作为一级索引,这样搜索的时候就可以使用二分查找来减少比较次数了。

我们还可以再从一级索引提取一些元素出来,作为二级索引,变成如下结构:

比如如果想要查找 59,那么搜索路径就是下面这样的:

回顾下链表的定义:

class ListNode {
    private int val;
	private ListNode next;
    
    public ListNode(int val) {
        this.val = val;
        this.next = null;
    }
}

我们在每一个节点的基础上添加一个 down 指针,用来指向下一层的节点

class Node {
    private int val;
	private ListNode next;
    private ListNode down;
    
    public ListNode(int val) {
        this.val = val;
        this.next = null;
        this.down = null;
    }
}

这样,一个最简单的跳表节点就定义出来了。

我们这里说的只是最简单的实现,像比如 Redis 的跳表实现和我们说的还是有所不同的,当然了,思想都是一致的

所以跳表是什么?简单来说,跳表就是支持二分查找的有序链表

具体的搜索算法如下:

/* 如果存在 x, 返回 x 所在的节点, 否则返回 x 的后继节点 */  
private Node find(x)  {  
    p = top;  
    while (true) {  
        while (p.next.val < x){
            p = p.next;
        }
        if (p.down == null){
            return p.next;  
        }
        p = p.down;  
    }
    return null;
}

插入

关于插入,大家可能很容易想到往最下面一层的有序链表中添加数据,但是索引该咋办?索引要不要更新呢?

如果不更新索引,就可能出现两个索引节点之间数据非常多的情况,极端情况下跳表就会退化为单链表,从而使得查找效率从 O(LogN) 退化为 O(N)。

所以,我们在插入数据的时候,索引节点也需要相应的改变来避免查找效率的退化

比较容易想到的做法就是完全重建索引,我们每次插入数据后,都把这个跳表的索引删掉全部重建。因为索引的空间复杂度是 O(N),即:索引节点的个数是 O(N) 级别,每次完全重新建一个 O(N) 级别的索引,时间复杂度也是 O(N) 。造成的后果是:为了维护索引,导致每次插入数据的时间复杂度变成了 O(N)。

那有没有其他效率比较高的方式来维护索引呢?

最理想的索引就是在原始链表中每隔一个元素抽取一个元素做为一级索引。换种说法,我们在原始链表中【随机】的选 n/2 个元素做为一级索引是不是也能通过索引提高查找的效率呢?

当然可以,因为一般随机选的元素相对来说都是比较均匀的。如下图所示,随机选择了 n/2 个元素做为一级索引,虽然不是每隔一个元素抽取一个,但是对于查找效率来讲,影响不大,比如我们想找元素 16,仍然可以通过一级索引,使得遍历路径较少了将近一半。

当然了,如果抽取的一级索引的元素恰好是前一半的元素 1、3、4、5、7、8,那么查找效率确实没有提升,但是这样的概率太小了。所以我们可以认为:当原始链表中元素数量足够大,且抽取足够随机的话,我们得到的索引是均匀的。所以,我们可以维护一个这样的索引:随机选 n/2 个元素做为一级索引、随机选 n/4 个元素做为二级索引、随机选 n/8 个元素做为三级索引,依次类推,一直到最顶层索引。这里每层索引的元素个数已经确定,且每层索引元素选取的足够随机,所以可以通过索引来提升跳表的查找效率。

那代码具体该如何实现,使得在每次新插入元素的时候,尽量让该元素有 1/2 的几率建立一级索引、1/4 的几率建立二级索引、1/8 的几率建立三级索引....呢?

其实很简单啦,搞一个概率算法就行了(具体是怎么个概率法这里就不详细解释了),当每次有数据要插入时,先通过概率算法告诉我们这个元素需要插入到几级索引中,然后开始维护索引并把数据插入到原始链表中。

如下所示,插入新元素 12,假设概率算法返回的结果是 4,表示新元素需要插入到 4 级索引中,同时,我们还需要建立 3 级索引、2 级索引和 1 级索引(也就是原始有序链表)

那插入数据时维护索引的时间复杂度是多少呢?

跳表中,每一层索引都是一个有序的单链表,元素插入到单链表的时间复杂度为 O(1),我们索引的高度最多为 LogN,当插入一个元素 x 时,最坏的情况就是元素 x 需要插入到每层索引中,所以插入数据的最坏时间复杂度是 O(LogN),最好的时间复杂度是 O(1)。

删除

跳表删除数据时,要把索引中对应节点也要删掉。如下图所示,如果要删除元素 8,需要把原始链表中的 8 和第 2、3 级索引的 8 都删除掉。

删除元素的过程跟查找元素的过程类似,只不过在查找的路径上如果发现了要删除的元素 x,则执行删除操作。

跳表中,每一层索引都是一个有序的单链表,单链表删除元素的时间复杂度为 O(1),最多需要删除 LogN 个元素(索引层数为 LogN),所以删除元素的总时间包 = 查找元素的时间 + 删除 LogN 个元素的时间 = O(LogN ) + O(LogN ) = 2O(LogN ),忽略常数部分,删除元素的时间复杂度为 O(LogN)。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MipNeRF:多尺度、抗混叠NeRF

Mip-NeRF: A Multiscale Representation for Anti-Aliasing Neural Radiance Fields ​ ICCV 2021 文章目录Mip-NeRF: A Multiscale Representation for Anti-Aliasing Neural Radiance Fields原始NeRF的问题重点componentsCone TracingIPE-integrated positional encodingPE与…

微服务框架 SpringCloud微服务架构 多级缓存 47 Lua 语法入门 47.2 变量和循环

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 多级缓存 文章目录微服务框架多级缓存47 Lua 语法入门47.2 变量和循环47.2.1 数据类型47.2.2 变量47.2.3 循环47 Lua 语法入门 47.2 变量和…

人脸识别Face Recognition综述

综述&#xff1a;https://arxiv.org/pdf/2009.13290.pdf 人脸识别整个系统一般由三个关键要素构成&#xff1a;人脸检测&#xff08;face detection&#xff09;、人脸预处理&#xff08;face preprocess&#xff09;&#xff0c;人脸表征&#xff08;face representation&…

EtherCAT设备协议详解一、EtherCAT概述

EtherCAT简介&#xff1a; • 用于控制自动化技术的以太网&#xff08;EtherCAT&#xff09; 是一种基于以太网的现场总线系统 – 由倍福自动化™于2003年发明 – Beckhoff 创建了 EtherCAT 技术集团&#xff08;ETG&#xff09;于2004年推广议定书 –…

DBCO 点击化学:DBCO-PEG-COOH,DBCO-PEG-acid,羧基聚乙二醇环辛炔

一、产品描述&#xff1a; 西安凯新生物科技有限公司供应的&#xff1a;​DBCO-PEG-COOH&#xff0c;末端羧酸在活化剂&#xff08;如EDC或HATU&#xff09;存在下可与伯胺基反应&#xff0c;形成稳定的酰胺键。DBCO 点击化学可以在水性缓冲液中运行&#xff0c;也可以在有机溶…

来啦|深度讲解风控模型中的参数调优

大数据时代的风控体系必有模型部分的参与&#xff0c;用策略贯穿整个风控体系&#xff0c;以数据为驱动&#xff0c;模型一定是标配内容。于是在模型的建设上&#xff0c;如何精细化地输出一套有效的模型&#xff0c;就是在精细化管理上非常重要的一个差异点。不管传统的逻辑回…

MATLAB处理语音信号基本函数、模块

目录 一、sound函数 二、symerr函数用来计算错误码元数目和误码率 三、From Workspace 模块 四、To Workspace模块 一、sound函数 sound函数可以用来播放音频数据&#xff0c;将矩阵变为立体声播放。 二、symerr函数用来计算错误码元数目和误码率 三、From Workspace 模…

【High 翻天】Higer-order Networks with Battiston Federico (2)

目录测量矩阵表示中心化测度度&#xff08;degree&#xff09;路径&#xff08;path&#xff09;特征向量中心三元闭包和聚类系数单纯同调高阶Lapalacian算子超图拉普拉斯组合拉普拉斯接上回说到了高阶的表示方法&#xff0c;接下来开始高阶系统的测量方法。 测量 具体来说就…

逻辑越权总结(超详细总结涉及各类越权)

逻辑越权总结&#xff08;超详细总结涉及各类越权&#xff09;1.逻辑越权1.1.漏洞原理1.2.漏洞原因1.3.水平越权1.3.1.原理1.3.2.漏洞出现位置1.3.3.危害1.3.4.案例1.3.4.1.登录账号1.3.4.2.获取信息1.3.4.3.修改信息1.4.垂直越权1.4.1.原理1.4.2.漏洞出现位置1.4.3.条件1.4.4.…

艾美捷CpG ODN——ODN 1585说明书

艾美捷CpG ODN系列——ODN 1585&#xff1a;CpG寡脱氧核苷酸&#xff08;A型&#xff09;优化用于NK细胞活化&#xff0c;具有混合的磷酸二酯酶/硫代磷酸酯主链。小鼠TLR9&#xff08;Toll样受体9&#xff09;的特异性配体。 艾美捷CpG ODN 丨ODN 1585化学性质&#xff1a; 序…

kruskalCase克鲁斯卡尔算法

介绍 它的特点和Prim算法不一样&#xff0c;Prim是以点为主&#xff0c;通过顶点遍历没有访问的节点计算最小权重直至一条最小边出来&#xff1b;而Kruskal算法是以边为主&#xff0c;时间复杂度要低一些0(edge); 什么是最小生成树 最小生成树&#xff1a;在一个有n个结点的…

blender教程

文章目录Three的部分课件blender相关资源模型下载地址视图基本操作实现甜甜圈下落的动画day01笔记Three的部分课件 blender相关资源 模型下载地址 视图基本操作 shiftd 复制多个 g键移动 x y z锁定方向 A可以全选 然后选择大小 s 键 拖拽大小 ctrl a 全部应用 切换到不同的编…

Python 图表利器 pyecharts

随着互联网的高速发展&#xff0c;数据量也在疯狂增长&#xff0c;近几年数据分析&#xff0c;数据挖掘的岗位越来越吃香。说到数据分析&#xff0c;就离不开数据的可视化&#xff0c;毕竟图表比冷冰冰的数字直观&#xff0c;一眼就可以看出趋势和结论&#xff0c;毕竟一图胜千…

【AIOT】BLE Paper Relative

Billah, Md Fazlay Rabbi Masum, et al. “BLE Can See: A Reinforcement Learning Approach for RF-based Indoor Occupancy Detection.” Proceedings of the 20th International Conference on Information Processing in Sensor Networks (co-located with CPS-IoT Week 20…

对象池模式

一、对象池模式 1、定义 对象池模式&#xff08;Object Pool Pattern&#xff09;是将对象预先创建并初始化后放入对象池中&#xff0c;对象提供者就能利用已有的对象来处理请求&#xff0c;减少频繁创建对象锁占用的内存空间和初始化时间。属于创建型设计模式。 一个对象池包…

python 模板注入

web 程序包括两个文件&#xff1a; flask-test.py 和 Config.py 文件 #!/usr/bin/env python # -*- coding:utf8 -*- import hashlib import logging from datetime import timedelta from flask import Flask from flask import request from flask import config from flask…

基于java(springboot)篮球竞赛预约管理系统(java毕业设计)

基于java(springboot)篮球竞赛预约管理系统 篮球竞赛管理系统是基于java编程语言&#xff0c;mysql数据库&#xff0c;springboot框架和idea工具开发&#xff0c;本系统分为用户和管理员两个角色&#xff0c;其中用户可以在线注册登陆&#xff0c;查看平台公告&#xff0c;查看…

JSP运动会信息网站

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 模块划分&#xff1a;通知类型、通知信息、裁判信息、运动员信息、项目类型、项目 信息、场地信息、项目安排、报名信息…

【记录】ubuntu20.04安装nvidia显卡驱动

新安装的Ubuntu20.04系统&#xff0c;如果想进行人工智能相关的学习&#xff0c;需要配置一系列的环境&#xff0c;这里我记录下具体的安装过程。 Nvidia显卡驱动的安装 1 安装前需要安装依赖(必须执行) sudo apt-get update #更新软件列表 #安装编译依赖 sudo apt-get inst…

Python urllib CRLF注入漏洞小结

Python urllib CRLF注入漏洞小结 CVE-2016-5699 https://www.suse.com/security/cve/CVE-2016-5699.html before 2.7.10 and 3.x before 3.4.4POC&#xff1a; http://127.0.0.1%0d%0aX-injected:%20header%0d%0ax-leftover:%20:12345/foo漏洞&patch源码&#xff1a;http…