【问题标题】:rehash in insert function in C在C中的插入函数中重新散列
【发布时间】:2020-08-27 19:21:55
【问题描述】:

我正在尝试重新散列已使用单独链接方法实现的哈希表。 我有哈希表的每个桶的链表,当负载因子(#nodes/#buckets)大于 0.75 时需要调整表的大小和重新哈希表 我尝试将原始表的每个桶的尾部复制到一个临时表中并释放先前为表分配的内存(map-> hashtable)然后通过将大小加倍来增加表的大小。然后我 malloc 一个新表(链表结构数组)在调整大小和重新散列过程后存储条目。 该函数的目的是向表中添加一个条目。我不确定如何在新表中重新散列原始表的节点。这是我为检查尺寸所做的。任何提示将不胜感激

size_t index = (map->hash_func(k)) % (map->size_map);
    float load_factor = map->node_count / map->size_map ;
    if (load_factor >= 0.75) {
        struct linked_list *temp_array = malloc(sizeof(struct linked_list) * map->size_map);
        for (int i = 0; i < map->size_map) {
            temp_array[i].tail = map->hashtable[i].tail;
        }
        free(map->hashtable);
        map->size_map *= map->size_map;
        map->hashtable = malloc(sizeof(struct linked_list) * map->size_map);

【问题讨论】:

  • 你有什么问题?你没有得到想要的行为吗?您的描述中的一些观察结果:(1)您不需要将现有的存储桶复制到新的临时内存中。只需在释放之前使用旧内存。 (2)“我试图只复制每个桶的尾部”——你的意思是每个桶的头部,不是吗? (3) map-&gt;size_map *= map-&gt;size_map -- 每次调整大小时将桶数平方。这将很快变得巨大。 (更常用的方法是每次将大小加倍。)
  • 您的for (int i = 0; i &lt; map-&gt;size_map) { 循环中缺少; i++ 部分

标签: c hashmap hashtable


【解决方案1】:

您的哈希表实现使用链表数组来存储键值对:

hash->table[0] -> ("dec", 31) -> NULL
hash->table[1] -> NULL
hash->table[2] -> ("aug", 31)  -> ("jun", 30) -> NULL
...
hash->table[n] -> ("feb", 28) -> NULL

链表的索引,即一个item存放在哪个“槽”,是由key模块的hash值和当前hash表大小决定的。列表中的所有条目具有相同的散列值模块大小。这个不变量总是正确的。

当你调整哈希表的大小时,你必须重新组织你的链表。您不需要创建新的列表节点,只需重新链接节点,以便新列表的不变量为真。

  • 创建一个新大小的新表。将该新表中的所有指针初始化为NULL
  • 处理旧表中的每个列表:
    • 计算哈希值。以新大小为模的值是新表中槽的索引i
    • 从旧列表中删除节点并将其插入新表的插槽i
  • 删除旧表,该表现在只包含过时的列表头。
  • 设置新表格和大小。

如果您将大小加倍(不要像示例中那样将其平方),您应该或多或少地将列表的长度减半。例如,如果您有 32 个插槽并将大小增加到 64,则插槽 5 中大约一半的项目也在新列表中的插槽 5 中。其余物品应在插槽 37 中。

调整大小的函数可能如下所示:

void map_resize(Map *map, size_t size)
{
    if (size > map->size) {
        Node **table = malloc(size * sizeof(*table));

        for (size_t i = 0; i < size; i++) {
            table[i] = NULL;
        }

        for (size_t i = 0; i < map->size; i++) {
            Node *node = map->table[i];

            while (node) {
                Node *next = node->next;
                size_t h = hash(node->key) % size;
                Node **p = &table[h];

                while (*p && strcmp(node->key, (*p)->key) < 0) {
                    p = &(*p)->next;
                }

                node->next = *p;
                *p = node;

                node = next;
            }
        }

        free(map->table);

        map->table = table;
        map->size = size;
    }
}

(为了清楚起见,该代码不会对分配进行任何错误检查,您的代码绝对应该这样做!Here's 上面的代码是一个完整的示例。)

【讨论】:

    猜你喜欢
    • 2016-04-14
    • 2015-01-05
    • 2014-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-21
    • 1970-01-01
    相关资源
    最近更新 更多