我正在研究一种使用int64s数组的算法。这些数组通常是稀疏的,并且不断地读取和写入。我目前正在使用相对较大的本机阵列,性能良好,但内存使用率很高(正如预期的那样)。
我希望能够让数组实现不浪费空间用于未使用的值,并允许索引偏移量不为零。举个例子,如果我的数字从1,000,000开始,我希望能够从1,000,000开始索引我的数组,并且不需要浪费具有一百万个未使用值的内存。
数组读取和写入需要快速。扩展到新领域可能会有一点延迟,但如果可能,读取和写入应为O(1)。
有人知道可以做到的图书馆吗?
谢谢!
更新为提及int64作为数据类型。
答案 0 :(得分:4)
听起来像blist
类型(documentation,download)可能就是您正在寻找的内容(免责声明:我是作者)。它与Python的list
具有完全相同的接口,因此没有学习曲线,但它具有不同的性能特征。特别是,在许多情况下,它可以有效地处理稀疏列表。下面是一个创建包含2 ** 29个元素的列表的示例。这几乎是瞬间完成的。以这种方式创建的稀疏列表使用O(log n)空间。
>>> from blist import *
>>> x = blist([0]) # x is a blist with one element
>>> x *= 2**29 # x is a blist with > 500 million elements
>>> x.append(5) # append to x
>>> y = x[4:-234234] # Take a 500 million element slice from x
>>> del x[3:1024] # Delete a few thousand elements from x
迭代整个列表的操作仍需要O(n)时间(remove
,reverse
,count
等。文档说明了每个操作的时间复杂性,因此您应该能够评估它是否能满足您的需求。
答案 1 :(得分:1)
您可以将numpy sparse matrix重新映射到稀疏数组中 - 或者考虑使用哈希表(python dict)。就偏移量而言,只需包装您正在使用的任何存储类,并使您拥有自己的插入/查找/删除方法。
答案 2 :(得分:1)
我不知道任何Python,所以这可能是一个没有答案的:
在某些语言中,您可以通过将索引空间中的函数定义到数据空间来模拟稀疏数组。例如(伪代码):
f[1000000] = 32;
f[2000000] = 51;
在某些语言(最好的语言)中,数组引用的形式(例如f[3]
)看起来就像函数调用的形式(例如f[3]
)。当然,这是因为数组定义了从索引空间到数据空间的函数。以这种方式实现更高维度的稀疏数组非常容易。
答案 3 :(得分:1)
为什么不直接使用dict?
sparse = dict()
sparse[100000] = 1234
sparse[123456] = 2345
答案 4 :(得分:1)
另一种选择 - 至少如果你愿意自己实施 - 是Page table。这通常用于虚拟内存系统中,以将虚拟地址映射到物理地址,如果地址空间稀疏填充,并且使用的地址是群集的,则效果最佳。如果使用过的地址是随机分布的,那么效果就会降低。
页表的基本方法与Trie - 递归细分相同。页表具有一些固定数量的级别,每个节点是固定大小的数组。如果给定子节点的条目为null,则该节点覆盖的所有叶子都为空。页表的主要优点是查找速度快,只需要几个位移和解引用。
让我们看一个2级页面表的简单Python实现:
class Pagetable(object):
def __init__(self, num_bits=8):
"""Creates a new Pagetable with num_bits bits per level.
Args:
num_bits: The number of bits per pagetable level.
A 2 level pagetable will be able to store indexes between 0 and 2^(num_bits*2).
"""
self.num_bits = num_bits
self.mask = (1 << num_bits) - 1
self.root = [None] * (2 ** num_bits)
def __getitem__(self, idx):
page = self.root[idx >> self.num_bits]
return page and page[idx & self.mask]
def __setitem__(self, idx, val):
page = self.root[idx >> self.num_bits]
if not page:
page = self.root[idx >> self.num_bits] = [None] * (2 ** self.num_bits)
page[idx & self.mask] = val