首页 > 解决方案 > 使用字符串键问题的哈希表插入实现

问题描述

我有一个问题我已经尝试解决好几天了。我尝试从三个结构创建一个哈希表,第一个结构带有指向具有键和值对的对数组的指针桶。密钥应该是一个字符串(char * arr)。我不完全掌握如何为它创建一个工作插入函数我的目标是在我的代码中尝试查看存储桶 h 中是否存在密钥。我觉得我的逻辑和语法有问题。如果有人可以帮助我,将不胜感激。

我看过维基百科和 youtube 视频上的哈希表理论,但没有一个使用三个结构和字符串键。这就是我感觉卡住的地方。

#include<stdio.h>
#include"hashtable.h"

struct hash_table
{
    Bucket *bucket;
    int hash_size;
};

struct bucket
{
    Pair *list;
    int capacity;
    int size;
};

struct pair
{
    char *key;
    int value;
};

Pair copy_key(char *key, int value)
{
    Pair copy = malloc(sizeof(Pair));
    copy->key = key;
    copy->value = value;
    return copy;
}

unsigned long hash(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while (c = *str++)          
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}

void hash_insert (HashTable *tab, const char *key, int value)
{
    unsigned long h = hash(key) % tab->hash_size;
    int i = 0;

    while(tab->bucket[h]->list[i]->key != NULL && (i < tab->bucket->size))
    {
        Pair pair = copy_key(key,value);
        if (tab->bucket[h]->list[i]->key == pair->key)
        {
            tab->bucket[h]->list[i]->value == pair->value;
            return;
        }
    }
}

用于具有字符串键的三层结构层哈希表的工作插入函数。

标签: chashtable

解决方案


您的插入功能存在很多问题:

void hash_insert (HashTable *tab, const char *key, int value)
{
    unsigned long h = hash(key) % tab->hash_size;
    int i = 0;

    // depending on how you initialise your hash table, the list might yet
    // be NULL(!) - so you possibly yet need a check for!

    // you need FIRST to check if the index is yet valid, THEN check
    // if there is a key!
    //while(tab->bucket[h]->list[i]->key != NULL && (i < tab->bucket->size))
    while(i < tab->bucket[h].size && tab->bucket[h].list[i].key != NULL)
    // additionally: you have a pointer, index operator [] dereferences
    // -> you have a struct directly -> need to access via .
    {
        //Pair pair = copy_key(key,value);
        // BAD idea: you malloc a struct, but never free it -> memory leak!

        if (tab->bucket[h].list[i].key == /*pair->*/key)
        // compare directly!

        // however: == compares the pointers only - most likely, though,
        // you have created a new string somewhere else just with same
        // CONTENT - in this case you need to compare via strcmp:
        if (strcmp(tab->bucket[h].list[i].key, key) == 0)

        {
            //tab->bucket[h]->list[i]->value == pair->value;
            // comparison? assuming you wanted to assign:
            tab->bucket[h].list[i].value = value;

            return;
        }
    }

    // end of while reached, the key was not yet found!
    // -> you need to insert it here:

    if(i == tab->bucket[h].size)
    {
        // no space in buckets left!
        // -> need to realloc (leaving this to you)

        // BUT: you might want to consider overall fill grade or maximum fill
        // grade for buckets and do a complete re-hash of all contents...
    }

    // assuming we insert in THIS bucket:
    tab->bucket[h].list[i].key = ???;
    tab->bucket[h].list[i].value = value;
}

???- 好吧,取决于。我几乎假设您希望哈希映射拥有它包含的键字符串。然后,您可以安全地避免 key 成为超出范围的本地数组或动态分配的字符串之后被删除!所以:

tab->bucket[h].list[i].key = strdup(key);

如果你想避免不必要的副本,因为你已经分配了字符串,你可以添加另一个参数:(int isTakeOwnwershipbool,但你需要#include <stdbool.h>):

tab->bucket[h].list[i].key = isTakeOwnership ? key : strdup(key);

在这两个示例中,我都没有检查 strdup 是否为 NULL 的结果 - 您需要这样做并处理内存分配失败的情况(可能在插入函数中添加一个返回值,指示成功或失败?)。

不要忘记free地图中的字符串元素移除!!!请记住,您的地图拥有所有权。


推荐阅读