存储一系列未知大小的值的最有效方法是什么?

时间:2011-03-01 10:16:51

标签: c arrays malloc hashtable glib

我有一个生成size_t值的函数(比如名为next_entity)。该函数充当生成器,即,它在每次调用时生成一个新值,最后返回0作为标记。

在调用next_entity的另一个函数中,我需要将值存储在某处。在收到哨兵之前我不知道值的数量,所以我不能malloc或静态分配数组来包含这些值。

问题是,在哨兵来之后,我唯一需要做的就是将它们保存到文件中,但没有重复,也就是说,每个值只能出现一次。

之后,不再需要这些值。

我尝试在迭代期间使用GHashTable中的glib.h来存储值作为键,但GHashTable的问题是指向传递给函数的键的指针g_hash_table_insert必须在哈希表的生命周期中保持活动状态,因此我必须为每个新值执行malloc(sizeof(size_t))种类。

它有效,但似乎效率很低,因为malloc非常耗时。

有没有更好的方法呢?

如果需要,我可以发布实际代码,但我不认为问题与代码有关。

任何帮助将不胜感激,谢谢你提前!

4 个答案:

答案 0 :(得分:2)

如果您的数据大小不是千兆字节,则可以使用动态数组,每次空间不足时,您将使用realloc()大小加倍。使用此策略,只需进行log(N)重新分配。

例如,在C ++中,许多std::vector实现通常都是这样做的。

答案 1 :(得分:2)

其他人建议realloc。而不是考虑使用malloced块的链接列表,其中每个块包含一个较大的数字数组;当你填满一个块时,分配另一个块并将前一个链接到它...或者将它链接到前一个块然后在输出它们之前反转列表。关键是您不需要将值存储在连续的内存中,因此您不需要使用realloc。 realloc复制前一个数组,你可以避免这个数组,对于非常大的数组来说,它会很慢,如果它找不到足够大的连续块,它甚至会耗尽内存,而分配单个块则更具弹性。缺点是管理链表需要更多的工作。

==== 编辑GHashTable用法:

将您的值存储到数组中,并将该元素的地址传递给哈希例程...如果它尚不存在,则前进数组指针。要输出值,只需枚举哈希表中的键即可。只需要解除分配数组的链接列表。如果这是程序的全部内容,那么您甚至不需要维护链表;你可以根据需要分配数组,当你的程序退出时它们都会被释放。

答案 2 :(得分:1)

通常的方法是将常数使用的空间乘以(2,1.69,1.618,1.5 ......)。

我喜欢黄金比例:)

arr = malloc(elems * sizeof *arr);
{
    /* ... */
    elems = elems * 13 / 8; /* approximate golden ratio */
    tmparr = realloc(arr, elems * sizeof *arr);
    if (tmparr == NULL) /* deal with error */;
    arr = tmparr;
    /* ... */
}
free(arr);

答案 3 :(得分:1)

哈希表中的键是void *,void *总是至少与size_t一样大。

您需要做的就是使用g_hash_table_new(NULL,NULL)而不是malloc(sizeof(size_t))来使用g_direct_hash作为哈希方法。然后这样做:

g_hash_table_replace(table, GSIZE_TO_POINTER(value), GSIZE_TO_POINTER(value))

要迭代键,请使用GPOINTER_TO_SIZE返回size_t。

您可以随时对任何整数类型执行此操作,而不是对其进行malloc。 (在适当的时候使用GINT_TO_POINTER,GUINT_TO_POINTER,而不是GSIZE_TO_POINTER)