访问Python dict的时间复杂度

时间:2009-12-26 14:32:02

标签: python hash dictionary complexity-theory

我正在编写一个简单的Python程序。

我的程序似乎受到线性词典的访问, 即使算法是二次的,它的运行时间也呈指数增长 我使用字典来记忆值。这似乎是一个瓶颈。

我正在散列的值是点的元组。 每个点是:(x,y),0 <= x,y <= 50
字典中的每个键是:2-5点的元组:((x1,y1),(x2,y2),(x3,y3),(x4,y4))

键的读取次数比写入次数多很多次。

我是否认为python dicts受到这些输入的线性访问时间的影响?

据我所知,套装保证了对数访问时间 如何在Python中使用集合(或类似的东西)模拟dicts?

编辑根据请求,这是memoization函数的(简化)版本:

def memoize(fun):
    memoized = {}
    def memo(*args):
        key = args
        if not key in memoized:
            memoized[key] = fun(*args)
        return memoized[key]
    return memo

6 个答案:

答案 0 :(得分:39)

Time Complexity。 python dict是一个hashmap,因此如果hash函数不好并导致大量冲突,则最坏的情况是O(n)。然而,这是一种非常罕见的情况,其中添加的每个项目都具有相同的哈希值,因此被添加到同一个链中,对于主要的Python实现来说,不太可能。平均时间复杂度当然是O(1)。

最好的方法是检查并查看正在使用的对象的哈希值。 CPython Dict使用int PyObject_Hash (PyObject *o),相当于hash(o)

经过快速检查后,我还没有设法找到两个散列为相同值的元组,这表明查找是O(1)

l = []
for x in range(0, 50):
    for y in range(0, 50):
        if hash((x,y)) in l:
            print "Fail: ", (x,y)
        l.append(hash((x,y)))
print "Test Finished"

CodePad(24小时可用)

答案 1 :(得分:3)

你不正确。 dict访问权限不太可能是您的问题。几乎可以肯定是O(1),除非你有一些非常奇怪的输入或非常糟糕的散列函数。粘贴应用程序中的一些示例代码以获得更好的诊断。

答案 2 :(得分:3)

如果提供示例代码和数据,建议会更容易。

访问字典不太可能是一个问题,因为该操作是O(1) on average, and O(N) amortized worst case。内置散列函数可能会遇到数据冲突。如果您遇到内置散列函数问题,可以自行提供。

  

Python的字典实现   降低了平均复杂度   字典查找到O(1)by   要求关键对象提供   “哈希”功能。这样的哈希函数   获取关键对象中的信息   并用它来产生一个整数,   称为哈希值。这个哈希值   然后用于确定哪个   “桶”这个(键,值)对应该   被放入。

您可以覆盖类中的__hash__方法来实现这样的自定义哈希函数:

def __hash__(self):    
    return hash(str(self))

根据您的数据实际情况,您可能能够提供一个比标准函数具有更少冲突的更快哈希函数。但是,这不太可能。有关详细信息,请参阅Python Wiki page on Dictionary Keys

答案 3 :(得分:2)

  

我的程序似乎受到字典线性访问的影响,即使算法是二次方,它的运行时间也呈指数级增长。

     

我使用字典来记忆值。这似乎是一个瓶颈。

这是您的记忆方法中存在错误的证据。

答案 4 :(得分:1)

正如其他人所指出的那样,访问Python中的dicts很快。鉴于它们的核心作用,它们可能是语言中最好的数据结构。问题出在其他地方。

你记得有多少元组?你考虑过内存占用吗?也许你把所有时间花在内存分配器或分页内存上。

答案 5 :(得分:1)

回答您的具体问题:

Q1:“”“我是否认为python dicts受到这些输入的线性访问时间的影响?”“”

A1:如果你的意思是平均查询时间是O(N),其中N是dict中的条目数,那么很可能你错了。如果你是对的,那么Python社区非常想知道你在什么情况下是正确的,这样可以减轻问题或者至少可以警告这个问题。 “样本”代码和“简化”代码都不是有用的。请显示重现问题的实际代码和数据。代码应该用诸如dict项的数量和每个P的dict访问次数之类的东西进行检测,其中P是密钥中的点数(2 <= P <= 5)

Q2:“”据我所知,套装保证了对数访问时间。 如何在Python中使用集合(或类似的东西)模拟dicts?“”“

A2:集合在什么情况下保证了对数访问时间? Python实现没有这样的保证。最近的CPython版本实际上使用了一个缩减的dict实现(仅键,没有值),所以期望是平均O(1)行为。你怎么能用任何语言的集合或类似的东西模拟dicts?简短回答:如果你想要dict.has_key(key)之外的任何功能,那么极其困难。