如何从hsearch中删除元素

时间:2014-09-22 10:08:23

标签: c search hash gnu

我正在使用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不实现替换功能,我们必须自己完成,即首先进行搜索,然后如果存在,则删除第一个条目,然后添加一个新条目。但是要做到这一点,我们需要从哈希中删除一个元素,我无法这样做。

1 个答案:

答案 0 :(得分:5)

可以在线找到source of hsearch_r

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

该实现不适合删除元素。它维护着一系列桶。通过查找另一个空桶来处理散列冲突,以便桶索引不一定等于散列码。当您使用相同的哈希码插入两个值时,第二个将获得这样一个桶,其中哈希码不是桶索引。

当您现在删除第一个项目然后尝试查找第二个项目时,将无法找到它,因为只有当哈希码为存储区索引的“最佳”存储区已满时才会考虑“其他”存储区。

除了不更新的重新添加和丢失的删除选项外,hsearch_r还有其他限制。例如,必须事先估计条目的最大nuber,并且以后不能更改。我认为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销毁数据,但也必须覆盖现有值。