我有大型文本文件,需要执行各种操作,主要涉及逐行验证。数据通常具有销售/交易性质,因此往往包含跨行的大量冗余信息,例如客户名称。迭代和操作这些数据已经成为一项常见的任务,我正在用C语言编写一个库,我希望将其作为Python模块提供。
在一次测试中,我发现在130万列值中,只有约300,000个是唯一的。内存开销是一个问题,因为我们基于Python的Web应用程序可以处理大型数据集的同时请求。
我的第一次尝试是读入文件并将每个列值插入二叉搜索树。如果之前从未见过该值,则分配内存来存储字符串,否则返回指向该值的现有存储的指针。这适用于~100,000行的数据集。更大,一切都停止了,内存消耗急剧上升。我假设树中所有节点指针的开销没有帮助,使用strcmp进行二进制搜索变得非常痛苦。
这种令人不满意的表现让我相信我应该投资使用哈希表。然而,这提出了另一点 - 我不知道有多少记录。它可能是10或一千万。如何在时间/空间之间取得适当的平衡,以防止反复调整哈希表的大小?
在这种情况下,最佳数据结构候选者是什么?
感谢您的时间。
答案 0 :(得分:1)
哈希表调整大小不是一个问题,除非您要求表中的每个插入都需要相同的时间。只要您始终将哈希表大小扩展一个常数因子(例如,总是将大小增加50%),添加额外元素的计算成本就会摊销O(1)
。这意味着n
插入操作(当n
很大时)将占用与n
成比例的时间量 - 但是,每次插入的实际时间可能会有很大差异(实际上,其中一个插入将非常慢,而其他插入将非常快,但所有操作的平均值很小)。这样做的原因是,当您插入一个额外的元素,迫使表格从例如1000000到1500000个元素,插入将花费大量时间,但是现在你需要再次调整大小之前已经为自己购买了500000个非常快速的插入。简而言之,我肯定会去哈希表。
答案 1 :(得分:0)
您需要使用哈希表的incremental resizing。在我当前的项目中,我会跟踪每个存储桶中使用的哈希密钥大小,如果该大小低于表的当前密钥大小,那么我会在插入或查找上重新插入该存储桶。在调整散列表的大小时,密钥大小加倍(向密钥添加一个额外的位),在所有新的桶中,我只需将指针添加回现有表中的相应存储桶。因此,如果n
是散列桶的数量,则散列扩展代码如下所示:
n=n*2;
bucket=realloc(bucket, sizeof(bucket)*n);
for (i=0,j=n/2; j<n; i++,j++) {
bucket[j]=bucket[i];
}
答案 2 :(得分:0)
我希望C中的库 可用作Python模块
Python已经内置了非常高效的精细调整哈希表。我强烈建议你先让你的库/模块使用Python。然后检查速度。如果这还不够快,可以通过使用Cython对其进行分析并删除您找到的任何减速带。
设置代码:
shared_table = {}
string_sharer = shared_table.setdefault
scrunching每个输入行:
for i, field in enumerate(fields):
fields[i] = string_sharer(field, field)
当然,您可能会在检查每个列后发现某些列不能很好地压缩并且应该从“scrunching”中排除。