【问题标题】:How to delete element from hsearch如何从 hsearch 中删除元素
【发布时间】:2014-11-16 06:24:43
【问题描述】:

我正在使用 GNU C 库提供的 hsearch_r 函数。

我看到虽然我可以使用 hsearch_r 将元素添加到 HASH 表中并将操作作为 ENTER 传递,但我看不到从 HASH 表中删除元素或条目的方法。

有人知道为什么会这样吗?

我可以执行以下操作来实现我的删除功能吗?

我首先使用 hsearch_r 搜索它,操作为 FIND。然后,一旦我得到一个指向 hash_element 的指针,我就会释放它。那会奏效吗?如果我只能添加元素并搜索它们,那么哈希库有什么好处。为什么不提供删除例程?

我尝试用谷歌搜索 hsearch 库的源代码,但找不到它。有人也可以指出我吗?

http://linux.die.net/man/3/hcreate_r

编辑:

我还看到,如果我使用操作 ADD 调用 hsearch_r 两次,那么它既不会引发错误,也不会使用新值更新散列。这很奇怪。这意味着 hsearch 内部没有实现替换功能,我们必须自己做,即首先进行搜索,然后如果存在,然后删除第一个条目,然后添加一个新条目。但是要做到这一点,我们需要从哈希中删除一个元素,而我无法做到。

【问题讨论】:

    标签: c search hash gnu


    【解决方案1】:

    source of hsearch_r 可以在网上找到。

    如果键在表中,则函数在检查操作之前返回找到的条目,这意味着添加现有键的行为就像找到它一样。 (您可以在调用hsearch(ADD) 后覆盖“found”结构的值并覆盖旧值。)

    该实现不适合元素删除。它维护一个桶数组。哈希冲突通过寻找另一个空桶来处理,因此桶索引不一定等于哈希码。当你插入两个哈希码相同的值时,第二个会得到这样一个哈希码不是桶索引的桶。

    当您现在删除第一项然后尝试查找第二项时,将找不到它,因为仅当哈希码为桶索引的“最佳”桶已满时才考虑“其他”桶。

    除了不更新的重新添加和缺少的删除选项之外,hsearch_r 还有其他限制。例如,条目的最大数量必须预先估计并且以后不能更改。我认为hsearch_r 旨在作为有限范围应用程序的快速哈希表。使用另一个更通用的哈希表实现可能会更好。

    或者,您可以使用表示“不存在”的默认数据参数。 entry->data 的类型是void *,所以NULL 是一个显而易见的选择。以下数据是对手册页示例的修改,其中包装函数的语法比hsearch_r 更自然:

    #include <stdio.h>
    #include <stdlib.h>
    
    #define _GNU_SOURCE
    #define __USE_GNU
    #include <search.h>
    
    #define NIL (-1L)
    
    void hadd(struct hsearch_data *tab, char *key, long value)
    {
        ENTRY item = {key, (void *) value};
        ENTRY *pitem = &item;
    
        if (hsearch_r(item, ENTER, &pitem, tab)) {
            pitem->data = (void *) value;
        }
    }
    
    void hdelete(struct hsearch_data *tab, char *key)
    {
        ENTRY item = {key};
        ENTRY *pitem = &item;
    
        if (hsearch_r(item, FIND, &pitem, tab)) {
            pitem->data = (void *) NIL;
        }
    }
    
    long hfind(struct hsearch_data *tab, char *key)
    {
        ENTRY item = {key};
        ENTRY *pitem = &item;
    
        if (hsearch_r(item, FIND, &pitem, tab)) {
            return (long) pitem->data;
        }
        return NIL;
    }
    
    int main()
    {
        char *data[] = { 
            "apple", "pear", "cherry", "kiwi", 
            "orange", "plum", "pomegranate", NULL
        };
        char **p = data;
    
        struct hsearch_data tab = {0};
        int i;
    
        hcreate_r(10, &tab);
        for (i = 0; i < 5; i++) hadd(&tab, data[i], i + 1L);
    
        hdelete(&tab, "pear");
        hadd(&tab, "cherry", 144);
    
        while (*p) {
            long value = hfind(&tab, *p);
    
            if (value == NIL) {
                printf("%s: NIL\n", *p);
            } else {
                printf("%s: %ld\n", *p, value);
            }
            p++;
        }
    
        hdestroy_r(&tab);
    
        return 0;
    }
    

    注意:如果您使用 ponters 作为数据并且哈希表拥有该数据,您必须 free 销毁数据,但在覆盖现有值时也是如此。

    【讨论】:

    • @M Oehm,hsearch_r 的第三个参数是应该包含返回值的结构,对吧?那你为什么要把它初始化为&amp;item呢? ps:我是新手,尝试使用hsearch_r
    • @venkrao:不需要初始化pitem;您可以传递未初始化指针的地址,因为它将被覆盖。所以对&amp;item 的初始化令人困惑,但对热有害。如果应该初始化pitem,则更好的值可能是NULL
    • @M Oehm,谢谢。我在我的代码中观察到这种奇怪的行为,hsearch_r 能够将ENTER 元素放入哈希表中。但是,当我尝试FIND 时,搜索失败。通过对一些打印语句进行更多的调试,我意识到只有最后一次插入的元素保留在哈希表中。其他的不是,或者他们只是被覆盖了。我发现很难理解为什么只存在一个元素(为什么它被覆盖)想知道你是否见过类似的行为,希望我能很好地解释这个问题。
    • @venkrao:没有代码很难找到。为什么不在这里问一个问题?检查事项:ENTER 操作是否表示成功?桌子够大吗?据我所知,它不能增长。你更新输入结构的键吗?您可能会无意中用相同的键覆盖该项目。
    • @M Oehm,是的,ENTER 表示成功。桌子够大。我更新了结构的键,是的。我正在插入新元素,而不是覆盖。是的,我可能遗漏了一些东西。我发布了一个新问题link 请看一下。
    猜你喜欢
    • 1970-01-01
    • 2011-02-28
    • 1970-01-01
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多