各种链表的描述

该文章不适合初学数据给链表的人看,因为里面涉及到了其他的数据结构和高级的链表数据结构

ArrayList

arrayList的添加流程:有兴趣可以自己debug进去看看

arrayList

在使用idea进行debug的时候,记得将这个配置关闭,否则不能看到数组中为null的元素

image-20230210153033370

在删除数组元素的时候,是将这个位置的后面的元素全部向前一位

System.arraycopy(
elementData, 	:从 哪个数组开始移动
index+1, 		:从哪个位置开始移动
elementData, 	:移动到哪个数组
index,			:移动到数组的哪个位置
numMoved		:要移动的长度
);

LinkedList

linkedList的结构就比较简单,每次只是需要改变链表中每个node结点的指针即可

关于栈和队列

栈的结构是后进先出的,所以这种结构使用链表来设计是比较高效的,因为每次都是修改列表的队尾部分,所以使用链表增删改查都效率都是较高的,但是在jdk1.8的时候栈的底层是ArrayList的数据结构,下图的debug的结果:

image-20230210155647842

队列

其实linkedList就是一个队列,它具有队列和双向队列的结果,下图是它的继承图

image-20230210160456647

CopyOnWriteArrayList

写时复制技术

Copy On Write:在写的时候,复制一份副本,保证写和读可以同时发送

示例图

image-20230210164823990

图片来源:CopyOnWriteArrayList实现原理及源码分析

docker中的写时复制

image-20230210204325900

这个图可能有点错误,具体的可以参考

什么是docker的写时复制(CoW)?有什么作用?

即可读层不懂,只编写可写层

Skip list(跳表)

java中没有跳表的直接实现类,但是在redis中有,在redis有一个操作类型:Sorted Set。Sorted Set的结构如下<key,key对应的值>,通常可以用于实时热点的排行榜。

排行榜的结构如下:<事件名称,事件的热度>,而排行榜是根据热度进行排名的,且热度是可以更新的。所以需要一种数据结构来将更新后的数据放在适当的位置

既然是热度排行榜,那么之前的热度肯定是有序的,在有序的结果集中找到适合一新个数值的最快算法是什么?肯定是二分查找啊。

但是遗憾的是,二分查找只适用于数组,不能用于链表。那么有没有一种结构可以作为链表的二分查找呢?跳表就可以大致做到链表的二分查找效果

下图是跳表的结构:

跳表的结构

图片来自于:Redis(十二)-Redis的数据结构之跳表

如果层数足够多的话(以61层为例),大致可以存2^61跳数据,算下来和二分查找的时间复杂度差不多

ziplist(压缩列表)

压缩链表这种数据结构不是java中的,而且java也不可能实现,它是redis对于内存的机制压缩而产生的一种数据结构。

在c语言中,一个指针占用的内存大小是8字节(64bit),而8字节可用表示的内存大小为4294967296GB,而redis使用的内存很显然是用不了这么多的,那么有没有什么方法替代指针呢?很显然–没有,因为指针可用指向不连续的存储空间。

但是对于连续的存储空间来说,我们可用使用内存空间的占用长度来替代指针,使用4字节(32-1)位的长度来 表示连续的内存空间占用情况,可用表示32G,而这符合当前机器的标准,所以redis中使用连续的存储空间中的压缩列表来替代指针,尽可能的压缩机器内存,提高内存利用率

压缩列表结构如下:

压缩列表

参考:一套打通Redis(2)–列表的底层实现-链表、压缩链表与快速列表

可以看出来,压缩列表不适合里面元素太大的场景

quicklist(快表)

顾名思义,即它比一般的链表要快,有点Skip list(跳表的思想),其实例如下:

quickList

参考:Redis|快速表、压缩表和双向链表(重点介绍quicklist)

它的结构描述如下:

将压缩列表存储在每一个快表的节点中,当需要某一个位置的数据的适合,可用从压缩列表中得到节点数,如果该数据不知压缩列表的数种,那么就会到下一个快表节点种查找,从而节约了多次在压缩列表中的查询

说明

以上关于redis的各种列表都是基于redis6的,其中redis6的各种数据的底层数据类型如下:

  • string:Int、SDS
  • List:ZipList、quicklist
  • hash:数据量少zipList,数量多hashTable
  • set:IntSet、HashSet
  • zSet:数据量少zipList,数量多skipList

可以 看出来 ,在很多地方都用了压缩列表的,说明redis对内存的压缩非常极致

listpack(紧凑列表)

这是在redis5的时候出现的数据类型,在redis7的时候替代了zipList。

zipList有一些缺点:

  • 查找复杂度高:使用quickList来解决了
  • 连续更新风险

连续更新风险:即在非末尾插入了一个元素,后面的数据因为保留了前一个元素的长度,所以后一个数据中保存长度的位置也要发送更改,如果后一个数据更改后的长度又发送了变化,再后一个元素的保存长度数据又要更改,依次往下

listpack的改进是:不保留前一个数据的长度,而是保留当前数据的长度,如图

紧凑列表

参考连接:ziplist、quicklist、listpack源码设计解读

总结

列表是一种基础的数据结构,可能很多人认为只是切换一下指针,其中我也是这样认为的,知道后来学习了redis的底层数据结构,才发现列表可以又很多的样式。

知道的越多,越能发现自己的无知

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值