python MemoryError:存储不同类型的大列表

时间:2016-07-23 11:37:11

标签: python-2.7 out-of-memory

我正在使用python2.7,我需要构建followind数据结构: 它必须存储所有三元组,使得:x< y< z< N(给出N)。 我可以随机选择一个三胞胎。 我有一个" Pop"带有输入的函数,如果它存在或从中返回" False"如果它不在数据库中。

N可能非常大。

我的代码:

N = 1000
Root = []
for x in range(0,N-2):
    xNode = [x, []]
    for y in range(x+1,N-1):
        yNode = [y, []]
        for z in range(y+1,N):
            yNode[1].append(z)
        xNode[1].append(yNode)
    Root.append(xNode)
    print "Loading [{0:.2f}%]".format(float(100*x)/(N-2))

在我的电脑上N=1000有一个MemoryError。我想要一个数据结构,而不是[],它将零件存储到内存中。我不在乎它是否慢,只要它不受N的限制(至少比{1}}小于我的PC中的光盘空间)

是否有可以使用的模块或其他东西?

1 个答案:

答案 0 :(得分:1)

据我了解您的问题,您需要针对该空列表进行解决方法并重复添加。

当我运行你的程序时,在我的本地机器中,N = 4的输出是:

>>> N = 4
>>> Root = []
>>> for x in range(0,N-2):
...     xNode = [x, []]
...     for y in range(x+1,N-1):
...         yNode = [y, []]
...         for z in range(y+1,N):
...             yNode[1].append(z)
...         xNode[1].append(yNode)
...     Root.append(xNode)
... 
>>> for i in Root:
...   print i
... 
[0, [[1, [2, 3]], [2, [3]]]]
[1, [[2, [3]]]]

我在这里假设您至少希望输出看起来像这样:

[0, 1, 2]
[0, 1, 3]
[0, 2, 3]
[1, 2, 3]

要实现这一点,您需要对代码进行一些小改动。您可以将每个列表直接附加到最里面的循环中,而不是临时xNodeyNode

>>> N = 4
>>> Root = []
>>> for x in xrange(0, N-2):
...   for y in xrange(x+1, N-1):
...     for z in xrange(y+1, N):
...       Root.append([x, y, z])
... 
>>>

现在,对于N = 1000,列表的大致长度为O(N^3)或大约10^9,这对本地计算机来说非常大。为了给你一个想法,列表的每个元素由3个整数组成。假设整数的大小为4 bytes,则列表的每个元素的大小为12 bytes。将完整列表存储在内存中所需的总内存为12*(10^9) bytes,大约为11 GB

关于检查和弹出元素的主要问题,您可以按如下方式执行:

我们的想法是假设所有有效的三元组最初都存在于内存中(虽然我们不会存储它,因为你提到N可能非常大而且我们无法存储所有三元组以获得更大的值N)。我们将制作三个N大小的列表 - xyz。每当我们弹出三元组时,我们都会在这些列表中标记相应的值。稍后,如果我们遇到相同的三元组,那么我们可以在O(1)时间检查它是否已被弹出。空间复杂度为O(N),时间复杂度为O(queries)

N = int(raw_input())
# number of queries
queries = int(raw_input())
x = [0]*N
y = [0]*N
z = [0]*N
for i in xrange(queries):
    a, b, c = map(int, raw_input().split())
    if a < b and b < c and c < N:
        # Basic idea is if (x[a], x[b], x[c]) = (1, 1, 1), then it has already
        # popped off, else, we pop it and mark it as popped.
        if x[a] == 1 and x[b] == 1 and x[c] == 1:
            print 'Triplet not in memory to remove'
        else:
            x[a] = 1
            x[b] = 1
            x[c] = 1
            print 'Triplet (%d, %d, %d) popped off memory' % (a, b, c)