将python dict的最坏情况时间复杂度优化为O(1)

将python dict的最坏情况时间复杂度优化为O(1),python,memory,dictionary,hashtable,complexity-theory,Python,Memory,Dictionary,Hashtable,Complexity Theory,我必须在内存(RAM)中存储500米的两位数unicode字符 我使用的数据结构应具有: Worst Case Space Complexity: O(n) Worst Case Time Complexity: O(1) <-- insertion, read, update, deletion 最坏情况下的空间复杂度:O(n) 最坏情况时间复杂度:O(1)从技术上讲,字典有一个最坏情况O(n),但它不太可能发生,在您的情况下也可能不会发生。我会尝试使用字典,只有在不足以满足您的需要时

我必须在内存(RAM)中存储500米的两位数unicode字符

我使用的数据结构应具有:

Worst Case Space Complexity: O(n)
Worst Case Time Complexity: O(1) <-- insertion, read, update, deletion
最坏情况下的空间复杂度:O(n)

最坏情况时间复杂度:O(1)从技术上讲,字典有一个最坏情况O(n),但它不太可能发生,在您的情况下也可能不会发生。我会尝试使用字典,只有在不足以满足您的需要时才切换到其他实现


大部分性能命中(通常在冲突时进行)在所有调用中摊销。因此,对于最实际的使用,您不会每次调用都得到
O(n)
。事实上,每次调用都会导致
O(n)
命中的唯一情况是在每个键的哈希值与现有键的哈希值发生冲突的病态情况下(即哈希表的最坏使用(或最不幸的使用)

例如,如果您事先知道密钥集,并且知道它们不会发生哈希冲突(即,它们的所有哈希都是唯一的),那么您就不会遇到冲突情况。另一个主要的
O(n)
操作是调整哈希表的大小,但其频率取决于实现(扩展因子/哈希函数/冲突解决方案等),并且它也会根据输入集的不同而不同

在这两种情况下,如果可以使用所有键预先填充dict,就可以避免运行时突然减速。可以将这些值设置为“无”,然后用它们的实际值填充。当最初使用键“启动”dict时,这将导致唯一明显的性能影响,并且未来的值插入应该是恒定时间

一个完全不同的问题是,您打算如何读取/查询该结构?您是否需要附加单独的值并通过密钥访问它们?应该点菜吗?也许
集合
可能比
dict
更合适,因为您实际上不需要
键:值
映射

更新:

根据您在评论中的描述,这听起来更像是数据库要做的工作,即使您使用的是临时集。您可以使用内存中的关系数据库(例如,使用SQLite)。此外,您可以使用类似SQLAlchemy的ORM与数据库进行更紧密的交互,而无需编写SQL

甚至听起来你可能是从数据库中读取数据开始,所以也许你可以进一步利用它

存储/查询/更新大量唯一键入的类型化记录正是RDBMS经过几十年的开发和研究而专门从事的工作。使用预先存在的关系数据库(如SQLite)的内存版本可能是一个更实用、更可持续的选择

尝试使用python的内置模块,并通过提供
”:memory:“
作为构建时的db文件路径来尝试内存版本:

con = sqlite3.connect(":memory:")

您是否有理由关心最坏情况下的性能而不是平均性能?任何合理的哈希表都会给出O(N)的平均性能

如果您确实想要O(1)在最坏情况下的性能,这里有两种可能的方法:

  • 拥有
    max(charCode)-min(charCode)
    项的向量,并直接从unicode字符代码中查找所需的值。这将很好地工作,如果你的钥匙落在一个足够紧凑的范围,你可以适合它在RAM

  • 使用蛮力方法选择散列函数或字典大小(使用允许您控制此操作的自定义字典实现),并不断尝试新函数和/或大小,直到得到一个没有冲突的函数和/或大小。预计这需要很长时间。我不建议这样做

  • 编辑:

    假设您知道您将看到的最小字符代码是1234,最大字符代码是98765。进一步假设您有足够的RAM来容纳98765-1234个元素。我还假设您愿意使用
    numpy
    库或其他一些高效的数组实现。在这种情况下,可以将值存储在向量中,如下所示:

    # configuration info
    max_value = 98765 # replace with your number
    min_value = 1234  # replace with your number
    spread = (max_value - min_value)
    dtype = object # replace with a primitive type if you want to store something simpler
    
    # create the big vector
    my_data = numpy.empty((spread,), dtype=dtype)
    
    # insert elements
    my_char_code              = ...
    my_value_for_my_char_code = ...
    
    assert min_value <= my_char_code < max_value
    my_data[my_char_code - min_value] = my_value_for_my_char_code
    
    # extract elements
    my_char_code              = ...
    assert min_value <= my_char_code < max_value
    my_value_for_my_char_code = my_data[my_char_code - min_value]
    
    #配置信息
    最大值=98765#替换为您的号码
    最小值=1234#替换为您的号码
    排列=(最大值-最小值)
    dtype=object#如果要存储更简单的内容,请替换为基元类型
    #创建大向量
    my_data=numpy.empty((排列),dtype=dtype)
    #插入元素
    我的字符代码=。。。
    我的字符代码=。。。
    
    断言最小值是否可以使用字典进行测试?时间复杂性可能不是一个真正的问题。@msvalkon:你想说实际上我根本不会遇到最坏的情况吗?
    O(n)
    情况的可能性与哈希冲突的数量直接相关,因此,
    dict
    的大小直接相关。您在dict中放入了多少对象?这些是什么类型的字符?UTF-16还是UTF-8?两个字符组合中的绝大多数可能是一小部分字符(例如字母数字字符?)@UtxD:那么如果
    n==2
    ,这是不可接受的吗?我觉得很难相信。让我们假设对象的分布是均匀的,假设哈希表的大小是元素大小的2/3。因此,
    n=500M
    k=333.33M
    。任何一个元素被分配给给定哈希的概率为
    1/k
    。所有5亿个元素被分配到该哈希槽的概率为
    (1/k)^500M
    。这是一个非常非常小的数字。我可能错了,但更有可能的是小行星撞击会在这之前摧毁你的硬盘;它需要n次操作,但在需要调整大小之前需要先插入n次。@PreetKukr