散列表:为什么散列表和链表经常会一起使用?

news2024/10/7 12:17:44

文章来源于极客时间前google工程师−王争专栏。

链表那一节,我们用链表来实现LRU缓存淘汰算法,但是链表实现的LRU时间复杂度是O(n),可以通过散列表将时间复杂度降低为O(1)

跳表那一节,Redis的有序集合是使用跳表来实现的,跳表可以看成一种改进版的链表。Redis有序集合不仅使用了跳表,还用到了散列表。

java中LinkedHashMap这样一个常用的容器,也用到了散列表和链表两种数据结构。

问题:为什么散列表和链表会经常放到一块使用?如何组合使用?

LRU缓存淘汰算法

如何借助散列表,将LRU的时间复杂度降为O(1)。

链表实现如下:

思路:维护一个有序单链表,越靠近链表尾部的结点是越早之前访问的。当有一个新的数据被访问时,我们从链表头开始顺序遍历链表。

  • 如果此数据之前已经被缓存在链表中了,我们遍历得到这个数据对应的结点,并将其从原来的位置删除,然后在插入到链表的头部。
  • 如果此数据没有在缓存链表中,又可以分为两种情况。
    • 如果此时缓存未满,则将此结点直接插入到链表的头部
    • 如果此时缓存已满,则链表尾结点删除,将新的数据结点插入链表头部。

因为不管缓存有没有满,我们都需要遍历一遍链表,所以这种基于链表的实现思路,缓存访问的时间复杂度为O(n)。

总结:一个缓存(cache)系统主要包含如下操作:

  • 往缓存中添加一个数据
  • 从缓存中删除一个数据
  • 在缓存中查找一个数据

这三个操作都要涉及“查找”操作,单纯使用链表法,时间复杂度只能是O(n),如果将散列表和链表两种数据结构组合使用,可以将这三个操作时间复杂度都降低为O(1)。如下图所示:
image

因为我们的散列表是通过链表法解决散列冲突的,所以每个结点会在两条链中。一个链是双向链表,另一个是散列表中的拉链。前驱和后继指针是为了将结点串在双向链表中,hnext指针是为了将结点串在散列表的拉链中。

如上,这种组合存储结构,对于前面的缓存的三个操作,都做到了时间复杂度为O(1)。

Redis有序集合

在有序集合中,每个成员对象有两个重要属性,key(键值)和score(分值)。我们不仅会通过score来查找数据,还会通过key来查找数据。

比如用户积分排行榜有这样一个功能:我们可以通过用户的ID来查找积分信息,也可以通过积分区间来查找用户ID或者姓名信息。这里包含ID、姓名和积分的用户信息,就是成员对象,用户ID就是key,积分就是score。

细化一下Redis有序集合的操作:

  • 添加一个成员对象
  • 按照键值来删除一个成员对象
  • 按照键值来查找一个成员对象
  • 按照分值区间查找数据,比如查找积分在[100,356]之间的成员对象
  • 按照分值从小到大排序成员变量

如果仅仅按照分值将成员对象组织成跳表结构,按照键值来删除、查询成员对象就会很慢,解决方法与LRU缓存淘汰算法的解决方法类似。我们可以再按照键值构建一个散列表,这样按照key来删除、查找一个成员对象的时间复杂度就变成了O(1)。同时,借助跳表结构,其他操作也非常高效。

Redis有序集合的操作还有另外一类,查找成员对象的排名或者根据排名区间查找成员对象。

Java LinkedHashMap

HashMap底层是通过散列表这种数据结构实现的。而LinkdedHashMap前面多了一个Linked,是不是说,LinkedHashMap是一个通过链表法解决散列冲突的散列表呢?

Linked并不仅仅代表它是通过链表法解决散列冲突的。

如下代码会以什么样的顺序打印3,1,5,2这几个key呢?原因是什么?

HashMap<Integer, Integer> m = new LinkedHashMap<>();
m.put(3, 11);
m.put(1, 12);
m.put(5, 23);
m.put(2, 22);

for (Map.Entry e : m.entrySet()) {
  System.out.println(e.getKey());
}

打印的顺序就是3,1,5,2。散列表中数据是经过散列函数打乱之后无规律存储的,这里是如何实现按照数据的插入顺序来遍历打印的呢?

LinkedHashMap也是通过散列表和链表组合在一起实现的。实际上,它不仅支持按照插入顺序遍历数据,还支持按照访问顺序来遍历数据。

// 10 是初始大小,0.75 是装载因子,true 是表示按照访问时间排序
HashMap<Integer, Integer> m = new LinkedHashMap<>(10, 0.75f, true);
m.put(3, 11);
m.put(1, 12);
m.put(5, 23);
m.put(2, 22);

m.put(3, 26);
m.get(5);

for (Map.Entry e : m.entrySet()) {
  System.out.println(e.getKey());
}

这段代码打印的结果是1,2,3,5。为什么是这样的顺序?

每次调用put()函数,往LinkedHashMap中添加数据的时候,都会将数据添加到链表的尾部,所以前4个操作之后,链表中的数据如下图所示:
image

我们再次将键值为3的数据放入到LinkedHashMap的时候,会先查找这个键值是否已经有了,然后再将已经存在的(3,11)删除,将新的(3,26)放到链表的尾部。所以,链表中的数据如下图所示:
image

当代码访问到key为5的数据的时候,我们将被访问到的数据移动到链表的尾部。所以m.get(5)之后,链表中的数据如下图所示:
image

最后打印出来的是1,2,3,5。按照访问时间排序的LinkedHashMap本身就是一个支持LRU缓存淘汰策略的缓存系统!实际上,它们两个的实现原理也是一模一样的。

实际上,LinkedHashMap是通过双向链表和散列表这两种数据结构组合实现的。LinkedHashMap中的“Linked”实际上指的是双向链表,并非指用链表法解决散列冲突。

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

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

相关文章

阿伐曲泊帕的合并用药方案【医游记】

&#xff08;图片来源于网络&#xff01;&#xff09; 阿伐曲泊帕是一种口服的促血小板生成素受体激动剂&#xff0c;用于治疗择期行诊断性操作或手术的慢性肝病相关血小板减少症的成年患者。本文将介绍阿伐曲泊帕的药理作用和药物相互作用。 药理作用 阿伐曲泊帕可以与人体…

H3C SecParh堡垒机 get_detail_view.php 任意用户登录漏洞

与齐治堡垒机出现的漏洞不能说毫不相关&#xff0c;只能说一模一样 POC验证的url为&#xff1a; /audit/gui_detail_view.php?token1&id%5C&uid%2Cchr(97))%20or%201:%20print%20chr(121)%2bchr(101)%2bchr(115)%0d%0a%23&loginadmin成功获取admin权限 文笔生疏…

C语言笔试面试必刷题

&#x1f38a;【面经】专题正在持续更新中&#xff0c;内含C语言&#xff0c;数据结构&#xff0c;Linux&#xff0c;网络编程等✨&#xff0c;欢迎大家前往订阅本专题&#xff0c;获取更多详细信息哦&#x1f38f;&#x1f38f;&#x1f38f; &#x1fa94;本系列专栏 - ​​…

【LSTM-Attention】基于长短期记忆网络融合注意力机制的多变量时间序列预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

URV5使用指南

1. 下载软件 搜索这个地址下载软件 https://github.com/Anjok07/ultimatevocalremovergui/releases/download/v5.6/UVR_v5.6.0_setup.exe 我现在使用的是目前的最新版本5.6.0&#xff0c;后面肯定会出新版&#xff0c;但是流程大致类似。 2.安装软件 基本一直点next就可以&a…

论坛议程|COSCon'23 区块链(B)

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&a…

【链表专题】

链表专题 移除链表元素设计链表反转链表 移除链表元素 移除链表元素&#xff08;Leetcode:203&#xff09; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 /*** Definition for sing…

跟着Nature Communications学作图:R语言ggplot2散点组合误差线展示响应比(Response ratio)

论文 Meta-analysis of the impacts of global change factors on soil microbial diversity and functionality https://www.nature.com/articles/s41467-020-16881-7#Sec15 论文里提供了数据和代码&#xff0c;很好的学习素材 这篇论文是公众号的一位读者留言&#xff0c;…

某验四代滑块验证码逆向分析

逆向目标 目标&#xff1a;某验四代滑块验证码&#xff0c;w 参数逆向主页&#xff1a;aHR0cHM6Ly9ndDQuZ2VldGVzdC5jb20v加密算法&#xff1a;RSA、AES 通讯流程 验证码流程分析 进入网页后&#xff0c;打开开发者人员工具进行抓包&#xff0c;点击滑动拼图验证&#xff0c…

最强英文开源模型LLaMA架构探秘,从原理到源码

导读&#xff1a; LLaMA 65B是由Meta AI&#xff08;原Facebook AI&#xff09;发布并宣布开源的真正意义上的千亿级别大语言模型&#xff0c;发布之初&#xff08;2023年2月24日&#xff09;曾引起不小的轰动。LLaMA的横空出世&#xff0c;更像是模型大战中一个搅局者。虽然它…

支付风控规则

支付宝使用基本风控规则 一、 6个规则 1、规则一&#xff1a;30分钟内&#xff0c;不要连续刷3笔&#xff08;包括失败交易&#xff09;&#xff0c;两笔交易时间间隔大于5分钟&#xff0c;交易金额不要一样&#xff0c;不要贴近限额&#xff1b; 2、规则二&#xff1a;非正…

Python数据结构(链表)

Python数据结构&#xff08;链表&#xff09; 单向链表 单向链表也叫单链表&#xff0c;是链表中最简单的一种形式&#xff0c;它的每个节点包含两个域&#xff0c;一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点&#xff0c;而最后一个节点的链接域则指向…

postgresql14-表的管理(四)

表table 创建表 CREATE TABLE table_name --表名 (column_name data_type column_constraint, --字段名、字段类型、约束字段&#xff08;可选&#xff09;column_name data_type, --表级别约束字段...,table_constraint );CREATE TABLE emp1 --创建表 AS SELECT * FROM empl…

『干货』WebStorm代码模板配置大全

『干货』WebStorm代码模板配置大全 文章目录 『干货』WebStorm代码模板配置大全一、代码模板二、前端 vue 框架2.1 选项式API2.2 组合式API2.3 组合式API TS 三、 前端 UniApp 框架3.1 选项式API3.2 组合式API3.3 组合式API TS 四、前端 React 框架4.1 类声明式4.2 函数声明式…

史上最全 2023全国大学生软件测试大赛——赛后有感

这个比赛什么成分我不好多说&#xff0c;首先说一下我的背景&#xff0c;我们学校是这个比赛的我们省赛的主办方&#xff0c;老师要求我们参加web应用测试和开发者测试&#xff0c;我都参加了&#xff0c;自认为还算是个学习成绩比较好的student&#xff0c;计算机专业前5%&…

【BP-Adaboost预测】基于BP神经网络的Adaboost的单维时间序列预测研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

详解 Diffusion (扩散) 模型

扩散模型是跨不同深度学习领域使用的生成模型。目前&#xff0c;它们主要用于图像和音频生成。最值得注意的是&#xff0c;这些模型是令人印象深刻的图像生成模型&#xff08;例如 Dalle2 和稳定扩散&#xff09;背后的驱动力。我相信您已经看过这些模型生成的闪烁图像。令人惊…

Java基础-IO流

目录 1 File 类的使用 1.1 File类的概念 1.2 构造方法 1.3 常用方法 1.4 课后练习 2 IO流原理及流的分类 2.1 IO原理 2.2 流的分类 2.3 IO流体系 2.4 接口方法 2.4.1 InputStream & Reader相同点 2.4.2 InputStream方法详解 2.4.3 Reader方法详解 2.4.4 Outp…

【数据结构】顺序表实现通讯录

前言 在上一节中我们实现了顺序表&#xff0c;现在我们将使用顺序表完成通讯录的实现。&#xff08;注&#xff1a;本人水平有限&#xff0c;“小屎山”有些许bug&#xff0c;代码冗余且语无伦次&#xff0c;望谅解&#xff01;&#x1f605;&#xff09; 文章目录 一、数据结构…

postgresql14-安装(一)

安装 以管理员权限运行windows版安装包&#xff0c;否则会导致安装不全。过程中记录密码。 在服务管理&#xff0c;启动postgresql服务。 管理工具pgadmin