加入收藏 | 设为首页 | 会员中心 | 我要投稿 江门站长网 (https://www.0750zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长资讯 > 评论 > 正文

剖析基础数据结构及其用法

发布时间:2020-11-13 12:06:06 所属栏目:评论 来源:互联网
导读:首先ZSet如果数组存储的话,由于ZSet中存储的元素是有序的,存入的时候需要将元素放入数组中对应的位置。这样就会对数组进行频繁的增删,而频繁的增删在数组中效率并不高,因为涉及到数组元素的移动,如果元素插入的位置是首位,那么后面的所有元素都要被移

首先ZSet如果数组存储的话,由于ZSet中存储的元素是有序的,存入的时候需要将元素放入数组中对应的位置。这样就会对数组进行频繁的增删,而频繁的增删在数组中效率并不高,因为涉及到数组元素的移动,如果元素插入的位置是首位,那么后面的所有元素都要被移动。

所以为了应付频繁增删的场景,我们需要使用到链表。但是随着链表的元素增多,同样的会出现问题,虽然增删的效率提升了,但是查询的效率变低了,因为查询元素会从头到尾的遍历链表。所有如果有什么方法能够提升链表的查询效率就好了。

于是跳表就诞生了。基于单链表,从第一个节点开始,每隔一个节点,建立索引。其实也是单链表。只不是中间省略了节点。

例如存在个单链表 1 3 4 5 7 8 9 10 13 16 17 18

抽象之后的索引为 1 4 7 9 13 17

如果要查询16只需要在索引层遍历到13,然后根据13存储的下层节点(真实链表节点的地址),此时只需要再遍历两个节点就可以找到值为16的节点。

所以可以重新给跳表下一个定义,链表加多级索引的结构,就是跳表

在跳表中,查询任意数据的时间复杂度是O(logn)。时间复杂度跟二分查找是一样的。可以换句话说,用单链表实现了二分查找。但这也是一种用空间换时间的思路,并不是免费的。

除了能够对其中的元素添加权重之外,使用ZSet还可以实现延迟队列。

延迟队列用于存放延迟任务,那什么是延迟队列呢?

举个很简单的例子, 你在某个电商APP中下订单,但是没有付款,此时它会提醒你,「订单如果超过1个小时没有支付,将会自动关闭」;再比如在某个活动结束前1个小时给用户推送消息;再比如订单完成后多少天自动确认收货等等。

用人话解释一遍,那就是过会才要干的事情。

那ZSet怎么实现这个功能?

其实很简单,就是将任务的执行时间设置为ZSet中的元素权重,然后通过一个后台线程定时的从ZSet中查询出权重最小的元素,然后通过与当前时间戳判断,如果大于当前时间戳(也就是该执行了)就将其从ZSet中取出。

那,怎么取?

其实我看很多讲Redis实现延迟队列的博客都没有把这个怎么取讲清楚,到底该用什么命令,传什么参数。我们使用zrangebyscore命令来实现,还记得-inf和inf吗,其全称是infinity,分别表示无限小和无限大。

基础的命令如下:

  • hset 在hash中设置键值对
  • hget 获hash中的某个key值
  • hdel 删除hash中某个键
  • hlen 统计hash中元素的个数
  • hmget 批量的获取hash中的键的值
  • hmset 批量的设置hash中的键和值
  • hexists 判断hash中某个key是否存在
  • hkeys 返回hash中的所有键(不包含值)
  • hvals 返回hash中的所有值(不包含键)
  • hgetall 获取所有的键值对,包含了键和值

其实大多数情况下的使用跟HashMap是差不多的,没有什么较为特殊的地方。

4.2 原理

hash的底层实现也是有两种,ZipList和HashTable。但具体采用哪一种与Redis的版本无关,而与当前hash中所存的元素有关。首先当我们创建一个hash的时候,采用的ZipList进行存储。随着hash中的元素增多,达到了Redis设定的阈值,就会转换为HashTable。

其设定的阈值如下:

  • 存储的某个键或者值长度大于默认值(64)
  • ZipList中存储的元素数量大于默认值(512)

ZipList上面我们专门简单分析了一下,理解这个设定应该也比较容易。当ZipList中的元素过多的时候,其查询的效率就会变得低下。而HashTable的底层设计其实和Java中的HashMap差不多,都是通过拉链法解决哈希冲突。具体的可以参考从基础的使用来深挖HashMap这篇文章。

(编辑:江门站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读