Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
python集与元组查找。元组中的查找是否为O(1)?_Python - Fatal编程技术网

python集与元组查找。元组中的查找是否为O(1)?

python集与元组查找。元组中的查找是否为O(1)?,python,Python,最近我在这里看到一个关于python的问题 :。评论中有人回答说可以这样做: 1 in(1,2,3)检查项目集合中是否存在1。但根据我的说法,{1,2,3}中的1应该快得多。正如您在讨论中所看到的,一些声誉很高的人继续说,()对于固定大小的输入更快。并且具有比{}更快的查找速度。我在这里问这个问题是因为我想知道哪一个是正确的,而且我不知道()是fiexd size还是variable size。我只是要求在原始问题中引用一下,这样如果我错了,我可以纠正自己,但是用户在清除我的计算机科学基础知识时

最近我在这里看到一个关于python的问题

:。评论中有人回答说可以这样做:


1 in(1,2,3)
检查项目集合中是否存在1。但根据我的说法,{1,2,3}中的
1应该快得多。正如您在讨论中所看到的,一些声誉很高的人继续说,
()
对于固定大小的输入更快。并且具有比
{}
更快的查找速度。我在这里问这个问题是因为我想知道哪一个是正确的,而且我不知道
()
fiexd size
还是
variable size
。我只是要求在原始问题中引用一下,这样如果我错了,我可以纠正自己,但是用户在清除我的计算机科学基础知识时,没有提到他的论点,即
在元组中查找是O(1)
。所以我在这里问它。

当你说类似
O(n)
的话,你必须说出
n
是什么。这里,
n
是元组的长度。。。但元组不是一个输入。你不能把元组当作参数或任何东西
n
在您链接的对话中始终是
2
,或者对于示例元组是
3
,因此对于这个特定的
n
O(n)
O(2)
O(1)
是一样的

正如您现在可能已经注意到的,当
n
是一个常数时,谈论
O(n)
没有多大意义。如果你有这样一个函数

def in_(element, tup):
    return element in tup
您可以说运行时是
O(n)
元素比较,其中
n
len(tup)
,但对于类似

usr in ('Y', 'y')

谈论
n
不是很有用。

当你说类似
O(n)
的话时,你必须说出
n
是什么。这里,
n
是元组的长度。。。但元组不是一个输入。你不能把元组当作参数或任何东西
n
在您链接的对话中始终是
2
,或者对于示例元组是
3
,因此对于这个特定的
n
O(n)
O(2)
O(1)
是一样的

正如您现在可能已经注意到的,当
n
是一个常数时,谈论
O(n)
没有多大意义。如果你有这样一个函数

def in_(element, tup):
    return element in tup
您可以说运行时是
O(n)
元素比较,其中
n
len(tup)
,但对于类似

usr in ('Y', 'y')

谈论
n
不是很有用。

尽管另一位评论者在技术上正确地认为
中的x在运行时是O(1),但比较相同大小的集合和元组的性能仍然很有趣。讨论可以概括为考虑包含{,代码,x,{a,b,c,…} /代码>的表达式的不同程序。如果表达式由
n
项组成,则在所有可能的此类程序中,
n
可被视为big-O分析的输入。(如果仍然有人坚持认为可以在运行时提供不同的
n
,只需想象该函数是使用
exec
创建的)

这类表达式的性能问题是Python运行时必须构造一个一次性集,用于
测试中的
,然后立即丢弃它。这在生成的部件中清晰可见:

>>> import dis
>>> def is_valid(x):
...     return x in {1, 2, 3}
... 
>>> dis.dis(is_valid)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 (2)
              9 LOAD_CONST               3 (3)
             12 BUILD_SET                3
             15 COMPARE_OP               6 (in)
             18 RETURN_VALUE        
构造一组
n
元素显然至少要花费O(n)。换句话说,使用一个集合(作为文字常量实现)的测试是而不是O(1),因为解释器必须构造集合。这就是评论者试图通过提及建筑成本来理解的

事实上,它变得更奇怪;由于Python VM的性质,编译器可以在编译时构造仅由数字文本组成的元组,它可以:

>>> import dis
>>> def is_valid(x):
...     return x in (1, 2, 3)
... 
>>> dis.dis(is_valid)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               4 ((1, 2, 3))
              6 COMPARE_OP               6 (in)
              9 RETURN_VALUE        
注意
(1,2,3)
常量不需要逐项构建-这是因为它已经由编译器构建并插入到函数的环境中。因此,
的这个实现是有效的
实际上可能比使用set的实现快
!这很容易测试:

$ python -m timeit -s 'def is_valid(x): return x in {1, 2, 3}' 'is_valid(-1)'
10000000 loops, best of 3: 0.189 usec per loop
$ python -m timeit -s 'def is_valid(x): return x in (1, 2, 3)' 'is_valid(-1)'
10000000 loops, best of 3: 0.128 usec per loop
同样,另一位评论者是对的

增加集合/元组的大小并不会使平衡朝着有利于集合的方向倾斜——构造一组
n
项,然后执行快速的常数时间搜索,总比在预先创建的元组上迭代查找项要昂贵得多。这是因为集合创建必须分配集合(可能多次)并计算所有项的哈希。虽然元组搜索和集合大小都是O(n),但集合的元组具有更大的常数因子

实现O(1)查找的正确方法需要手动实现编译器自动对元组进行的优化:

_valid = {1, 2, 3}
def is_valid(x):
    return x in _valid

将此
代码与使用元组的等效代码进行比较,即使项目数很少,集合也总是更快。随着项目数量的增加,集合通过其O(1)查找成为明显的赢家。

尽管另一位评论者在技术上正确地认为
中的x在运行时是O(1),但比较相同大小的集合和元组的性能仍然很有趣。讨论可以概括为考虑包含{,代码,x,{a,b,c,…} /代码>的表达式的不同程序。如果表达式由
n
项组成,则在所有可能的此类程序中,
n
可被视为big-O分析的输入。(如果仍然有人坚持认为可以在运行时提供不同的
n
,只需想象该函数是使用
exec
创建的)

性能问题 2 0 LOAD_FAST 0 (x) 3 LOAD_CONST 3 (frozenset({'name', 'known_as'})) 6 COMPARE_OP 6 (in) 9 RETURN_VALUE $ python3.5 -m timeit -s "def is_valid(x): return x in {'name', 'known_as'}" "is_valid('')" 10000000 loops, best of 3: 0.0815 usec per loop $ python3.5 -m timeit -s "def is_valid(x): return x in ('name', 'known_as')" "is_valid('')" 10000000 loops, best of 3: 0.0997 usec per loop