最快的数据结构,可按顺序返回一系列项目

时间:2018-08-26 17:06:56

标签: python dictionary data-structures set

我正在研究一个leet问题,我只是为了好玩而已。我认为我可以深入探讨该问题的所有测试输入。可以这么说,我提前知道所有输入。返回解决方案最快的结构是什么。

我尝试使用字典将所有输入与假定的解决方案进行映射。

class DictSolution():
    DATA = {x:x for x in range(1000000)}

    def compute(self, x):
        return self.DATA[x]

然后,我想,因为我知道输入将按什么顺序进行测试,所以我不需要“查找”。因此,我尝试使用set并忽略所有输入。

class SetSolution():
    DATA = {i for i in range(1000000)}

    def compute(self, x):
        return self.DATA.pop()

令我惊讶的是,它比dict慢一点,每次都慢1-2%。顺便说一句,这是我给他们计时的方式。

def test_dict():
    sol = DictSolution()
    for i in range(1000000):
        sol.compute(i

ds = timeit.timeit(test_dict, number=1)
ss = timeit.timeit(test_set,  number=1)
print ("Dict Solution:", ds)
print ("Set  Solution:", ss)

>> Dict Solution: 0.11734077199999998
>> Set  Solution: 0.11939082499999998

问题:

  1. 为什么set慢一些?
  2. 从逻辑上讲,按顺序返回内容应该比在表中查找内容更快。因此,我不认为dict方法已经是最快的方法。我该怎么做才能获得更好的时间?

2 个答案:

答案 0 :(得分:1)

我相信@schwobaseggl的建议是正确的。从here开始,O(1)dict的访问元素的复杂度均为list,实际上在之前的question中已对此进行了复制设置listdict更快。我完全复制了您的基准,并添加了其他数据结构:

  • 列表
  • 字典
  • 设置(使用弹出窗口)
  • 双端队列(来自收藏集)
  • 元组

代码:

import timeit
from collections import deque


class DictSolution:
    DATA = {x: x for x in range(1000000)}

    def compute(self, x):
        return self.DATA[x]


class SetSolution:
    DATA = {i for i in range(1000000)}

    def compute(self, x):
        return self.DATA.pop()


class DequeSolution:
    DATA = deque(i for i in range(1000000))

    def compute(self, x):
        return self.DATA.popleft()


class ListSolution:
    DATA = [i for i in range(1000000)]

    def compute(self, x):
        return self.DATA[x]


class TupleSolution:
    DATA = tuple(i for i in range(1000000))

    def compute(self, x):
        return self.DATA[x]


def test_dict():
    sol = DictSolution()
    for i in range(1000000):
        sol.compute(i)


def test_set():
    sol = SetSolution()
    for i in range(1000000):
        sol.compute(i)


def test_deque():
    sol = DequeSolution()
    for i in range(1000000):
        sol.compute(i)


def test_list():
    sol = ListSolution()
    for i in range(1000000):
        sol.compute(i)


def test_tuple():
    sol = TupleSolution()
    for i in range(1000000):
        sol.compute(i)


def test_pop_list():
    sol = PopListSolution()
    for i in range(1000000):
        sol.compute(i)


des = timeit.timeit(test_deque, number=1)
ss = timeit.timeit(test_set, number=1)
ds = timeit.timeit(test_dict, number=1)
ls = timeit.timeit(test_list, number=1)
ts = timeit.timeit(test_tuple, number=1)
times = [("Dict Solution:", ds), ("Set Solution:", ss), ("Deque Solution:", des), ("List Solution:", ls), ("Tuple Solution:", ts)]

for label, time in sorted(times, key=lambda e: e[1]):
    print(label, time)

输出

Tuple Solution: 0.1597294129896909
List Solution: 0.16653884798870422
Dict Solution: 0.17414769899914972
Set Solution: 0.190879073983524
Deque Solution: 0.1914772919844836

我多次运行了脚本,结果与元组解决方案和列表解决方案交替使用的结果相似。请注意,SetSolutionDequeSolution都是最慢的。因此,回答您的问题:

  1. setdeque都较慢,因为您要从列表中删除一个元素,而在其他结构中,您仅访问这些元素。
  2. 这在先前的答案中得到了部分回答,pop不仅从数据结构中返回一个元素,还从其中删除了该元素。因此,我希望更新数据结构比访问仅其中一个元素要慢。

注释 尽管popset一起用于测试用例,但是通常不会出现这种情况,例如:

test = {'e' + str(i) for i in range(10)}
while test:
    print(test.pop())

输出(弹出设置)

e5
e8
e6
e0
e1
e3
e7
e4
e9
e2

有关该主题的更多信息,请参见here

我还使用list.pop(0)对解决方案进行了基准测试,尽管使用的范围较小:100000,并且候选对象(列表,元组和字典)更少。结果如下:

('List Solution:', 0.018702030181884766)
('Tuple Solution:', 0.021403074264526367)
('Dict Solution:', 0.02230381965637207)
('List Pop Solution', 1.8658080101013184)

该基准测试是在以下设置上运行的:

Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz
16GB
Ubuntu 16.04
Python 3.5.2

答案 1 :(得分:0)

dict是最快的查找数据结构,因为它是使用哈希表实现的:在哈希表中查找键几乎需要固定的时间。请查看下面的链接以获取更多信息:

This pdf from MIT explains the subject