列表查找比设置查找慢

时间:2016-12-27 11:00:10

标签: python set time-complexity

我目前正在做一个项目,我必须多次检查给定的2D点是否合法",即它是否在网格边界内并且如果之前没有访问过。网格有一个固定的H x W大小,所以我想我可以将它们存储在一个集合中,而不是一个2D查找表。令我惊讶的是,它比检查它是否出现在一个集合中要慢得多,即使它(理论上)是一个O(logn)操作,而不是O(1)一个简单的操作数组查找。

首先尝试:

class PointSet:
    def __init__(self, h, w):
        if h <= 0 or w <= 0:
            raise ValueError("Invalid size")
        self.h = h
        self.w = w
        self.lookup = [[False for _ in range(w)] for _ in range(h)]
        self.size = 0

    def add(self, point):
        r, c = point
        self.lookup[r][c] = True
        self.size += 1

    def remove(self, point):
        r, c = point
        self.lookup[r][c] = False
        self.size -= 1

    def __contains__(self, point):
        r, c = point
        return 0 <= r < self.h and 0 <= c < self.w and self.lookup[r][c]

    def __bool__(self):
        return self.size != 0

    def __len__(self):
        return self.size

# H, W = ...
# pointset = PointSet(H, W)
# if (3, 5) in pointset:
#   ...

第二次尝试:

#  pointset = set()
#  if (3, 5) in pointset:
#    ...

第二代码执行得更快。为什么会这样?

1 个答案:

答案 0 :(得分:1)

首先,您必须考虑__contains__方法的实现调用__getitem__ 两次(因为您有一个列表列表),每个方法都有0(1)个复杂度,并将评估两个链式比较(0 <= r < self.h0 <= c < self.w);在最坏的情况下,评估所有表达式,因为and只会在第一个False上短路。前一行中的可迭代解包会产生额外的开销。属性查找还有一些小的补充。

集合的成员资格查找只是简单的0(1),所以我看不到你的代码可能会如何击败它。