首页 > 数据库 >记一个问题:为什么 Redis get 方法时间复杂度官网标称 O(1)

记一个问题:为什么 Redis get 方法时间复杂度官网标称 O(1)

时间:2023-08-08 10:59:06浏览次数:39  
标签:return get 复杂度 Redis 链表 key hash he

事情源自于上一篇文章:Redis 数据结构 - 字典 dict

在学习到 dict 结构会用来维护 redis 数据库时,联想到 redis 的 get 方法底层一定会访问 dict 来查找键值。本质上还是查找 hash ,那么既然会查找 hash ,redis 又是采取拉链法来解决 hash 冲突,那当访问的哈希桶是一个链表时,不就会出现对这个链表的遍历了么?

我们都知道,对一个链表的遍历,时间复杂度是 O(n)。

那对于这种情况,查询的时间复杂度就会退化为 O(n) 了,而官网标称 get 的时间复杂度是 O(1)。(官网不该如此不严谨的吧)。

后经社区向大佬提问,得到的回答为:

  1. 确实存在遍历链表的情况
  2. 官网标称 O(1) 为定位到哈希桶的时间复杂度,计算 hash 的确是 O(1)
  3. 上述问题实际体现出对时间复杂度理解的不足
    • 当存在链表遍历时,确实是一个 O(n) 的时间,但是并不代表着就退化成了 O(n),只是介于 O(1) 和 O(n) 之间的一个时间
    • 当一个 hash 表中随处都是链表时,此时要考虑的应该是数据合理性的问题了

以下贴出 redis 的 hash 查找源码(也就只有计算 hash 和 查询链表)

dictEntry *dictFind(dict *d, const void *key)
{
    dictEntry *he;
    uint64_t h, idx, table;

    if (dictSize(d) == 0) return NULL; /* dict is empty */
    if (dictIsRehashing(d)) _dictRehashStep(d);
    h = dictHashKey(d, key);
    for (table = 0; table <= 1; table++) {
        idx = h & DICTHT_SIZE_MASK(d->ht_size_exp[table]);
        he = d->ht_table[table][idx];
        while(he) {
            void *he_key = dictGetKey(he);
            if (key == he_key || dictCompareKeys(d, key, he_key))
                return he;
            he = dictGetNext(he);
        }
        if (!dictIsRehashing(d)) return NULL;
    }
    return NULL;
}

void *dictGetKey(const dictEntry *de) {
    if (entryIsKey(de)) return (void*)de;
    if (entryIsNoValue(de)) return decodeEntryNoValue(de)->key;
    return de->key;
}

所以实际上 redis 的 get 方法是一个介于 O(1) 和 O(n) 之间的一个时间复杂度,大部分时间都是 O(1) 的。

标签:return,get,复杂度,Redis,链表,key,hash,he
From: https://www.cnblogs.com/radish40/p/17613576.html

相关文章

  • vector | push_back()的时间复杂度
    std::vector.push_back()使用push_back()函数时,在不用扩增容量的情况下,时间复杂度是O(1);但如果需要扩增容量,会将旧vector中所有元素复制到新的内存空间中,时间复杂度是O(n)。假定扩增后的容量为原来的m倍假如从一个空vevtor开始,需要插入n次元素,下面推导其时间复杂度:对于第i次......
  • 解决ls: relocation error: /lib64/libacl.so.1: symbol getxattr, version ATTR_1.0
    这个问题是在我conda装了一个包之后就出现了,ls等最基础的命令没有办法用了,网上的帖子也没有很好解决我的问题,而且我试了把我刚刚安的包删掉也没有解决,后面仔细分析一下这个报错,猜测应该是包安装的过程中本地conda中的一些依赖与系统中的一些起了冲突。通过ldd/lib64/libacl.so......
  • P6665 Forget You
    补完番后来做一下这道题。首先考虑\(n=1\)怎么做。一个很直观的感觉是,如果将一组集合进行首尾配对,即\((1,a_i),(2,a_i-1),\cdots\),那么每一对中的两个数地位均等(即在所有方案中的出现次数均等)。证明可以考虑将所有方案进行配对,\((p_1,p_2,\cdots,p_l)\)对应\((a_i-p_l+1,\cd......
  • 使用 RediSearch 在 Redis 中进行全文检索
    Redis大家肯定都不陌生了,作为一种快速、高性能的键值存储数据库,广泛应用于缓存、队列、会话存储等方面。然而,Redis在原生状态下并不支持全文检索功能,这使得处理文本数据变得相对困难。但是在有一些场景下还需要这样的功能,有什么好办法呢?答案就是RediSearch。RediSearch是Redis......
  • Linux安装Jdk,gcc,nginx,redis,nacos
    Linux安装JDK1、下载JDK下载地址:oracle.com/java/technologies/downloads/#java82、将下载好的压缩包放到指定文件夹下3、进入文件夹目录cdsoftware4、创建java目录mkdir/usr/local/java5、解压压缩包到创建好的文件夹tar-zxvfjdk-8u341-linux-x64.tar.gz-C/us......
  • [系统设计] 分布式系统 (1) 分布式锁(1)基于Redis(setnx)实现分布式锁组件
    1序言近期遇到一个问题:外部查询缓存了InfluxDB中物联网数据表的字段信息元数据的本地缓存(基于GoogleGuavaCache、及其RefreshAfterWrite(seconds,TimeUnit.SECOND))的Web接口为什么会缓存Influxdb的字段信息呢?因为字段信息非常多,多到每次查询时需要花费1.5-2分钟(80秒......
  • springboot中redis作为缓存使用
    springboot中redis作为缓存使用springboot中的redis作为缓存使用application.yamlserver:port:8089#servlet:#context-path:/demoRedis1spring:redis:host:127.0.0.1port:6379password:pom文件<!--添加的依赖--><!--Redis......
  • Java Web Service Get请求使用指南
    JavaWebServiceGet请求使用指南在当今互联网时代,WebService已经成为了现代软件开发中不可或缺的一部分。而Java作为一种广泛使用的编程语言,自然也提供了丰富的工具和库来支持WebService的开发。本文将为大家介绍如何使用Java编程语言进行WebService的Get请求。JavaWebserv......
  • Airflow 2.2.6 + MySQL 8.0.27 + Redis 7.0.12 部署Airflow任务调度平台
    本docker-compose文件在centos7.9系统,docker版本为24.0.2上测试的如果你的docker版本低于24.xxx就需要手动安装docker-compose,高于24就不需要安装了,docker已经自带了官方文档,关于docker部署1.先执行mkdir-p./dags./logs./plugins./config./......
  • uniapp获取位置时显示getLocation:fail the api need to be declared in the required
    uniapp获取位置时显示getLocation:failtheapineedtobedeclaredintherequiredPrivateInfosfieldinapp.json/ext.json解决方式:1.manifest.json文件 "mp-weixin" 中添加"permission":{"scope.userLocation":{&quo......