首页 > 其他分享 >Go语言对比跳表和Map

Go语言对比跳表和Map

时间:2022-10-31 16:57:34浏览次数:70  
标签:Map 链表 跳表 key Go 数据结构 SkipList

最近学习一个GO语言写的开源项目Lotusdb, https://github.com/flower-corp/lotusdb, 其中使用跳表作为数据结构来缓存Key-Value,产生了疑惑为什么不直接用Map而要自己写个跳表呢? 带着这个疑惑我就进一步学习了很多知识。学习过程记录下来。

跳表
首先第一个知识点跳表,跳表可以实现二分查找的有序链表, 这里直接借用一个图来说明

 

 


这张图来自极客时间- 王争老师《数据结构与算法之美》 https://time.geekbang.org/column/article/42896

举例说明它的原理, 比如我们要找key=5的结点,我们先在二级索引上面找到1, 向下找到第一级索引中找到4和7之间,从4再向下,到了原始链表,从4开始遍历,就能找到5这个结点了。它能提高我们查找的效率。而且原始链表是有序的,在需要顺序的场景,它就比较有用了。

这里有篇文章详细的描述了跳表的原理 Skip List--跳表(全网最详细的跳表文章没有之一)

跳表的查询,插入,删除时间复杂度O(logn), 空间复杂度是增加了索引,索引的空间复杂度O(n), 但是索引只是key,所以占用空间可以忽略

Map
第二个知识点“Map”, 以前我只知道Map是用来存储Key-Value的,能够通过key,快速的找到Value, 但是它底层的数据结构是什么,我就不没有细究,这次把它认真的学习了下,实际上Map是数组+链表,看下图

 

 


这张图来自博客园 go map数据结构和源码详解

举例说明, 对于某个key, 我们先用对key进行hash, hash成数组的下标, 对应图中的Hmap.buckets,通过数据下标就找到了它的位置。那么对于发生hash 碰撞的情形怎么办呢? 不同的key,hash成相同的值的情况,Go语言是链接到了一个8个元素的数组, 遍历这个数组就能找到我们要的元素了,对于超过8个的情况就用图上的溢出指针指向个链表。

通过这个大体的分析我们能够知道map的时间复杂度是O(1), 空间复杂度O(0.1875n) ~ O(n)之间

那么map要比跳表在性能上更优秀。如何来验证这一点呢? 接下来我们就通过实际的代码来确定这个实验。

 

这里用到go 自带的benchmark测试

插入性能
首先我们测试插入性能, 这里skiplist 我们使用"github.com/flower-corp/lotusdb/arenaskl", map使用go runtime自带的

 

 


插入SkipList和Map
上面两个方法分别是存入skip list 和 map, 根据recordNum的数据,插入数据到这两个数据结构中

 

 


通过对比这两个benchmark, 我们插入相同的100000条记录,InsertSkipList 1S中可以做24次, InsertMap 1S中可以做46次, 性能相差一倍。

读取性能

 

读数据
分别读取SkipList和Map中的数据。

 

 

 

 

 


读性能对比
可以看到读取相同的记录数,ReadMap 要比ReadSkipList快一倍多,一个是74,一个是32.

 

总结
通过数据结构的原理分析和实际代码验证,我们能看出Map的性能确实要比SkipList快,那么回到我们最初的问题,为什么要选SkipList 呢, 我想答案应该是SkipList是有序的, 后面的操作需要用到它的有序性来存储到磁盘。实际上LSM Tree数据库都是使用SkipList来作为它的数据结构,这点在我们前面的跳表原理的那片博客中有讲到。至此疑问得到解答。通过这个分析源码,我学到了Map和SkipList的原理,学到了如何用Go来写Benchmark test,这个benchmark test确实很好用,对比不同的方法的性能,它很优秀而且天然集成在Go的标准库中,是开发的好帮手。

标签:Map,链表,跳表,key,Go,数据结构,SkipList
From: https://www.cnblogs.com/dk168/p/16844904.html

相关文章

  • mmap
    学习bolt源码 bbolt,发现有一处使用到mmap, 开始的时候不明白是什么东西,很是好奇,怎么就把硬盘上的文件读到内存了,并没有看到read方法,后来查了资料,知道原来使用了mmap,所谓......
  • The bean 'xxxUserMapper' could not be injected because it is a JDK dynamic proxy
    Thebean'xxxUserMapper'couldnotbeinjectedbecauseitisaJDKdynamicproxy原因Mapper代码当时如下:publicinterfaceXxxUserMapperextendsMapper<XxxUser......
  • 【THM】Nmap Post Port Scans(Nmap端口扫描后期工作)-学习
    本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/nmap04通过学习相关知识点:了解如何利用Nmap进行服务和操作系统检测,使用Nmap脚本引擎(NSE)并保存扫描结......
  • OJ周赛第一次——Good morning
    Goodmorning 问题描述一天,小马在A点过B分准时起床(24小时制),而小亮在C点过D分1秒准时起床。 输入 输入4个整数A,B,C,D0≤A≤230≤B≤590≤C≤230≤D≤5......
  • Redis系列8:Bitmap实现亿万级数据计算
    Redis系列1:深刻理解高性能Redis的本质Redis系列2:数据持久化提高可用性Redis系列3:高可用之主从架构Redis系列4:高可用之Sentinel(哨兵模式)Redis系列5:深入分析Cluster集......
  • go-gin实现文件上传
    见代码packagemainimport( "fmt" "github.com/gin-gonic/gin" "net/http")funcmain(){ server:=gin.Default() gin.SetMode(gin.DebugMode) fmt.Printl......
  • Nginx配置godaddy证书
    在阿里云上购买的证书下载直接上传服务器配置到Nginx就可以直接使用,但是godaddy的需要自己手动生成证书:1.在网站:https://www.myssl.cn/tools/create-csr.html上生成KEY及......
  • go: no such tool "compile"(记录)
    这是一次离谱问题和胡搞一通莫名解决的记录背景:win11系统下,原有的go1.18更新到go1.19后出现了莫名的go:nosucntool"compile"的情况。当时检查goenv,如下:PSD:\Desk......
  • 设置Google浏览器不更新
    设置Google浏览器不更新右键计算机=>管理,在计算机管理(本地)=>系统工具=>任务计划程序=>任务计划程序库中找到两个和Google自动更新相关的任务计划:GoogleUpdateTaskMa......
  • Mybatis 报错Mapper method 'xxx' has an unsupported return type
    报错原因:出现这种错误,说明sql语句执行成功,只是返回类型出了问题。解决方法:insert、delete、update操作默认返回一个int类型的整数,将增删改的接口改成int或者void即可。......