python字典相关操作的复杂度

最近对大量数据做处理时,耗时较大,后来通过改进用了字典,一定程度上提高了效率。
字典与列表的不同之处在于,可以通过键而不是位置来访问字典中的项。字典上的get item和set item操作是O(1)。另一个重要的字典操作是contains操作,即检查一个键是否在字典中也是O(1)。下图总结了所有字典操作的效率。该图中提供的效率是针对平均性能的。在一些罕见的情况下,contains、get item和set item操作可能会退化为O(n)性能。
在这里插入图片描述
字典相关操作的代码:

# dictionary 类似Map哈希表
d = {'cat': 'cute', 'dog': 'furry'}
print(d['cat'])
print('cat' in d)
d['fish'] = 'wet'
print(d['fish'])
# print(d['monkey'])  # KeyError: 'monkey' not a key of d
print(d.get('monkey', 'N/A'))
print(d.get('fish', 'N/A'))
del d['fish']
print(d.get('fish', 'N/A'))

d = {'person': 2, 'cat': 4, 'spider': 8}
for animal in d:
    legs = d[animal]
    print('A %s has %d legs' % (animal, legs))
    
d = {'person': 2, 'cat': 4, 'spider': 8}
for animal, legs in d.items():
    print('A %s has %d legs' % (animal, legs))
    
nums = [0, 1, 2, 3, 4]
even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0}
print(even_num_to_square)

使用python字典来进行查找的话速度非常快,是O(1)级别,因为是用hash实现的。
哈希表也叫散列表,可理解为借助哈希函数对数组这种数据结构进行扩展,利用的是数组支持按照下标随机访问元素的特性,是存储 Key-Value 键值对的集合。参考文章:知乎:什么是哈希表?
存放记录的哈希表结构如图所示(数组下标index与[key,value]键值对):
在这里插入图片描述

关于哈希表的基本原理可简单理解为:当我们用字典当中的key去获取对应的value时,会将key转换为列表当中的index,通过index去准确快速地获取到value。这里面的关键在于哈希函数与冲突检测
key转化为index的函数就称为哈希函数,其中key既可以为数字,也可以为字符串,哈希函数通过计算模值或计算字符串哈希值得到对应的数组下标(存储地址)。可见,不需要遍历地址,而只通过一次计算即得到地址,从而方便取该地址存放的值,则在不冲突的理想情况下,时间复杂度为O(1)。总体来说,若设计好哈希函数减少冲突次数,则时间复杂度的平均性能为O(1)。
而在计算index的时候要注意冲突检测(例如多个key通过哈希函数后同时对应到同一index),这时候主要通过index与其存放的key进行处理(可参考如下代码)。根据冲突检测的处理方法可以将检测方法分为开放寻址法拉链法
我们可以通过如下数组模拟散列表的问题进行理解,该问题实现了加入元素与判断元素是否存在的功能。通过计算得到要查找的key所对应的数组的下标k,并进行冲突检测(若有冲突,则k++),从平均性能上来说,确实可以达到O(1)。这种冲突检测方法为开放寻址法,除此之外还有基于链表的拉链法。该问题中存放的是key,即仅存放不重复的元素,其实就类似于hashset。若加入value,每个数组位置存放一个键值对[key, value],其实就类似于hashtable,key通常用来冲突检测与快速查找,而value用于存储对应于key的值。而hashtable与dictionary是较为相近的,具体区别之后再具体调研。
数组模拟散列表问题链接如下:
AcWing 840. 模拟散列表
该问题C++代码:

#include <cstring>
#include <iostream>

using namespace std;
// N为模数,null为空位置的初始值
// N通常取大于范围的质数,取质数冲突的概率最小
const int N = 2e5 + 3, null = 0x3f3f3f3f;

int h[N];

int find(int x) // 哈希函数:通过key得到对应的数组下标索引值(k)
{
    int k = ((x % N) + N) % N; // key->index(k)
    while(h[k] != null && h[k] != x) // 冲突检测
    {
        k ++;
        if(k == N) k = 0;
    }
    return k; // 返回地址
}

int main()
{
    int n;
    scanf("%d", &n);
    
    // 数组初始化为无穷大,无穷大表示不存放值
    memset(h, 0x3f, sizeof h); 
      
    while(n --)
    {
        char op[2];
        int x;
        scanf("%s%d", op, &x);
        int k = find(x);
        if(*op == 'I') h[k] = x; // 插入元素
        else // 判断存在
        {
            if(h[k] != null) puts("Yes");
            else puts("No");
        }
    }
    
    return 0;
}

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python 中的字典是一种基于哈希表实现的高效数据结构,它支持快速插入、查找和删除操作。下面简要介绍 Python 字典底层的实现原理。 1. 哈希表 Python 字典的底层实现基于哈希表,它是一种由数组和链表组成的数据结构。哈希表的基本思想是将每个键值对映射到一个唯一的位置,这个位置称为哈希桶,通过哈希桶可以快速查找、插入和删除键值对。 在 Python 中,哈希桶通过一个数组来实现,每个元素都是一个指向链表头部的指针,这个链表中存储了哈希值相同的键值对。当哈希表中的键值对数量增加时,可以动态地扩容哈希表,以保证哈希桶的利用率。 2. 哈希函数 哈希函数是将键值对映射到哈希桶的关键,它需要满足以下两个条件: - 相同的键值对应相同的哈希桶; - 不同的键尽可能映射到不同的哈希桶。 在 Python 中,哈希函数使用的是一种称为 MurmurHash 的算法,它能够快速计算出任意长度的输入数据的哈希值,并且哈希值的分布比较均匀,能够尽可能地避免哈希冲突。 3. 冲突处理 由于哈希函数的映射是有限的,因此不同的键值对可能会映射到同一个哈希桶中,这种情况称为哈希冲突。Python 中的哈希表通过链表来处理哈希冲突,同一个哈希桶中的键值对会被存储在一个链表中,当出现哈希冲突时,新的键值对会被插入到链表的头部,这样就能够保证查找时优先找到最近插入的键值对。 4. 字典操作复杂度 Python 字典操作复杂度字典中键值对的数量和哈希桶的利用率有关。在哈希桶的利用率比较低时,字典操作复杂度接近于常数级别,即 $O(1)$,这是由于哈希桶的利用率越低,哈希冲突的概率就越低,查找、插入和删除操作时间复杂度也就越低。在哈希桶的利用率比较高时,字典操作复杂度会逐渐接近于线性级别,即 $O(n)$,这是由于哈希冲突的概率增加,需要查找更多的链表节点才能找到目标键值对。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值