Python循环出现MemoryError:装箱问题脚本优化求助
看起来你的代码逻辑本身是正确的(在示例数据下能得到预期输出),但出现MemoryError大概率是因为处理的数据集过大,或者有一些容易忽略的代码细节问题。我来帮你分析并给出解决方案:
首先,修正代码中的潜在问题
你用了max作为列表变量名,但max是Python的内置函数,虽然在这个小例子里不会直接报错,但这是非常不好的编程习惯,可能在后续扩展代码时引发奇怪的冲突。先把变量名改成remaining这类语义清晰的名字。
另外,用for-else结构虽然可行,但换成显式的标志变量会让代码可读性更强,不容易出错。修改后的基础代码如下:
B = 60 data = [35,21,40,12,24] # 替换max为remaining,避免内置函数名冲突 remaining = [B] sol = [[]] for item in data: item_placed = False for idx, free_space in enumerate(remaining): if free_space >= item: # 将元素放入对应子列表,更新剩余容量 remaining[idx] -= item sol[idx].append(item) item_placed = True break if not item_placed: # 没有合适的子列表,新建一个 sol.append([item]) remaining.append(B - item) solved = len(sol) print(solved) print(sol)
这段代码运行后会输出你预期的结果:3 [[35, 21], [40, 12], [24]]
针对MemoryError的解决方案
如果你的实际data列表非常庞大(比如包含数百万甚至更多元素),不断向sol和remaining添加元素会占用大量内存,从而触发MemoryError。可以尝试以下优化:
改用首次适应递减算法(First Fit Decreasing)
先将data按降序排序,再进行装箱,这种策略通常能生成更少的子列表(箱子),直接减少sol和remaining的长度,从而降低内存占用。示例代码:B = 60 # 先降序排序数据 data = sorted([35,21,40,12,24], reverse=True) remaining = [B] sol = [[]] for item in data: item_placed = False for idx, free_space in enumerate(remaining): if free_space >= item: remaining[idx] -= item sol[idx].append(item) item_placed = True break if not item_placed: sol.append([item]) remaining.append(B - item) print(len(sol)) print(sol)运行结果箱子数量和之前一致,但对于更大的数据集,能显著减少箱子总数。
使用更高效的数据结构存储剩余容量
对于remaining列表,如果里面都是整数,可以用array.array来代替普通列表,它存储数据的内存效率更高(普通列表每个元素是一个对象引用,而array.array直接存储原始字节)。示例:import array B = 60 data = [35,21,40,12,24] # 用array存储整数,类型代码'i'表示int remaining = array.array('i', [B]) sol = [[]] for item in data: item_placed = False for idx in range(len(remaining)): free_space = remaining[idx] if free_space >= item: remaining[idx] -= item sol[idx].append(item) item_placed = True break if not item_placed: sol.append([item]) remaining.append(B - item) print(len(sol)) print(sol)分块处理(仅在允许少量额外箱子的情况下)
如果数据集大到无法一次性加载到内存,可以分块处理data,每处理完一块后,将剩余容量不足B的箱子合并(如果可能),但这种方法可能会导致最终的箱子数量略多于最优解,适合对箱子数量要求不是极端严格的场景。
内容的提问来源于stack exchange,提问作者Eloah

