我正在尝试编程的一颗珍珠:
给出一个最多包含一千万个7位整数且无重复的文件。仅使用1.5Mb RAM并仅读取一次数据的升序打印这些数字的有效方法是什么?仅具有1Mb的RAM而没有其他存储的后果是什么?如果允许重复,您的答案将如何变化?
为了创建测试用例I,生成了8999999个数字并将其写入文件中。 然后,对于每一行,我开始将其插入到树中,最后创建一个trie结构。
示例代码:
from sys import getsizeof
tree = dict()
xtree = dict()
f = open("data2.txt", "r")
cnt = 0
for number in f:
cnt += 1
currTree = tree
xtree[number] = dict()
for n in number.strip():
if n not in currTree:
currTree[n] = dict()
currTree = currTree[n]
f.close()
print(cnt)
print(getsizeof(tree))
print(getsizeof(xtree))
print(tree)
示例文件data2.txt有20条记录
生成的树是
现在的问题是,当我对构建的树进行内存大小调整时,在20行时它显示240字节的内存占用量
在100行时,树的大小变为368个字节
,并且在8999999行处也提供了368个字节
我建立了一个名为xtree
的辅助地图,该地图仅用于提供数据
xtree和tree的大小以字节为单位。
任何人都可以解释一下这是怎么回事吗??
答案 0 :(得分:4)
您的tree
只是一个最多有10个键值对的字典。在更大的树中,不再有键/值对。键值对中…内的值中还有更多值,但是dict中仍然只有10个键值对。大约有10个键值对占用368个字节的字典看起来像您应该期望的那样。 1
getsizeof
的文档说:
仅考虑直接归因于对象的内存消耗,而不考虑其引用的对象的内存消耗。
...
有关recursive sizeof recipe递归使用
getsizeof()
来查找容器的大小及其所有内容的示例。
由于您实际上并不具有完全任意的数据结构,而只是一个dict等等的字典。而且,当您 do 时有一些共享的引用(例如,如果您阅读数字{ {1}}当您已经有一个具有相同内存值的int时,Python只会重用相同的对象),如果您试图验证自己是否适合1.5MB,则确实需要进行最坏情况的测量,因此您可能要跳过对已经看到的值的检查。
因此,您可以根据需要编写更简单的方法,而不使用该配方。但是想法是一样的:
1234567
另一方面,您的def total_dict_size(d):
size = sys.getsizeof(d)
if isinstance(d, dict):
for key, value in d.items():
size += sys.getsizeof(key) + total_dict_size(value)
return size
是具有8999999键值对的字典。进行相同的后端计算,我希望它不到300MB。相反,它超过了300MB。足够靠近。
您还将在堆中存储8999999 7位整数。为了获得一些不错的整数,我们假设有5M个不同的整数,它们不属于CPython预先创建和缓存的少数小值。这些整数中的每一个都足够小以适合一个30位数字,因此在64位CPython上它们每个占用28个字节。因此,如果您在任一{{1上调用了上面的递归函数,请在上面调用递归函数,这是另外xtree
中未占的140MB(但它们占了-实际上,占了过多的空间,给出了最坏情况的测量实现)。 }}或sys.getsizeof(xtree)
。
因此,您在tree
,xtree
之间的总内存使用量和实际整数可能约为750MB,这不太符合tree
的要求。 / p>
1。每个Python对象都有一些固定的标头开销,例如refcount,指向类型的指针等,以及特定于类型的事物(例如大多数容器类型的长度)。调用该64个字节。然后,字典有一个哈希表。它必须大于10个插槽,以将负载保持在1.0以下。称之为13个插槽。每个插槽都需要一个散列值,一个对键的引用以及对该值的引用,因此为3个指针或24个字节。 64 + 13 * 24 =376。因此,封底计算仅减少了8个字节…